diff options
Diffstat (limited to 't')
162 files changed, 11061 insertions, 2865 deletions
@@ -563,6 +563,11 @@ library for your script to use. argument. This is primarily meant for use during the development of a new test script. + - debug <git-command> + + Run a git command inside a debugger. This is primarily meant for + use when debugging a failing test script. + - test_done Your test script must have test_done at the end. Its purpose diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index f5c01758ca..093832fef1 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -68,6 +68,13 @@ test_expect_success 'blame 1 author' ' check_count A 2 ' +test_expect_success 'blame by tag objects' ' + git tag -m "test tag" testTag && + git tag -m "test tag #2" testTag2 testTag && + check_count -h testTag A 2 && + check_count -h testTag2 A 2 +' + test_expect_success 'setup B lines' ' echo "2A quick brown fox jumps over the" >>file && echo "lazy dog" >>file && @@ -111,6 +118,10 @@ test_expect_success 'blame 2 authors + 2 merged-in authors' ' check_count A 2 B 1 B1 2 B2 1 ' +test_expect_success 'blame --first-parent blames merge for branch1' ' + check_count --first-parent A 2 B 1 "A U Thor" 2 B2 1 +' + test_expect_success 'blame ancestor' ' check_count -h master A 2 B 2 ' diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh index 5aa8adcf9c..f9ae1d780d 100644 --- a/t/lib-git-p4.sh +++ b/t/lib-git-p4.sh @@ -6,6 +6,14 @@ # a subdirectory called "$git" TEST_NO_CREATE_REPO=NoThanks +# Some operations require multiple attempts to be successful. Define +# here the maximal retry timeout in seconds. +RETRY_TIMEOUT=60 + +# Sometimes p4d seems to hang. Terminate the p4d process automatically after +# the defined timeout in seconds. +P4D_TIMEOUT=300 + . ./test-lib.sh if ! test_have_prereq PYTHON @@ -36,6 +44,15 @@ native_path() { echo "$path" } +# On Solaris the 'date +%s' function is not supported and therefore we +# need this replacement. +# Attention: This function is not safe again against time offset updates +# at runtime (e.g. via NTP). The 'clock_gettime(CLOCK_MONOTONIC)' +# function could fix that but it is not in Python until 3.3. +time_in_seconds() { + python -c 'import time; print int(time.time())' +} + # Try to pick a unique port: guess a large number, then hope # no more than one of each test is running. # @@ -57,6 +74,15 @@ cli="$TRASH_DIRECTORY/cli" git="$TRASH_DIRECTORY/git" pidfile="$TRASH_DIRECTORY/p4d.pid" +# Sometimes "prove" seems to hang on exit because p4d is still running +cleanup() { + if test -f "$pidfile" + then + kill -9 $(cat "$pidfile") 2>/dev/null && exit 255 + fi +} +trap cleanup EXIT + # 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. @@ -69,7 +95,7 @@ start_p4d() { ( cd "$db" && { - p4d -q -p $P4DPORT & + p4d -q -p $P4DPORT "$@" & echo $! >"$pidfile" } ) && @@ -81,6 +107,19 @@ start_p4d() { # will be caught with the "kill -0" check below. i=${P4D_START_PATIENCE:-300} pid=$(cat "$pidfile") + + timeout=$(($(time_in_seconds) + $P4D_TIMEOUT)) + while true + do + if test $(time_in_seconds) -gt $timeout + then + kill -9 $pid + exit 1 + fi + sleep 1 + done & + watchdog_pid=$! + ready= while test $i -gt 0 do @@ -121,22 +160,36 @@ p4_add_user() { EOF } +retry_until_success() { + timeout=$(($(time_in_seconds) + $RETRY_TIMEOUT)) + until "$@" 2>/dev/null || test $(time_in_seconds) -gt $timeout + do + sleep 1 + done +} + +retry_until_fail() { + timeout=$(($(time_in_seconds) + $RETRY_TIMEOUT)) + until ! "$@" 2>/dev/null || test $(time_in_seconds) -gt $timeout + do + sleep 1 + done +} + kill_p4d() { pid=$(cat "$pidfile") - # it had better exist for the first kill - kill $pid && - for i in 1 2 3 4 5 ; do - kill $pid >/dev/null 2>&1 || break - sleep 1 - done && + retry_until_fail kill $pid + retry_until_fail kill -9 $pid # complain if it would not die test_must_fail kill $pid >/dev/null 2>&1 && - rm -rf "$db" "$cli" "$pidfile" + rm -rf "$db" "$cli" "$pidfile" && + retry_until_fail kill -9 $watchdog_pid } cleanup_git() { - rm -rf "$git" && - mkdir "$git" + retry_until_success rm -r "$git" + test_must_fail test -d "$git" && + retry_until_success mkdir "$git" } marshal_dump() { diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh index 6bd252212a..9a96e1566d 100644 --- a/t/lib-rebase.sh +++ b/t/lib-rebase.sh @@ -14,7 +14,7 @@ # specified line. # # "<cmd> <lineno>" -- add a line with the specified command -# ("squash", "fixup", "edit", or "reword") and the SHA1 taken +# ("squash", "fixup", "edit", "reword" or "drop") and the SHA1 taken # from the specified line. # # "exec_cmd_with_args" -- add an "exec cmd with args" line. @@ -46,7 +46,7 @@ set_fake_editor () { action=pick for line in $FAKE_LINES; do case $line in - squash|fixup|edit|reword) + squash|fixup|edit|reword|drop) action="$line";; exec*) echo "$line" | sed 's/_/ /g' >> "$1";; @@ -54,6 +54,11 @@ set_fake_editor () { echo '# comment' >> "$1";; ">") echo >> "$1";; + bad) + action="badcmd";; + fakesha) + echo "$action XXXXXXX False commit" >> "$1" + action=pick;; *) sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1" action=pick;; diff --git a/t/perf/aggregate.perl b/t/perf/aggregate.perl index 15f7fc1b80..924b19dab4 100755 --- a/t/perf/aggregate.perl +++ b/t/perf/aggregate.perl @@ -1,5 +1,6 @@ #!/usr/bin/perl +use lib '../../perl/blib/lib'; use strict; use warnings; use Git; diff --git a/t/perf/p5310-pack-bitmaps.sh b/t/perf/p5310-pack-bitmaps.sh index f8ed8573b7..de2a224a36 100755 --- a/t/perf/p5310-pack-bitmaps.sh +++ b/t/perf/p5310-pack-bitmaps.sh @@ -39,14 +39,14 @@ test_expect_success 'create partial bitmap state' ' # 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 + 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 + git repack -Ad && # and now restore our original tip, as if the pushes # had happened diff --git a/t/perf/p7000-filter-branch.sh b/t/perf/p7000-filter-branch.sh new file mode 100755 index 0000000000..15ee5d1d53 --- /dev/null +++ b/t/perf/p7000-filter-branch.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +test_description='performance of filter-branch' +. ./perf-lib.sh + +test_perf_default_repo +test_checkout_worktree + +test_expect_success 'mark bases for tests' ' + git tag -f tip && + git tag -f base HEAD~100 +' + +test_perf 'noop filter' ' + git checkout --detach tip && + git filter-branch -f base..HEAD +' + +test_done diff --git a/t/perf/p7300-clean.sh b/t/perf/p7300-clean.sh new file mode 100755 index 0000000000..7c1888a27e --- /dev/null +++ b/t/perf/p7300-clean.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +test_description="Test git-clean performance" + +. ./perf-lib.sh + +test_perf_default_repo +test_checkout_worktree + +test_expect_success 'setup untracked directory with many sub dirs' ' + rm -rf 500_sub_dirs 100000_sub_dirs clean_test_dir && + mkdir 500_sub_dirs 100000_sub_dirs clean_test_dir && + for i in $(test_seq 1 500) + do + mkdir 500_sub_dirs/dir$i || return $? + done && + for i in $(test_seq 1 200) + do + cp -r 500_sub_dirs 100000_sub_dirs/dir$i || return $? + done +' + +test_perf 'clean many untracked sub dirs, check for nested git' ' + git clean -n -q -f -d 100000_sub_dirs/ +' + +test_perf 'clean many untracked sub dirs, ignore nested git' ' + git clean -n -q -f -f -d 100000_sub_dirs/ +' + +test_perf 'ls-files -o' ' + git ls-files -o +' + +test_done diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 7de8d85ee8..f91bbcfc85 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -202,8 +202,8 @@ test_expect_success 'init honors global core.sharedRepository' ' x$(git config -f shared-honor-global/.git/config core.sharedRepository) ' -test_expect_success 'init rejects insanely long --template' ' - test_must_fail git init --template=$(printf "x%09999dx" 1) test +test_expect_success 'init allows insanely long --template' ' + git init --template=$(printf "x%09999dx" 1) test ' test_expect_success 'init creates a new directory' ' diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh index 37e9396e5d..3afe0125c9 100755 --- a/t/t0002-gitfile.sh +++ b/t/t0002-gitfile.sh @@ -99,4 +99,63 @@ test_expect_success 'check rev-list' ' test "$SHA" = "$(git rev-list HEAD)" ' +test_expect_failure 'setup_git_dir twice in subdir' ' + git init sgd && + ( + cd sgd && + git config alias.lsfi ls-files && + mv .git .realgit && + echo "gitdir: .realgit" >.git && + mkdir subdir && + cd subdir && + >foo && + git add foo && + git lsfi >actual && + echo foo >expected && + test_cmp expected actual + ) +' + +test_expect_success 'enter_repo non-strict mode' ' + test_create_repo enter_repo && + ( + cd enter_repo && + test_tick && + test_commit foo && + mv .git .realgit && + echo "gitdir: .realgit" >.git + ) && + git ls-remote enter_repo >actual && + cat >expected <<-\EOF && + 946e985ab20de757ca5b872b16d64e92ff3803a9 HEAD + 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/heads/master + 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/tags/foo + EOF + test_cmp expected actual +' + +test_expect_success 'enter_repo linked checkout' ' + ( + cd enter_repo && + git worktree add ../foo refs/tags/foo + ) && + git ls-remote foo >actual && + cat >expected <<-\EOF && + 946e985ab20de757ca5b872b16d64e92ff3803a9 HEAD + 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/heads/master + 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/tags/foo + EOF + test_cmp expected actual +' + +test_expect_success 'enter_repo strict mode' ' + git ls-remote --upload-pack="git upload-pack --strict" foo/.git >actual && + cat >expected <<-\EOF && + 946e985ab20de757ca5b872b16d64e92ff3803a9 HEAD + 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/heads/master + 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/tags/foo + EOF + test_cmp expected actual +' + test_done diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index e9f1626b09..718efa04d3 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -204,6 +204,16 @@ test_expect_success 'filtering large input to small output should use little mem GIT_MMAP_LIMIT=1m GIT_ALLOC_LIMIT=1m git add 30MB ' +test_expect_success 'filter that does not read is fine' ' + test-genrandom foo $((128 * 1024 + 1)) >big && + echo "big filter=epipe" >.gitattributes && + git config filter.epipe.clean "echo xyzzy" && + git add big && + git cat-file blob :big >actual && + echo xyzzy >expect && + test_cmp expect actual +' + test_expect_success EXPENSIVE 'filter large file' ' git config filter.largefile.smudge cat && git config filter.largefile.clean cat && diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh index 452320df83..b343651504 100755 --- a/t/t0027-auto-crlf.sh +++ b/t/t0027-auto-crlf.sh @@ -55,20 +55,38 @@ create_gitattributes () { esac } +create_NNO_files () { + lfname=$1 + crlfname=$2 + lfmixcrlf=$3 + lfmixcr=$4 + crlfnul=$5 + for crlf in false true input + do + for attr in "" auto text -text lf crlf + do + pfx=NNO_${crlf}_attr_${attr} && + cp $lfname ${pfx}_LF.txt && + cp $crlfname ${pfx}_CRLF.txt && + cp $lfmixcrlf ${pfx}_CRLF_mix_LF.txt && + cp $lfmixcr ${pfx}_LF_mix_CR.txt && + cp $crlfnul ${pfx}_CRLF_nul.txt + done + done +} + check_warning () { case "$1" in - LF_CRLF) grep "LF will be replaced by CRLF" $2;; - CRLF_LF) grep "CRLF will be replaced by LF" $2;; - '') - >expect - grep "will be replaced by" $2 >actual - test_cmp expect actual - ;; - *) false ;; + LF_CRLF) echo "warning: LF will be replaced by CRLF" >"$2".expect ;; + CRLF_LF) echo "warning: CRLF will be replaced by LF" >"$2".expect ;; + '') >"$2".expect ;; + *) echo >&2 "Illegal 1": "$1" ; return false ;; esac + grep "will be replaced by" "$2" | sed -e "s/\(.*\) in [^ ]*$/\1/" | uniq >"$2".actual + test_cmp "$2".expect "$2".actual } -create_file_in_repo () { +commit_check_warn () { crlf=$1 attr=$2 lfname=$3 @@ -76,9 +94,9 @@ create_file_in_repo () { lfmixcrlf=$5 lfmixcr=$6 crlfnul=$7 - create_gitattributes "$attr" && pfx=crlf_${crlf}_attr_${attr} - for f in LF CRLF LF_mix_CR CRLF_mix_LF CRLF_nul + create_gitattributes "$attr" && + for f in LF CRLF repoMIX LF_mix_CR CRLF_mix_LF LF_nul CRLF_nul do fname=${pfx}_$f.txt && cp $f $fname && @@ -92,6 +110,45 @@ create_file_in_repo () { check_warning "$crlfnul" ${pfx}_CRLF_nul.err } +commit_chk_wrnNNO () { + crlf=$1 + attr=$2 + lfwarn=$3 + crlfwarn=$4 + lfmixcrlf=$5 + lfmixcr=$6 + crlfnul=$7 + pfx=NNO_${crlf}_attr_${attr} + #Commit files on top of existing file + create_gitattributes "$attr" && + for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + do + fname=${pfx}_$f.txt && + cp $f $fname && + git -c core.autocrlf=$crlf add $fname 2>/dev/null && + git -c core.autocrlf=$crlf commit -m "commit_$fname" $fname >"${pfx}_$f.err" 2>&1 + done + + test_expect_success "commit NNO files crlf=$crlf attr=$attr LF" ' + check_warning "$lfwarn" ${pfx}_LF.err + ' + test_expect_success "commit NNO files crlf=$crlf attr=$attr CRLF" ' + check_warning "$crlfwarn" ${pfx}_CRLF.err + ' + + test_expect_success "commit NNO files crlf=$crlf attr=$attr CRLF_mix_LF" ' + check_warning "$lfmixcrlf" ${pfx}_CRLF_mix_LF.err + ' + + test_expect_success "commit NNO files crlf=$crlf attr=$attr LF_mix_cr" ' + check_warning "$lfmixcr" ${pfx}_LF_mix_CR.err + ' + + test_expect_success "commit NNO files crlf=$crlf attr=$attr CRLF_nul" ' + check_warning "$crlfnul" ${pfx}_CRLF_nul.err + ' +} + check_files_in_repo () { crlf=$1 attr=$2 @@ -108,8 +165,33 @@ check_files_in_repo () { compare_files $crlfnul ${pfx}CRLF_nul.txt } +check_in_repo_NNO () { + crlf=$1 + attr=$2 + lfname=$3 + crlfname=$4 + lfmixcrlf=$5 + lfmixcr=$6 + crlfnul=$7 + pfx=NNO_${crlf}_attr_${attr}_ + test_expect_success "compare_files $lfname ${pfx}LF.txt" ' + compare_files $lfname ${pfx}LF.txt + ' + test_expect_success "compare_files $crlfname ${pfx}CRLF.txt" ' + compare_files $crlfname ${pfx}CRLF.txt + ' + test_expect_success "compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt" ' + compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt + ' + test_expect_success "compare_files $lfmixcr ${pfx}LF_mix_CR.txt" ' + compare_files $lfmixcr ${pfx}LF_mix_CR.txt + ' + test_expect_success "compare_files $crlfnul ${pfx}CRLF_nul.txt" ' + compare_files $crlfnul ${pfx}CRLF_nul.txt + ' +} -check_files_in_ws () { +checkout_files () { eol=$1 crlf=$2 attr=$3 @@ -122,7 +204,7 @@ check_files_in_ws () { git config core.autocrlf $crlf && pfx=eol_${eol}_crlf_${crlf}_attr_${attr}_ && src=crlf_false_attr__ && - for f in LF CRLF LF_mix_CR CRLF_mix_LF CRLF_nul + for f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul do rm $src$f.txt && if test -z "$eol"; then @@ -144,8 +226,8 @@ check_files_in_ws () { test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=LF_mix_CR" " compare_ws_file $pfx $lfmixcr ${src}LF_mix_CR.txt " - test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=CRLF_nul" " - compare_ws_file $pfx $crlfnul ${src}CRLF_nul.txt + test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=LF_nul" " + compare_ws_file $pfx $crlfnul ${src}LF_nul.txt " } @@ -157,11 +239,16 @@ test_expect_success 'setup master' ' git commit -m "add .gitattributes" "" && printf "line1\nline2\nline3" >LF && printf "line1\r\nline2\r\nline3" >CRLF && + printf "line1\r\nline2\nline3" >repoMIX && printf "line1\r\nline2\nline3" >CRLF_mix_LF && printf "line1\nline2\rline3" >LF_mix_CR && printf "line1\r\nline2\rline3" >CRLF_mix_CR && printf "line1Q\r\nline2\r\nline3" | q_to_nul >CRLF_nul && - printf "line1Q\nline2\nline3" | q_to_nul >LF_nul + printf "line1Q\nline2\nline3" | q_to_nul >LF_nul && + create_NNO_files CRLF_mix_LF CRLF_mix_LF CRLF_mix_LF CRLF_mix_LF CRLF_mix_LF && + git -c core.autocrlf=false add NNO_*.txt && + git commit -m "mixed line endings" && + test_tick ' @@ -169,45 +256,86 @@ test_expect_success 'setup master' ' warn_LF_CRLF="LF will be replaced by CRLF" warn_CRLF_LF="CRLF will be replaced by LF" -test_expect_success 'add files empty attr' ' - create_file_in_repo false "" "" "" "" "" "" && - create_file_in_repo true "" "LF_CRLF" "" "LF_CRLF" "" "" && - create_file_in_repo input "" "" "CRLF_LF" "CRLF_LF" "" "" +# WILC stands for "Warn if (this OS) converts LF into CRLF". +# WICL: Warn if CRLF becomes LF +# WAMIX: Mixed line endings: either CRLF->LF or LF->CRLF +if test_have_prereq NATIVE_CRLF +then + WILC=LF_CRLF + WICL= + WAMIX=LF_CRLF +else + WILC= + WICL=CRLF_LF + WAMIX=CRLF_LF +fi + +# attr LF CRLF CRLFmixLF LFmixCR CRLFNUL +test_expect_success 'commit files empty attr' ' + commit_check_warn false "" "" "" "" "" "" && + commit_check_warn true "" "LF_CRLF" "" "LF_CRLF" "" "" && + commit_check_warn input "" "" "CRLF_LF" "CRLF_LF" "" "" ' -test_expect_success 'add files attr=auto' ' - create_file_in_repo false "auto" "" "CRLF_LF" "CRLF_LF" "" "" && - create_file_in_repo true "auto" "LF_CRLF" "" "LF_CRLF" "" "" && - create_file_in_repo input "auto" "" "CRLF_LF" "CRLF_LF" "" "" +test_expect_success 'commit files attr=auto' ' + commit_check_warn false "auto" "$WILC" "$WICL" "$WAMIX" "" "" && + commit_check_warn true "auto" "LF_CRLF" "" "LF_CRLF" "" "" && + commit_check_warn input "auto" "" "CRLF_LF" "CRLF_LF" "" "" ' -test_expect_success 'add files attr=text' ' - create_file_in_repo false "text" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" && - create_file_in_repo true "text" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" && - create_file_in_repo input "text" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" +test_expect_success 'commit files attr=text' ' + commit_check_warn false "text" "$WILC" "$WICL" "$WAMIX" "$WILC" "$WICL" && + commit_check_warn true "text" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" && + commit_check_warn input "text" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" ' -test_expect_success 'add files attr=-text' ' - create_file_in_repo false "-text" "" "" "" "" "" && - create_file_in_repo true "-text" "" "" "" "" "" && - create_file_in_repo input "-text" "" "" "" "" "" +test_expect_success 'commit files attr=-text' ' + commit_check_warn false "-text" "" "" "" "" "" && + commit_check_warn true "-text" "" "" "" "" "" && + commit_check_warn input "-text" "" "" "" "" "" ' -test_expect_success 'add files attr=lf' ' - create_file_in_repo false "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" && - create_file_in_repo true "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" && - create_file_in_repo input "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" +test_expect_success 'commit files attr=lf' ' + commit_check_warn false "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" && + commit_check_warn true "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" && + commit_check_warn input "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" ' -test_expect_success 'add files attr=crlf' ' - create_file_in_repo false "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" && - create_file_in_repo true "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" && - create_file_in_repo input "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" +test_expect_success 'commit files attr=crlf' ' + commit_check_warn false "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" && + commit_check_warn true "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" && + commit_check_warn input "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" ' +# attr LF CRLF CRLFmixLF LF_mix_CR CRLFNUL +commit_chk_wrnNNO false "" "" "" "" "" "" +commit_chk_wrnNNO true "" "LF_CRLF" "" "" "" "" +commit_chk_wrnNNO input "" "" "" "" "" "" + + +commit_chk_wrnNNO false "auto" "$WILC" "$WICL" "$WAMIX" "" "" +commit_chk_wrnNNO true "auto" "LF_CRLF" "" "LF_CRLF" "" "" +commit_chk_wrnNNO input "auto" "" "CRLF_LF" "CRLF_LF" "" "" + +commit_chk_wrnNNO false "text" "$WILC" "$WICL" "$WAMIX" "$WILC" "$WICL" +commit_chk_wrnNNO true "text" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" +commit_chk_wrnNNO input "text" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" + +commit_chk_wrnNNO false "-text" "" "" "" "" "" +commit_chk_wrnNNO true "-text" "" "" "" "" "" +commit_chk_wrnNNO input "-text" "" "" "" "" "" + +commit_chk_wrnNNO false "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" +commit_chk_wrnNNO true "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" +commit_chk_wrnNNO input "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" + +commit_chk_wrnNNO false "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" +commit_chk_wrnNNO true "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" +commit_chk_wrnNNO input "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" + test_expect_success 'create files cleanup' ' rm -f *.txt && - git reset --hard + git -c core.autocrlf=false reset --hard ' test_expect_success 'commit empty gitattribues' ' @@ -234,10 +362,28 @@ test_expect_success 'commit -text' ' check_files_in_repo input "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul ' +# attr LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL +check_in_repo_NNO false "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_in_repo_NNO true "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_in_repo_NNO input "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + +check_in_repo_NNO false "auto" LF LF LF LF_mix_CR CRLF_nul +check_in_repo_NNO true "auto" LF LF LF LF_mix_CR CRLF_nul +check_in_repo_NNO input "auto" LF LF LF LF_mix_CR CRLF_nul + +check_in_repo_NNO false "text" LF LF LF LF_mix_CR LF_nul +check_in_repo_NNO true "text" LF LF LF LF_mix_CR LF_nul +check_in_repo_NNO input "text" LF LF LF LF_mix_CR LF_nul + +check_in_repo_NNO false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_in_repo_NNO true "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_in_repo_NNO input "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + + ################################################################################ # Check how files in the repo are changed when they are checked out # How to read the table below: -# - check_files_in_ws will check multiple files with a combination of settings +# - checkout_files will check multiple files with a combination of settings # and attributes (core.autocrlf=input is forbidden with core.eol=crlf) # - parameter $1 : core.eol lf | crlf # - parameter $2 : core.autocrlf false | true | input @@ -249,87 +395,89 @@ test_expect_success 'commit -text' ' # - parameter $8 : reference for a file with CRLF and a NUL (should be handled as binary when auto) # What we have in the repo: -# ----------------- EOL in repo ---------------- -# LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +# ----------------- EOL in repo ---------------- +# LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul # settings with checkout: # core. core. .gitattr # eol acrlf # ---------------------------------------------- # What we want to have in the working tree: -if test_have_prereq MINGW +if test_have_prereq NATIVE_CRLF then MIX_CRLF_LF=CRLF MIX_LF_CR=CRLF_mix_CR NL=CRLF +LFNUL=CRLF_nul else MIX_CRLF_LF=CRLF_mix_LF MIX_LF_CR=LF_mix_CR NL=LF +LFNUL=LF_nul fi export CRLF_MIX_LF_CR MIX NL -check_files_in_ws lf false "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf true "" CRLF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf input "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf false "auto" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf true "auto" CRLF CRLF CRLF LF_mix_CR CRLF_nul -check_files_in_ws lf input "auto" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf false "text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -check_files_in_ws lf input "text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf true "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf input "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf false "lf" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf true "lf" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf input "lf" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws lf false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -check_files_in_ws lf true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -check_files_in_ws lf input "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul - -check_files_in_ws crlf false "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws crlf true "" CRLF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws crlf false "auto" CRLF CRLF CRLF LF_mix_CR CRLF_nul -check_files_in_ws crlf true "auto" CRLF CRLF CRLF LF_mix_CR CRLF_nul -check_files_in_ws crlf false "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -check_files_in_ws crlf true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -check_files_in_ws crlf false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws crlf true "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws crlf false "lf" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws crlf true "lf" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws crlf false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -check_files_in_ws crlf true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul - -check_files_in_ws "" false "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws "" true "" CRLF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws "" input "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws "" false "auto" $NL CRLF $MIX_CRLF_LF LF_mix_CR CRLF_nul -check_files_in_ws "" true "auto" CRLF CRLF CRLF LF_mix_CR CRLF_nul -check_files_in_ws "" input "auto" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws "" false "text" $NL CRLF $MIX_CRLF_LF $MIX_LF_CR CRLF_nul -check_files_in_ws "" true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -check_files_in_ws "" input "text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws "" false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws "" true "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws "" input "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws "" false "lf" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws "" true "lf" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws "" input "lf" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws "" false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -check_files_in_ws "" true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -check_files_in_ws "" input "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul - -check_files_in_ws native false "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws native true "" CRLF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws native false "auto" $NL CRLF $MIX_CRLF_LF LF_mix_CR CRLF_nul -check_files_in_ws native true "auto" CRLF CRLF CRLF LF_mix_CR CRLF_nul -check_files_in_ws native false "text" $NL CRLF $MIX_CRLF_LF $MIX_LF_CR CRLF_nul -check_files_in_ws native true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -check_files_in_ws native false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws native true "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws native false "lf" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws native true "lf" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul -check_files_in_ws native false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul -check_files_in_ws native true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files lf false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf false "auto" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf true "auto" CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files lf input "auto" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf false "text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files lf input "text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf false "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf true "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf input "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf false "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf true "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf input "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files lf true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files lf input "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + +checkout_files crlf false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files crlf true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files crlf false "auto" CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files crlf true "auto" CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files crlf false "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files crlf true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files crlf false "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files crlf true "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files crlf false "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files crlf true "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files crlf false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files crlf true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + +checkout_files "" false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" false "auto" $NL CRLF $MIX_CRLF_LF LF_mix_CR LF_nul +checkout_files "" true "auto" CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files "" input "auto" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" false "text" $NL CRLF $MIX_CRLF_LF $MIX_LF_CR $LFNUL +checkout_files "" true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files "" input "text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" false "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" true "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" input "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" false "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" true "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" input "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files "" true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files "" input "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + +checkout_files native false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files native true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files native false "auto" $NL CRLF $MIX_CRLF_LF LF_mix_CR LF_nul +checkout_files native true "auto" CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files native false "text" $NL CRLF $MIX_CRLF_LF $MIX_LF_CR $LFNUL +checkout_files native true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files native false "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files native true "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files native false "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files native true "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files native false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files native true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul test_done diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index b044785175..9be6411104 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -19,6 +19,7 @@ usage: test-parse-options <options> -i, --integer <n> get a integer -j <n> get a integer, too + -m, --magnitude <n> get a magnitude --set23 set integer to 23 -t <time> get timestamp of <time> -L, --length <str> get length of <str> @@ -58,6 +59,7 @@ mv expect expect.err cat >expect.template <<EOF boolean: 0 integer: 0 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -132,9 +134,32 @@ test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown_i18n --no-no-fear test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt' +test_expect_success 'OPT_INT() negative' 'check integer: -2345 -i -2345' + +test_expect_success 'OPT_MAGNITUDE() simple' ' + check magnitude: 2345678 -m 2345678 +' + +test_expect_success 'OPT_MAGNITUDE() kilo' ' + check magnitude: 239616 -m 234k +' + +test_expect_success 'OPT_MAGNITUDE() mega' ' + check magnitude: 104857600 -m 100m +' + +test_expect_success 'OPT_MAGNITUDE() giga' ' + check magnitude: 1073741824 -m 1g +' + +test_expect_success 'OPT_MAGNITUDE() 3giga' ' + check magnitude: 3221225472 -m 3g +' + cat > expect << EOF boolean: 2 integer: 1729 +magnitude: 16384 timestamp: 0 string: 123 abbrev: 7 @@ -145,8 +170,8 @@ file: prefix/my.file EOF test_expect_success 'short options' ' - test-parse-options -s123 -b -i 1729 -b -vv -n -F my.file \ - > output 2> output.err && + test-parse-options -s123 -b -i 1729 -m 16k -b -vv -n -F my.file \ + >output 2>output.err && test_cmp expect output && test_must_be_empty output.err ' @@ -154,6 +179,7 @@ test_expect_success 'short options' ' cat > expect << EOF boolean: 2 integer: 1729 +magnitude: 16384 timestamp: 0 string: 321 abbrev: 10 @@ -164,9 +190,10 @@ file: prefix/fi.le EOF 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-parse-options --boolean --integer 1729 --magnitude 16k \ + --boolean --string2=321 --verbose --verbose --no-dry-run \ + --abbrev=10 --file fi.le --obsolete \ + >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' @@ -180,6 +207,7 @@ test_expect_success 'missing required value' ' cat > expect << EOF boolean: 1 integer: 13 +magnitude: 0 timestamp: 0 string: 123 abbrev: 7 @@ -202,6 +230,7 @@ test_expect_success 'intermingled arguments' ' cat > expect << EOF boolean: 0 integer: 2 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -230,6 +259,7 @@ test_expect_success 'ambiguously abbreviated option' ' cat > expect << EOF boolean: 0 integer: 0 +magnitude: 0 timestamp: 0 string: 123 abbrev: 7 @@ -268,6 +298,7 @@ test_expect_success 'detect possible typos' ' cat > expect <<EOF boolean: 0 integer: 0 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -287,6 +318,7 @@ test_expect_success 'keep some options as arguments' ' cat > expect <<EOF boolean: 0 integer: 0 +magnitude: 0 timestamp: 1 string: (not set) abbrev: 7 @@ -308,6 +340,7 @@ cat > expect <<EOF Callback: "four", 0 boolean: 5 integer: 4 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -336,6 +369,7 @@ test_expect_success 'OPT_CALLBACK() and callback errors work' ' cat > expect <<EOF boolean: 1 integer: 23 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -360,6 +394,7 @@ test_expect_success 'OPT_NEGBIT() and OPT_SET_INT() work' ' cat > expect <<EOF boolean: 6 integer: 0 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -390,6 +425,7 @@ test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' ' cat > expect <<EOF boolean: 0 integer: 12345 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -408,6 +444,7 @@ test_expect_success 'OPT_NUMBER_CALLBACK() works' ' cat >expect <<EOF boolean: 0 integer: 0 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index c0143a0a70..f0152a7ab4 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -19,6 +19,14 @@ relative_path() { "test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'" } +test_git_path() { + test_expect_success "git-path $1 $2 => $3" " + $1 git rev-parse --git-path $2 >actual && + echo $3 >expect && + test_cmp expect actual + " +} + # On Windows, we are using MSYS's bash, which mangles the paths. # Absolute paths are anchored at the MSYS installation directory, # which means that the path / accounts for this many characters: @@ -51,6 +59,9 @@ case $(uname -s) in ;; esac +test_expect_success basename 'test-path-utils basename' +test_expect_success dirname 'test-path-utils dirname' + norm_path "" "" norm_path . "" norm_path ./ "" @@ -244,4 +255,38 @@ relative_path "<null>" "<empty>" ./ relative_path "<null>" "<null>" ./ relative_path "<null>" /foo/a/b ./ +test_git_path A=B info/grafts .git/info/grafts +test_git_path GIT_GRAFT_FILE=foo info/grafts foo +test_git_path GIT_GRAFT_FILE=foo info/////grafts foo +test_git_path GIT_INDEX_FILE=foo index foo +test_git_path GIT_INDEX_FILE=foo index/foo .git/index/foo +test_git_path GIT_INDEX_FILE=foo index2 .git/index2 +test_expect_success 'setup fake objects directory foo' 'mkdir foo' +test_git_path GIT_OBJECT_DIRECTORY=foo objects foo +test_git_path GIT_OBJECT_DIRECTORY=foo objects/foo foo/foo +test_git_path GIT_OBJECT_DIRECTORY=foo objects2 .git/objects2 +test_expect_success 'setup common repository' 'git --git-dir=bar init' +test_git_path GIT_COMMON_DIR=bar index .git/index +test_git_path GIT_COMMON_DIR=bar HEAD .git/HEAD +test_git_path GIT_COMMON_DIR=bar logs/HEAD .git/logs/HEAD +test_git_path GIT_COMMON_DIR=bar logs/refs/bisect/foo .git/logs/refs/bisect/foo +test_git_path GIT_COMMON_DIR=bar logs/refs/bisec/foo bar/logs/refs/bisec/foo +test_git_path GIT_COMMON_DIR=bar logs/refs/bisec bar/logs/refs/bisec +test_git_path GIT_COMMON_DIR=bar logs/refs/bisectfoo bar/logs/refs/bisectfoo +test_git_path GIT_COMMON_DIR=bar objects bar/objects +test_git_path GIT_COMMON_DIR=bar objects/bar bar/objects/bar +test_git_path GIT_COMMON_DIR=bar info/exclude bar/info/exclude +test_git_path GIT_COMMON_DIR=bar info/grafts bar/info/grafts +test_git_path GIT_COMMON_DIR=bar info/sparse-checkout .git/info/sparse-checkout +test_git_path GIT_COMMON_DIR=bar info//sparse-checkout .git/info//sparse-checkout +test_git_path GIT_COMMON_DIR=bar remotes/bar bar/remotes/bar +test_git_path GIT_COMMON_DIR=bar branches/bar bar/branches/bar +test_git_path GIT_COMMON_DIR=bar logs/refs/heads/master bar/logs/refs/heads/master +test_git_path GIT_COMMON_DIR=bar refs/heads/master bar/refs/heads/master +test_git_path GIT_COMMON_DIR=bar refs/bisect/foo .git/refs/bisect/foo +test_git_path GIT_COMMON_DIR=bar hooks/me bar/hooks/me +test_git_path GIT_COMMON_DIR=bar config bar/config +test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs +test_git_path GIT_COMMON_DIR=bar shallow bar/shallow + test_done diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh index 601d02d71f..adfd4f0b5e 100755 --- a/t/t0090-cache-tree.sh +++ b/t/t0090-cache-tree.sh @@ -199,6 +199,30 @@ test_expect_success 'checkout -B gives cache-tree' ' test_cache_tree ' +test_expect_success 'merge --ff-only maintains cache-tree' ' + git checkout current && + git checkout -b changes && + test_commit llamas && + test_commit pachyderm && + test_cache_tree && + git checkout current && + test_cache_tree && + git merge --ff-only changes && + test_cache_tree +' + +test_expect_success 'merge maintains cache-tree' ' + git checkout current && + git checkout -b changes2 && + test_commit alpacas && + test_cache_tree && + git checkout current && + test_commit struthio && + test_cache_tree && + git merge changes2 && + test_cache_tree +' + test_expect_success 'partial commit gives cache-tree' ' git checkout -b partial no-children && test_commit one && @@ -218,4 +242,14 @@ test_expect_success 'no phantom error when switching trees' ' ! test -s errors ' +test_expect_success 'switching trees does not invalidate shared index' ' + git update-index --split-index && + >split && + git add split && + test-dump-split-index .git/index | grep -v ^own >before && + git commit -m "as-is" && + test-dump-split-index .git/index | grep -v ^own >after && + test_cmp before after +' + test_done diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index ab36b1eb72..4f38078ff3 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -47,6 +47,18 @@ $content" test_cmp expect actual ' + test_expect_success "Type of $type is correct using --allow-unknown-type" ' + echo $type >expect && + git cat-file -t --allow-unknown-type $sha1 >actual && + test_cmp expect actual + ' + + test_expect_success "Size of $type is correct using --allow-unknown-type" ' + echo $size >expect && + git cat-file -s --allow-unknown-type $sha1 >actual && + test_cmp expect actual + ' + test -z "$content" || test_expect_success "Content of $type is correct" ' maybe_remove_timestamp "$content" $no_ts >expect && @@ -189,6 +201,13 @@ do ' done +for opt in t s e p +do + test_expect_success "Passing -$opt with --follow-symlinks fails" ' + test_must_fail git cat-file --follow-symlinks -$opt $hello_sha1 + ' +done + test_expect_success "--batch-check for a non-existent named object" ' test "foobar42 missing foobar84 missing" = \ @@ -296,4 +315,262 @@ test_expect_success '%(deltabase) reports packed delta bases' ' } ' +bogus_type="bogus" +bogus_content="bogus" +bogus_size=$(strlen "$bogus_content") +bogus_sha1=$(echo_without_newline "$bogus_content" | git hash-object -t $bogus_type --literally -w --stdin) + +test_expect_success "Type of broken object is correct" ' + echo $bogus_type >expect && + git cat-file -t --allow-unknown-type $bogus_sha1 >actual && + test_cmp expect actual +' + +test_expect_success "Size of broken object is correct" ' + echo $bogus_size >expect && + git cat-file -s --allow-unknown-type $bogus_sha1 >actual && + test_cmp expect actual +' +bogus_type="abcdefghijklmnopqrstuvwxyz1234679" +bogus_content="bogus" +bogus_size=$(strlen "$bogus_content") +bogus_sha1=$(echo_without_newline "$bogus_content" | git hash-object -t $bogus_type --literally -w --stdin) + +test_expect_success "Type of broken object is correct when type is large" ' + echo $bogus_type >expect && + git cat-file -t --allow-unknown-type $bogus_sha1 >actual && + test_cmp expect actual +' + +test_expect_success "Size of large broken object is correct when type is large" ' + echo $bogus_size >expect && + git cat-file -s --allow-unknown-type $bogus_sha1 >actual && + test_cmp expect actual +' + +# Tests for git cat-file --follow-symlinks +test_expect_success 'prep for symlink tests' ' + echo_without_newline "$hello_content" >morx && + test_ln_s_add morx same-dir-link && + test_ln_s_add dir link-to-dir && + test_ln_s_add ../fleem out-of-repo-link && + test_ln_s_add .. out-of-repo-link-dir && + test_ln_s_add same-dir-link link-to-link && + test_ln_s_add nope broken-same-dir-link && + mkdir dir && + test_ln_s_add ../morx dir/parent-dir-link && + test_ln_s_add .. dir/link-dir && + test_ln_s_add ../../escape dir/out-of-repo-link && + test_ln_s_add ../.. dir/out-of-repo-link-dir && + test_ln_s_add nope dir/broken-link-in-dir && + mkdir dir/subdir && + test_ln_s_add ../../morx dir/subdir/grandparent-dir-link && + test_ln_s_add ../../../great-escape dir/subdir/out-of-repo-link && + test_ln_s_add ../../.. dir/subdir/out-of-repo-link-dir && + test_ln_s_add ../../../ dir/subdir/out-of-repo-link-dir-trailing && + test_ln_s_add ../parent-dir-link dir/subdir/parent-dir-link-to-link && + echo_without_newline "$hello_content" >dir/subdir/ind2 && + echo_without_newline "$hello_content" >dir/ind1 && + test_ln_s_add dir dirlink && + test_ln_s_add dir/subdir subdirlink && + test_ln_s_add subdir/ind2 dir/link-to-child && + test_ln_s_add dir/link-to-child link-to-down-link && + test_ln_s_add dir/.. up-down && + test_ln_s_add dir/../ up-down-trailing && + test_ln_s_add dir/../morx up-down-file && + test_ln_s_add dir/../../morx up-up-down-file && + test_ln_s_add subdirlink/../../morx up-two-down-file && + test_ln_s_add loop1 loop2 && + test_ln_s_add loop2 loop1 && + git add morx dir/subdir/ind2 dir/ind1 && + git commit -am "test" && + echo $hello_sha1 blob $hello_size >found +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for non-links' ' + echo HEAD:morx | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + echo HEAD:nope missing >expect && + echo HEAD:nope | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for in-repo, same-dir links' ' + echo HEAD:same-dir-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for in-repo, links to dirs' ' + echo HEAD:link-to-dir/ind1 | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for broken in-repo, same-dir links' ' + echo dangling 25 >expect && + echo HEAD:broken-same-dir-link >>expect && + echo HEAD:broken-same-dir-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for same-dir links-to-links' ' + echo HEAD:link-to-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for parent-dir links' ' + echo HEAD:dir/parent-dir-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + echo notdir 29 >expect && + echo HEAD:dir/parent-dir-link/nope >>expect && + echo HEAD:dir/parent-dir-link/nope | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for .. links' ' + echo dangling 22 >expect && + echo HEAD:dir/link-dir/nope >>expect && + echo HEAD:dir/link-dir/nope | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:dir/link-dir/morx | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + echo dangling 27 >expect && + echo HEAD:dir/broken-link-in-dir >>expect && + echo HEAD:dir/broken-link-in-dir | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for ../.. links' ' + echo notdir 41 >expect && + echo HEAD:dir/subdir/grandparent-dir-link/nope >>expect && + echo HEAD:dir/subdir/grandparent-dir-link/nope | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:dir/subdir/grandparent-dir-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + echo HEAD:dir/subdir/parent-dir-link-to-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir/ links' ' + echo dangling 17 >expect && + echo HEAD:dirlink/morx >>expect && + echo HEAD:dirlink/morx | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo $hello_sha1 blob $hello_size >expect && + echo HEAD:dirlink/ind1 | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir/subdir links' ' + echo dangling 20 >expect && + echo HEAD:subdirlink/morx >>expect && + echo HEAD:subdirlink/morx | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:subdirlink/ind2 | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir ->subdir links' ' + echo notdir 27 >expect && + echo HEAD:dir/link-to-child/morx >>expect && + echo HEAD:dir/link-to-child/morx | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:dir/link-to-child | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + echo HEAD:link-to-down-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-of-repo symlinks' ' + echo symlink 8 >expect && + echo ../fleem >>expect && + echo HEAD:out-of-repo-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo symlink 2 >expect && + echo .. >>expect && + echo HEAD:out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-of-repo symlinks in dirs' ' + echo symlink 9 >expect && + echo ../escape >>expect && + echo HEAD:dir/out-of-repo-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo symlink 2 >expect && + echo .. >>expect && + echo HEAD:dir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-of-repo symlinks in subdirs' ' + echo symlink 15 >expect && + echo ../great-escape >>expect && + echo HEAD:dir/subdir/out-of-repo-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo symlink 2 >expect && + echo .. >>expect && + echo HEAD:dir/subdir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo symlink 3 >expect && + echo ../ >>expect && + echo HEAD:dir/subdir/out-of-repo-link-dir-trailing | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' ' + echo HEAD: | git cat-file --batch-check >expect && + echo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + echo symlink 7 >expect && + echo ../morx >>expect && + echo HEAD:up-up-down-file | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:up-two-down-file | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlink breaks loops' ' + echo loop 10 >expect && + echo HEAD:loop1 >>expect && + echo HEAD:loop1 | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch --follow-symlink returns correct sha and mode' ' + echo HEAD:morx | git cat-file --batch >expect && + echo HEAD:morx | git cat-file --batch --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'cat-file --batch-all-objects shows all objects' ' + # make new repos so we know the full set of objects; we will + # also make sure that there are some packed and some loose + # objects, some referenced and some not, and that there are + # some available only via alternates. + git init all-one && + ( + cd all-one && + echo content >file && + git add file && + git commit -qm base && + git rev-parse HEAD HEAD^{tree} HEAD:file && + git repack -ad && + echo not-cloned | git hash-object -w --stdin + ) >expect.unsorted && + git clone -s all-one all-two && + ( + cd all-two && + echo local-unref | git hash-object -w --stdin + ) >>expect.unsorted && + sort <expect.unsorted >expect && + git -C all-two cat-file --batch-all-objects \ + --batch-check="%(objectname)" >actual && + test_cmp expect actual +' + test_done diff --git a/t/t1090-sparse-checkout-scope.sh b/t/t1090-sparse-checkout-scope.sh new file mode 100755 index 0000000000..1f61eb3e88 --- /dev/null +++ b/t/t1090-sparse-checkout-scope.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +test_description='sparse checkout scope tests' + +. ./test-lib.sh + +test_expect_success 'setup' ' + echo "initial" >a && + echo "initial" >b && + echo "initial" >c && + git add a b c && + git commit -m "initial commit" +' + +test_expect_success 'create feature branch' ' + git checkout -b feature && + echo "modified" >b && + echo "modified" >c && + git add b c && + git commit -m "modification" +' + +test_expect_success 'perform sparse checkout of master' ' + git config --local --bool core.sparsecheckout true && + echo "!/*" >.git/info/sparse-checkout && + echo "/a" >>.git/info/sparse-checkout && + echo "/c" >>.git/info/sparse-checkout && + git checkout master && + test_path_is_file a && + test_path_is_missing b && + test_path_is_file c +' + +test_expect_success 'merge feature branch into sparse checkout of master' ' + git merge feature && + test_path_is_file a && + test_path_is_missing b && + test_path_is_file c && + test "$(cat c)" = "modified" +' + +test_expect_success 'return to full checkout of master' ' + git checkout feature && + echo "/*" >.git/info/sparse-checkout && + git checkout master && + test_path_is_file a && + test_path_is_file b && + test_path_is_file c && + test "$(cat b)" = "modified" +' + +test_done diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 66dd28644f..52678e7d0a 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -353,6 +353,18 @@ test_expect_success '--list without repo produces empty output' ' ' cat > expect << EOF +beta.noindent +nextsection.nonewline +123456.a123 +version.1.2.3eX.alpha +EOF + +test_expect_success '--name-only --list' ' + git config --name-only --list >output && + test_cmp expect output +' + +cat > expect << EOF beta.noindent sillyValue nextsection.nonewline wow2 for me EOF @@ -363,6 +375,16 @@ test_expect_success '--get-regexp' ' ' cat > expect << EOF +beta.noindent +nextsection.nonewline +EOF + +test_expect_success '--name-only --get-regexp' ' + git config --name-only --get-regexp in >output && + test_cmp expect output +' + +cat > expect << EOF wow2 for me wow4 for you EOF diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh index 0d9388afc4..9bcd34969f 100755 --- a/t/t1302-repo-version.sh +++ b/t/t1302-repo-version.sh @@ -67,4 +67,64 @@ test_expect_success 'gitdir required mode' ' ) ' +check_allow () { + git rev-parse --git-dir >actual && + echo .git >expect && + test_cmp expect actual +} + +check_abort () { + test_must_fail git rev-parse --git-dir +} + +# avoid git-config, since it cannot be trusted to run +# in a repository with a broken version +mkconfig () { + echo '[core]' && + echo "repositoryformatversion = $1" && + shift && + + if test $# -gt 0; then + echo '[extensions]' && + for i in "$@"; do + echo "$i" + done + fi +} + +while read outcome version extensions; do + test_expect_success "$outcome version=$version $extensions" " + mkconfig $version $extensions >.git/config && + check_${outcome} + " +done <<\EOF +allow 0 +allow 1 +allow 1 noop +abort 1 no-such-extension +allow 0 no-such-extension +EOF + +test_expect_success 'precious-objects allowed' ' + mkconfig 1 preciousObjects >.git/config && + check_allow +' + +test_expect_success 'precious-objects blocks destructive repack' ' + test_must_fail git repack -ad +' + +test_expect_success 'other repacks are OK' ' + test_commit foo && + git repack +' + +test_expect_success 'precious-objects blocks prune' ' + test_must_fail git prune +' + +test_expect_success 'gc runs without complaint' ' + git gc +' + test_done diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh index 91235b76ba..9863d0d0ed 100755 --- a/t/t1308-config-set.sh +++ b/t/t1308-config-set.sh @@ -218,4 +218,15 @@ test_expect_success 'check line errors for malformed values' ' test_i18ngrep "fatal: .*alias\.br.*\.git/config.*line 2" result ' +test_expect_success 'error on modifying repo config without repo' ' + mkdir no-repo && + ( + GIT_CEILING_DIRECTORIES=$(pwd) && + export GIT_CEILING_DIRECTORIES && + cd no-repo && + test_must_fail git config a.b c 2>err && + grep "not in a git directory" err + ) +' + test_done diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index ba89f4c009..af1b20dd5c 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -23,6 +23,7 @@ test_expect_success setup ' m=refs/heads/master n_dir=refs/heads/gu n=$n_dir/fixes +outside=foo test_expect_success \ "create $m" \ @@ -74,6 +75,24 @@ test_expect_success "delete $m (by HEAD)" ' ' rm -f .git/$m +test_expect_success 'update-ref does not create reflogs by default' ' + test_when_finished "git update-ref -d $outside" && + git update-ref $outside $A && + git rev-parse $A >expect && + git rev-parse $outside >actual && + test_cmp expect actual && + test_must_fail git reflog exists $outside +' + +test_expect_success 'update-ref creates reflogs with --create-reflog' ' + test_when_finished "git update-ref -d $outside" && + git update-ref --create-reflog $outside $A && + git rev-parse $A >expect && + git rev-parse $outside >actual && + test_cmp expect actual && + git reflog exists $outside +' + test_expect_success \ "create $m (by HEAD)" \ "git update-ref HEAD $A && @@ -155,12 +174,11 @@ test_expect_success "(not) changed .git/$m" " ' rm -f .git/$m -: a repository with working tree always has reflog these days... -: >.git/logs/refs/heads/master +rm -f .git/logs/refs/heads/master test_expect_success \ "create $m (logged by touch)" \ 'GIT_COMMITTER_DATE="2005-05-26 23:30" \ - git update-ref HEAD '"$A"' -m "Initial Creation" && + git update-ref --create-reflog HEAD '"$A"' -m "Initial Creation" && test '"$A"' = $(cat .git/'"$m"')' test_expect_success \ "update $m (logged by touch)" \ @@ -472,6 +490,25 @@ test_expect_success 'stdin create ref works' ' test_cmp expect actual ' +test_expect_success 'stdin does not create reflogs by default' ' + test_when_finished "git update-ref -d $outside" && + echo "create $outside $m" >stdin && + git update-ref --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $outside >actual && + test_cmp expect actual && + test_must_fail git reflog exists $outside +' + +test_expect_success 'stdin creates reflogs with --create-reflog' ' + echo "create $outside $m" >stdin && + git update-ref --create-reflog --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $outside >actual && + test_cmp expect actual && + git reflog exists $outside +' + test_expect_success 'stdin succeeds with quoted argument' ' git update-ref -d $a && echo "create $a \"$m\"" >stdin && @@ -519,7 +556,7 @@ test_expect_success 'stdin create ref works with path with space to blob' ' 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 ref '"'"'$c'"'"'" err && + grep "fatal: cannot lock ref '"'"'$c'"'"'" err && test_must_fail git rev-parse --verify -q $c ' @@ -555,7 +592,7 @@ test_expect_success 'stdin update ref works with right old value' ' 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 ref '"'"'$a'"'"'" err && + grep "fatal: cannot lock ref '"'"'$a'"'"'" err && git rev-parse $m >expect && git rev-parse $a >actual && test_cmp expect actual @@ -688,7 +725,7 @@ test_expect_success 'stdin update refs fails with wrong old value' ' update $c '' EOF test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: Cannot lock ref '"'"'$c'"'"'" err && + grep "fatal: cannot lock ref '"'"'$c'"'"'" err && git rev-parse $m >expect && git rev-parse $a >actual && test_cmp expect actual && @@ -883,7 +920,7 @@ test_expect_success 'stdin -z create ref works with path with space to blob' ' 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 ref '"'"'$c'"'"'" err && + grep "fatal: cannot lock ref '"'"'$c'"'"'" err && test_must_fail git rev-parse --verify -q $c ' @@ -899,7 +936,7 @@ test_expect_success 'stdin -z create ref fails when ref exists' ' git rev-parse "$c" >expect && printf $F "create $c" "$m~1" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: Cannot lock ref '"'"'$c'"'"'" err && + grep "fatal: cannot lock ref '"'"'$c'"'"'" err && git rev-parse "$c" >actual && test_cmp expect actual ' @@ -930,7 +967,7 @@ test_expect_success 'stdin -z update ref works with right old value' ' 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 ref '"'"'$a'"'"'" err && + grep "fatal: cannot lock ref '"'"'$a'"'"'" err && git rev-parse $m >expect && git rev-parse $a >actual && test_cmp expect actual @@ -1045,7 +1082,7 @@ 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" "$m" "$Z" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: Cannot lock ref '"'"'$c'"'"'" err && + grep "fatal: cannot lock ref '"'"'$c'"'"'" err && git rev-parse $m >expect && git rev-parse $a >actual && test_cmp expect actual && @@ -1093,4 +1130,23 @@ test_expect_success ULIMIT_FILE_DESCRIPTORS 'large transaction deleting branches ) ' +test_expect_success 'handle per-worktree refs in refs/bisect' ' + git commit --allow-empty -m "initial commit" && + git worktree add -b branch worktree && + ( + cd worktree && + git commit --allow-empty -m "test commit" && + git for-each-ref >for-each-ref.out && + ! grep refs/bisect for-each-ref.out && + git update-ref refs/bisect/something HEAD && + git rev-parse refs/bisect/something >../worktree-head && + git for-each-ref | grep refs/bisect/something + ) && + test_path_is_missing .git/refs/bisect && + test_must_fail git rev-parse refs/bisect/something && + git update-ref refs/bisect/something HEAD && + git rev-parse refs/bisect/something >main-head && + ! test_cmp main-head worktree-head +' + test_done diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh index 36378b0e3f..1f0dff3a0b 100755 --- a/t/t1401-symbolic-ref.sh +++ b/t/t1401-symbolic-ref.sh @@ -63,4 +63,55 @@ test_expect_success 'symbolic-ref fails to delete real ref' ' ' reset_to_sane +test_expect_success 'create large ref name' ' + # make 256+ character ref; some systems may not handle that, + # so be gentle + long=0123456789abcdef && + long=$long/$long/$long/$long && + long=$long/$long/$long/$long && + long_ref=refs/heads/$long && + tree=$(git write-tree) && + commit=$(echo foo | git commit-tree $tree) && + if git update-ref $long_ref $commit; then + test_set_prereq LONG_REF + else + echo >&2 "long refs not supported" + fi +' + +test_expect_success LONG_REF 'symbolic-ref can point to large ref name' ' + git symbolic-ref HEAD $long_ref && + echo $long_ref >expect && + git symbolic-ref HEAD >actual && + test_cmp expect actual +' + +test_expect_success LONG_REF 'we can parse long symbolic ref' ' + echo $commit >expect && + git rev-parse --verify HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'symbolic-ref reports failure in exit code' ' + test_when_finished "rm -f .git/HEAD.lock" && + >.git/HEAD.lock && + test_must_fail git symbolic-ref HEAD refs/heads/whatever +' + +test_expect_success 'symbolic-ref writes reflog entry' ' + git checkout -b log1 && + test_commit one && + git checkout -b log2 && + test_commit two && + git checkout --orphan orphan && + git symbolic-ref -m create HEAD refs/heads/log1 && + git symbolic-ref -m update HEAD refs/heads/log2 && + cat >expect <<-\EOF && + update + create + EOF + git log --format=%gs -g >actual && + test_cmp expect actual +' + test_done diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh index e5dc62e9ef..0790edf60d 100755 --- a/t/t1402-check-ref-format.sh +++ b/t/t1402-check-ref-format.sh @@ -62,9 +62,11 @@ invalid_ref 'heads/foo\bar' invalid_ref "$(printf 'heads/foo\t')" invalid_ref "$(printf 'heads/foo\177')" valid_ref "$(printf 'heads/fu\303\237')" -invalid_ref 'heads/*foo/bar' --refspec-pattern -invalid_ref 'heads/foo*/bar' --refspec-pattern -invalid_ref 'heads/f*o/bar' --refspec-pattern +valid_ref 'heads/*foo/bar' --refspec-pattern +valid_ref 'heads/foo*/bar' --refspec-pattern +valid_ref 'heads/f*o/bar' --refspec-pattern +invalid_ref 'heads/f*o*/bar' --refspec-pattern +invalid_ref 'heads/foo*/bar*' --refspec-pattern ref='foo' invalid_ref "$ref" diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index 779d4e3829..17a194bfa6 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -100,7 +100,8 @@ test_expect_success setup ' check_fsck && - test_line_count = 4 .git/logs/refs/heads/master + git reflog refs/heads/master >output && + test_line_count = 4 output ' test_expect_success rewind ' @@ -116,7 +117,8 @@ test_expect_success rewind ' check_have A B C D E F G H I J K L && - test_line_count = 5 .git/logs/refs/heads/master + git reflog refs/heads/master >output && + test_line_count = 5 output ' test_expect_success 'corrupt and check' ' @@ -134,7 +136,8 @@ test_expect_success 'reflog expire --dry-run should not touch reflog' ' --stale-fix \ --all && - test_line_count = 5 .git/logs/refs/heads/master && + git reflog refs/heads/master >output && + test_line_count = 5 output && check_fsck "missing blob $F" ' @@ -147,7 +150,8 @@ test_expect_success 'reflog expire' ' --stale-fix \ --all && - test_line_count = 2 .git/logs/refs/heads/master && + git reflog refs/heads/master >output && + test_line_count = 2 output && check_fsck "dangling commit $K" ' @@ -213,7 +217,8 @@ test_expect_success 'delete' ' test_expect_success 'rewind2' ' test_tick && git reset --hard HEAD~2 && - test_line_count = 4 .git/logs/refs/heads/master + git reflog refs/heads/master >output && + test_line_count = 4 output ' test_expect_success '--expire=never' ' @@ -222,7 +227,8 @@ test_expect_success '--expire=never' ' --expire=never \ --expire-unreachable=never \ --all && - test_line_count = 4 .git/logs/refs/heads/master + git reflog refs/heads/master >output && + test_line_count = 4 output ' test_expect_success 'gc.reflogexpire=never' ' @@ -230,7 +236,8 @@ test_expect_success 'gc.reflogexpire=never' ' git config gc.reflogexpire never && git config gc.reflogexpireunreachable never && git reflog expire --verbose --all && - test_line_count = 4 .git/logs/refs/heads/master + git reflog refs/heads/master >output && + test_line_count = 4 output ' test_expect_success 'gc.reflogexpire=false' ' @@ -238,7 +245,8 @@ test_expect_success 'gc.reflogexpire=false' ' git config gc.reflogexpire false && git config gc.reflogexpireunreachable false && git reflog expire --verbose --all && - test_line_count = 4 .git/logs/refs/heads/master && + git reflog refs/heads/master >output && + test_line_count = 4 output && git config --unset gc.reflogexpire && git config --unset gc.reflogexpireunreachable @@ -317,4 +325,17 @@ test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' ' test_cmp expect actual ' +test_expect_success 'no segfaults for reflog containing non-commit sha1s' ' + git update-ref --create-reflog -m "Creating ref" \ + refs/tests/tree-in-reflog HEAD && + git update-ref -m "Forcing tree" refs/tests/tree-in-reflog HEAD^{tree} && + git update-ref -m "Restoring to commit" refs/tests/tree-in-reflog HEAD && + git reflog refs/tests/tree-in-reflog +' + +test_expect_failure 'reflog with non-commit entries displays all entries' ' + git reflog refs/tests/tree-in-reflog >actual && + test_line_count = 3 actual +' + test_done diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh index 6f47c0dd0e..6ac7734d79 100755 --- a/t/t1411-reflog-show.sh +++ b/t/t1411-reflog-show.sh @@ -138,7 +138,7 @@ test_expect_success '--date magic does not override explicit @{0} syntax' ' : >expect test_expect_success 'empty reflog file' ' git branch empty && - : >.git/logs/refs/heads/empty && + git reflog expire --expire=all refs/heads/empty && git log -g empty >actual && test_cmp expect actual @@ -166,4 +166,9 @@ test_expect_success 'git log -g -p shows diffs vs. parents' ' test_cmp expect actual ' +test_expect_success 'reflog exists works' ' + git reflog exists refs/heads/master && + ! git reflog exists refs/heads/nonexistent +' + test_done diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh index 468e85621a..c465abe8e3 100755 --- a/t/t1430-bad-ref-name.sh +++ b/t/t1430-bad-ref-name.sh @@ -38,18 +38,20 @@ test_expect_success 'fast-import: fail on invalid branch name "bad[branch]name"' test_must_fail git fast-import <input ' -test_expect_success 'git branch shows badly named ref' ' +test_expect_success 'git branch shows badly named ref as warning' ' cp .git/refs/heads/master .git/refs/heads/broken...ref && test_when_finished "rm -f .git/refs/heads/broken...ref" && - git branch >output && - grep -e "broken\.\.\.ref" output + git branch >output 2>error && + grep -e "broken\.\.\.ref" error && + ! grep -e "broken\.\.\.ref" output ' test_expect_success 'branch -d can delete badly named ref' ' cp .git/refs/heads/master .git/refs/heads/broken...ref && test_when_finished "rm -f .git/refs/heads/broken...ref" && git branch -d broken...ref && - git branch >output && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && ! grep -e "broken\.\.\.ref" output ' @@ -57,7 +59,8 @@ test_expect_success 'branch -D can delete badly named ref' ' cp .git/refs/heads/master .git/refs/heads/broken...ref && test_when_finished "rm -f .git/refs/heads/broken...ref" && git branch -D broken...ref && - git branch >output && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && ! grep -e "broken\.\.\.ref" output ' @@ -68,6 +71,14 @@ test_expect_success 'branch -D cannot delete non-ref in .git dir' ' test_cmp expect .git/my-private-file ' +test_expect_success 'branch -D cannot delete ref in .git dir' ' + git rev-parse HEAD >.git/my-private-file && + git rev-parse HEAD >expect && + git branch foo/legit && + test_must_fail git branch -D foo////./././../../../my-private-file && + test_cmp expect .git/my-private-file +' + test_expect_success 'branch -D cannot delete absolute path' ' git branch -f extra && test_must_fail git branch -D "$(pwd)/.git/refs/heads/extra" && @@ -77,7 +88,8 @@ test_expect_success 'branch -D cannot delete absolute path' ' test_expect_success 'git branch cannot create a badly named ref' ' test_when_finished "rm -f .git/refs/heads/broken...ref" && test_must_fail git branch broken...ref && - git branch >output && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && ! grep -e "broken\.\.\.ref" output ' @@ -87,7 +99,8 @@ test_expect_success 'branch -m cannot rename to a bad ref name' ' git branch goodref && test_must_fail git branch -m goodref broken...ref && test_cmp_rev master goodref && - git branch >output && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && ! grep -e "broken\.\.\.ref" output ' @@ -96,14 +109,16 @@ test_expect_failure 'branch -m can rename from a bad ref name' ' test_when_finished "rm -f .git/refs/heads/broken...ref" && git branch -m broken...ref renamed && test_cmp_rev master renamed && - git branch >output && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && ! grep -e "broken\.\.\.ref" output ' test_expect_success 'push cannot create a badly named ref' ' test_when_finished "rm -f .git/refs/heads/broken...ref" && test_must_fail git push "file://$(pwd)" HEAD:refs/heads/broken...ref && - git branch >output && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && ! grep -e "broken\.\.\.ref" output ' @@ -123,7 +138,8 @@ test_expect_failure 'push --mirror can delete badly named ref' ' cp .git/refs/heads/master .git/refs/heads/broken...ref ) && git -C src push --mirror "file://$top/dest" && - git -C dest branch >output && + git -C dest branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && ! grep -e "broken\.\.\.ref" output ' @@ -151,7 +167,8 @@ test_expect_success 'update-ref -d can delete broken name' ' cp .git/refs/heads/master .git/refs/heads/broken...ref && test_when_finished "rm -f .git/refs/heads/broken...ref" && git update-ref -d refs/heads/broken...ref && - git branch >output && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && ! grep -e "broken\.\.\.ref" output ' diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index cfb32b6242..e66b7cb697 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -77,11 +77,31 @@ test_expect_success 'object with bad sha1' ' test_expect_success 'branch pointing to non-commit' ' git rev-parse HEAD^{tree} >.git/refs/heads/invalid && test_when_finished "git update-ref -d refs/heads/invalid" && - git fsck 2>out && + test_must_fail git fsck 2>out && cat out && grep "not a commit" out ' +test_expect_success 'HEAD link pointing at a funny object' ' + test_when_finished "mv .git/SAVED_HEAD .git/HEAD" && + mv .git/HEAD .git/SAVED_HEAD && + echo 0000000000000000000000000000000000000000 >.git/HEAD && + # avoid corrupt/broken HEAD from interfering with repo discovery + test_must_fail env GIT_DIR=.git git fsck 2>out && + cat out && + grep "detached HEAD points" out +' + +test_expect_success 'HEAD link pointing at a funny place' ' + test_when_finished "mv .git/SAVED_HEAD .git/HEAD" && + mv .git/HEAD .git/SAVED_HEAD && + echo "ref: refs/funny/place" >.git/HEAD && + # avoid corrupt/broken HEAD from interfering with repo discovery + test_must_fail env GIT_DIR=.git git fsck 2>out && + cat out && + grep "HEAD points to something strange" out +' + test_expect_success 'email without @ is okay' ' git cat-file commit HEAD >basis && sed "s/@/AT/" basis >okay && @@ -156,6 +176,18 @@ test_expect_success 'integer overflow in timestamps is reported' ' grep "error in commit $new.*integer overflow" out ' +test_expect_success 'commit with NUL in header' ' + git cat-file commit HEAD >basis && + sed "s/author ./author Q/" <basis | q_to_nul >commit-NUL-header && + new=$(git hash-object -t commit -w --stdin <commit-NUL-header) && + test_when_finished "remove_object $new" && + git update-ref refs/heads/bogus "$new" && + test_when_finished "git update-ref -d refs/heads/bogus" && + test_must_fail git fsck 2>out && + cat out && + grep "error in commit $new.*unterminated header: NUL at offset" out +' + test_expect_success 'malformatted tree object' ' test_when_finished "git update-ref -d refs/tags/wrong" && test_when_finished "remove_object \$T" && @@ -231,8 +263,8 @@ test_expect_success 'tag with incorrect tag name & missing tagger' ' git fsck --tags 2>out && cat >expect <<-EOF && - warning in tag $tag: invalid '\''tag'\'' name: wrong name format - warning in tag $tag: invalid format - expected '\''tagger'\'' line + warning in tag $tag: badTagName: invalid '\''tag'\'' name: wrong name format + warning in tag $tag: missingTaggerEntry: invalid format - expected '\''tagger'\'' line EOF test_cmp expect out ' @@ -256,6 +288,26 @@ test_expect_success 'tag with bad tagger' ' grep "error in tag .*: invalid author/committer" out ' +test_expect_success 'tag with NUL in header' ' + sha=$(git rev-parse HEAD) && + q_to_nul >tag-NUL-header <<-EOF && + object $sha + type commit + tag contains-Q-in-header + tagger T A Gger <tagger@example.com> 1234567890 -0000 + + This is an invalid tag. + EOF + + tag=$(git hash-object --literally -t tag -w --stdin <tag-NUL-header) && + test_when_finished "remove_object $tag" && + echo $tag >.git/refs/tags/wrong && + test_when_finished "git update-ref -d refs/tags/wrong" && + test_must_fail git fsck --tags 2>out && + cat out && + grep "error in tag $tag.*unterminated header: NUL at offset" out +' + test_expect_success 'cleaned up' ' git fsck >actual 2>&1 && test_cmp empty actual @@ -287,6 +339,17 @@ test_expect_success 'rev-list --verify-objects with bad sha1' ' grep -q "error: sha1 mismatch 63ffffffffffffffffffffffffffffffffffffff" out ' +test_expect_success 'force fsck to ignore double author' ' + git cat-file commit HEAD >basis && + sed "s/^author .*/&,&/" <basis | tr , \\n >multiple-authors && + new=$(git hash-object -t commit -w --stdin <multiple-authors) && + test_when_finished "remove_object $new" && + git update-ref refs/heads/bogus "$new" && + test_when_finished "git update-ref -d refs/heads/bogus" && + test_must_fail git fsck && + git -c fsck.multipleAuthors=ignore fsck +' + _bz='\0' _bz5="$_bz$_bz$_bz$_bz$_bz" _bz20="$_bz5$_bz5$_bz5$_bz5" @@ -420,4 +483,26 @@ test_expect_success 'fsck notices ref pointing to missing tag' ' test_must_fail git -C missing fsck ' +test_expect_success 'fsck --connectivity-only' ' + rm -rf connectivity-only && + git init connectivity-only && + ( + cd connectivity-only && + touch empty && + git add empty && + test_commit empty && + empty=.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 && + rm -f $empty && + echo invalid >$empty && + test_must_fail git fsck --strict && + git fsck --strict --connectivity-only && + tree=$(git rev-parse HEAD:) && + suffix=${tree#??} && + tree=.git/objects/${tree%$suffix}/$suffix && + rm -f $tree && + echo invalid >$tree && + test_must_fail git fsck --strict --connectivity-only + ) +' + test_done diff --git a/t/t1501-worktree.sh b/t/t1501-work-tree.sh index 8f36aa9fc4..cc5b870e58 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-work-tree.sh @@ -346,4 +346,81 @@ test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' test_cmp expected actual ' +test_expect_success 'Multi-worktree setup' ' + mkdir work && + mkdir -p repo.git/repos/foo && + cp repo.git/HEAD repo.git/index repo.git/repos/foo && + test_might_fail cp repo.git/sharedindex.* repo.git/repos/foo && + sane_unset GIT_DIR GIT_CONFIG GIT_WORK_TREE +' + +test_expect_success 'GIT_DIR set (1)' ' + echo "gitdir: repo.git/repos/foo" >gitfile && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + GIT_DIR=../gitfile git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual + ) +' + +test_expect_success 'GIT_DIR set (2)' ' + echo "gitdir: repo.git/repos/foo" >gitfile && + echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir && + ( + cd work && + GIT_DIR=../gitfile git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual + ) +' + +test_expect_success 'Auto discovery' ' + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual && + echo haha >data1 && + git add data1 && + git ls-files --full-name :/ | grep data1 >actual && + echo work/data1 >expect && + test_cmp expect actual + ) +' + +test_expect_success '$GIT_DIR/common overrides core.worktree' ' + mkdir elsewhere && + git --git-dir=repo.git config core.worktree "$TRASH_DIRECTORY/elsewhere" && + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual && + echo haha >data2 && + git add data2 && + git ls-files --full-name :/ | grep data2 >actual && + echo work/data2 >expect && + test_cmp expect actual + ) +' + +test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' ' + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + echo haha >data3 && + git --git-dir=../.git --work-tree=. add data3 && + git ls-files --full-name -- :/ | grep data3 >actual && + echo data3 >expect && + test_cmp expect actual + ) +' + test_done diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh index ebe7c3b87c..310f93fd30 100755 --- a/t/t1502-rev-parse-parseopt.sh +++ b/t/t1502-rev-parse-parseopt.sh @@ -3,7 +3,40 @@ test_description='test git rev-parse --parseopt' . ./test-lib.sh -sed -e 's/^|//' >expect <<\END_EXPECT +test_expect_success 'setup optionspec' ' + sed -e "s/^|//" >optionspec <<\EOF +|some-command [options] <args>... +| +|some-command does foo and bar! +|-- +|h,help show the help +| +|foo some nifty option --foo +|bar= some cool option --bar with an argument +|b,baz a short and long option +| +| An option group Header +|C? option C with an optional argument +|d,data? short and long option with an optional argument +| +| Argument hints +|B=arg short option required argument +|bar2=arg long option required argument +|e,fuz=with-space short and long option required argument +|s?some short option optional argument +|long?data long option optional argument +|g,fluf?path short and long option optional argument +|longest=very-long-argument-hint a very long argument hint +|pair=key=value with an equals sign in the hint +|short-hint=a with a one symbol hint +| +|Extras +|extra1 line above used to cause a segfault but no longer does +EOF +' + +test_expect_success 'test --parseopt help output' ' + sed -e "s/^|//" >expect <<\END_EXPECT && |cat <<\EOF |usage: some-command [options] <args>... | @@ -28,49 +61,23 @@ sed -e 's/^|//' >expect <<\END_EXPECT | -g, --fluf[=<path>] short and long option optional argument | --longest <very-long-argument-hint> | a very long argument hint +| --pair <key=value> with an equals sign in the hint +| --short-hint <a> with a one symbol hint | |Extras | --extra1 line above used to cause a segfault but no longer does | |EOF END_EXPECT - -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' ' test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec && test_i18ncmp expect output ' -cat > expect <<EOF +test_expect_success 'setup expect.1' " + cat > expect <<EOF set -- --foo --bar 'ham' -b -- 'arg' EOF +" test_expect_success 'test --parseopt' ' git rev-parse --parseopt -- --foo --bar=ham --baz arg < optionspec > output && @@ -82,9 +89,11 @@ test_expect_success 'test --parseopt with mixed options and arguments' ' test_cmp expect output ' -cat > expect <<EOF +test_expect_success 'setup expect.2' " + cat > expect <<EOF set -- --foo -- 'arg' '--bar=ham' EOF +" test_expect_success 'test --parseopt with --' ' git rev-parse --parseopt -- --foo -- arg --bar=ham < optionspec > output && @@ -96,54 +105,66 @@ test_expect_success 'test --parseopt --stop-at-non-option' ' test_cmp expect output ' -cat > expect <<EOF +test_expect_success 'setup expect.3' " + cat > expect <<EOF set -- --foo -- '--' 'arg' '--bar=ham' EOF +" test_expect_success 'test --parseopt --keep-dashdash' ' git rev-parse --parseopt --keep-dashdash -- --foo -- arg --bar=ham < optionspec > output && test_cmp expect output ' -cat >expect <<EOF +test_expect_success 'setup expect.4' " + cat >expect <<EOF set -- --foo -- '--' 'arg' '--spam=ham' EOF +" test_expect_success 'test --parseopt --keep-dashdash --stop-at-non-option with --' ' git rev-parse --parseopt --keep-dashdash --stop-at-non-option -- --foo -- arg --spam=ham <optionspec >output && test_cmp expect output ' -cat > expect <<EOF +test_expect_success 'setup expect.5' " + cat > expect <<EOF set -- --foo -- 'arg' '--spam=ham' EOF +" test_expect_success 'test --parseopt --keep-dashdash --stop-at-non-option without --' ' git rev-parse --parseopt --keep-dashdash --stop-at-non-option -- --foo arg --spam=ham <optionspec >output && test_cmp expect output ' -cat > expect <<EOF +test_expect_success 'setup expect.6' " + 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 +test_expect_success 'setup expect.7' " + 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 +test_expect_success 'setup expect.8' " + 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 && diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh index 823fe1d799..ab27d0db5c 100755 --- a/t/t1503-rev-parse-verify.sh +++ b/t/t1503-rev-parse-verify.sh @@ -85,8 +85,7 @@ test_expect_success 'fails silently when using -q' ' test_expect_success 'fails silently when using -q with deleted reflogs' ' ref=$(git rev-parse HEAD) && - : >.git/logs/refs/test && - git update-ref -m "message for refs/test" refs/test "$ref" && + git update-ref --create-reflog -m "message for refs/test" refs/test "$ref" && git reflog delete --updateref --rewrite refs/test@{0} && test_must_fail git rev-parse -q --verify refs/test@{0} >error 2>&1 && test_must_be_empty error @@ -94,16 +93,14 @@ test_expect_success 'fails silently when using -q with deleted reflogs' ' test_expect_success 'fails silently when using -q with not enough reflogs' ' ref=$(git rev-parse HEAD) && - : >.git/logs/refs/test2 && - git update-ref -m "message for refs/test2" refs/test2 "$ref" && + git update-ref --create-reflog -m "message for refs/test2" refs/test2 "$ref" && test_must_fail git rev-parse -q --verify refs/test2@{999} >error 2>&1 && test_must_be_empty error ' test_expect_success 'succeeds silently with -q and reflogs that do not go far back enough in time' ' ref=$(git rev-parse HEAD) && - : >.git/logs/refs/test3 && - git update-ref -m "message for refs/test3" refs/test3 "$ref" && + git update-ref --create-reflog -m "message for refs/test3" refs/test3 "$ref" && git rev-parse -q --verify refs/test3@{1.year.ago} >actual 2>error && test_must_be_empty error && echo "$ref" >expect && diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh index 1978947c41..46ef1f22dc 100755 --- a/t/t1507-rev-parse-upstream.sh +++ b/t/t1507-rev-parse-upstream.sh @@ -150,7 +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 && - fatal: No upstream configured for branch ${sq}non-tracking${sq} + fatal: no upstream configured for branch ${sq}non-tracking${sq} EOF error_message non-tracking@{u} 2>actual && test_i18ncmp expect actual @@ -158,7 +158,7 @@ test_expect_success 'branch@{u} error message when no upstream' ' test_expect_success '@{u} error message when no upstream' ' cat >expect <<-EOF && - fatal: No upstream configured for branch ${sq}master${sq} + fatal: no upstream configured for branch ${sq}master${sq} EOF test_must_fail git rev-parse --verify @{u} 2>actual && test_i18ncmp expect actual @@ -166,7 +166,7 @@ test_expect_success '@{u} error message when no upstream' ' test_expect_success 'branch@{u} error message with misspelt branch' ' cat >expect <<-EOF && - fatal: No such branch: ${sq}no-such-branch${sq} + fatal: no such branch: ${sq}no-such-branch${sq} EOF error_message no-such-branch@{u} 2>actual && test_i18ncmp expect actual @@ -183,7 +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 && - fatal: Upstream branch ${sq}refs/heads/side${sq} not stored as a remote-tracking branch + fatal: upstream branch ${sq}refs/heads/side${sq} not stored as a remote-tracking branch EOF error_message bad-upstream@{u} 2>actual && test_i18ncmp expect actual diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-work-tree.sh index b6977d4b39..553a3f601b 100755 --- a/t/t1509-root-worktree.sh +++ b/t/t1509-root-work-tree.sh @@ -125,7 +125,7 @@ fi ONE_SHA1=d00491fd7e5bb6fa28c517a0bb32b8b506539d4d test_expect_success 'setup' ' - rm -rf /foo + rm -rf /foo && mkdir /foo && mkdir /foo/bar && echo 1 > /foo/foome && @@ -218,7 +218,7 @@ unset GIT_WORK_TREE test_expect_success 'go to /' 'cd /' test_expect_success 'setup' ' - rm -rf /.git + rm -rf /.git && echo "Initialized empty Git repository in /.git/" > expected && git init > result && test_cmp expected result @@ -241,8 +241,8 @@ say "auto bare gitdir" # DESTROYYYYY!!!!! test_expect_success 'setup' ' - rm -rf /refs /objects /info /hooks - rm /* + rm -rf /refs /objects /info /hooks && + rm -f /expected /ls.expected /me /result && cd / && echo "Initialized empty Git repository in /" > expected && git init --bare > result && diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh index f6aa3c70f8..13ae12dfa7 100755 --- a/t/t1510-repo-setup.sh +++ b/t/t1510-repo-setup.sh @@ -106,6 +106,7 @@ setup_env () { expect () { cat >"$1/expected" <<-EOF setup: git_dir: $2 + setup: git_common_dir: $2 setup: worktree: $3 setup: cwd: $4 setup: prefix: $5 diff --git a/t/t1514-rev-parse-push.sh b/t/t1514-rev-parse-push.sh new file mode 100755 index 0000000000..7214f5b33f --- /dev/null +++ b/t/t1514-rev-parse-push.sh @@ -0,0 +1,63 @@ +#!/bin/sh + +test_description='test <branch>@{push} syntax' +. ./test-lib.sh + +resolve () { + echo "$2" >expect && + git rev-parse --symbolic-full-name "$1" >actual && + test_cmp expect actual +} + +test_expect_success 'setup' ' + git init --bare parent.git && + git init --bare other.git && + git remote add origin parent.git && + git remote add other other.git && + test_commit base && + git push origin HEAD && + git branch --set-upstream-to=origin/master master && + git branch --track topic origin/master && + git push origin topic && + git push other topic +' + +test_expect_success '@{push} with default=nothing' ' + test_config push.default nothing && + test_must_fail git rev-parse master@{push} +' + +test_expect_success '@{push} with default=simple' ' + test_config push.default simple && + resolve master@{push} refs/remotes/origin/master +' + +test_expect_success 'triangular @{push} fails with default=simple' ' + test_config push.default simple && + test_must_fail git rev-parse topic@{push} +' + +test_expect_success '@{push} with default=current' ' + test_config push.default current && + resolve topic@{push} refs/remotes/origin/topic +' + +test_expect_success '@{push} with default=matching' ' + test_config push.default matching && + resolve topic@{push} refs/remotes/origin/topic +' + +test_expect_success '@{push} with pushremote defined' ' + test_config push.default current && + test_config branch.topic.pushremote other && + resolve topic@{push} refs/remotes/other/topic +' + +test_expect_success '@{push} with push refspecs' ' + test_config push.default nothing && + test_config remote.origin.push refs/heads/*:refs/heads/magic/* && + git push && + resolve topic@{push} refs/remotes/origin/magic/topic +' + +test_done diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh new file mode 100755 index 0000000000..3694174989 --- /dev/null +++ b/t/t2025-worktree-add.sh @@ -0,0 +1,201 @@ +#!/bin/sh + +test_description='test git worktree add' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit init +' + +test_expect_success '"add" an existing worktree' ' + mkdir -p existing/subtree && + test_must_fail git worktree add --detach existing master +' + +test_expect_success '"add" an existing empty worktree' ' + mkdir existing_empty && + git worktree add --detach existing_empty master +' + +test_expect_success '"add" refuses to checkout locked branch' ' + test_must_fail git worktree add zere master && + ! test -d zere && + ! test -d .git/worktrees/zere +' + +test_expect_success 'checking out paths not complaining about linked checkouts' ' + ( + cd existing_empty && + echo dirty >>init.t && + git checkout master -- init.t + ) +' + +test_expect_success '"add" worktree' ' + git rev-parse HEAD >expect && + git worktree add --detach here master && + ( + cd here && + test_cmp ../init.t init.t && + test_must_fail git symbolic-ref HEAD && + git rev-parse HEAD >actual && + test_cmp ../expect actual && + git fsck + ) +' + +test_expect_success '"add" worktree from a subdir' ' + ( + mkdir sub && + cd sub && + git worktree add --detach here master && + cd here && + test_cmp ../../init.t init.t + ) +' + +test_expect_success '"add" from a linked checkout' ' + ( + cd here && + git worktree add --detach nested-here master && + cd nested-here && + git fsck + ) +' + +test_expect_success '"add" worktree creating new branch' ' + git worktree add -b newmaster there master && + ( + cd there && + test_cmp ../init.t init.t && + git symbolic-ref HEAD >actual && + echo refs/heads/newmaster >expect && + test_cmp expect actual && + git fsck + ) +' + +test_expect_success 'die the same branch is already checked out' ' + ( + cd here && + test_must_fail git checkout newmaster + ) +' + +test_expect_success SYMLINKS 'die the same branch is already checked out (symlink)' ' + head=$(git -C there rev-parse --git-path HEAD) && + ref=$(git -C there symbolic-ref HEAD) && + rm "$head" && + ln -s "$ref" "$head" && + test_must_fail git -C here checkout newmaster +' + +test_expect_success 'not die the same branch is already checked out' ' + ( + cd here && + git worktree add --force anothernewmaster newmaster + ) +' + +test_expect_success 'not die on re-checking out current branch' ' + ( + cd there && + git checkout newmaster + ) +' + +test_expect_success '"add" from a bare repo' ' + ( + git clone --bare . bare && + cd bare && + git worktree add -b bare-master ../there2 master + ) +' + +test_expect_success 'checkout from a bare repo without "add"' ' + ( + cd bare && + test_must_fail git checkout master + ) +' + +test_expect_success 'checkout with grafts' ' + test_when_finished rm .git/info/grafts && + test_commit abc && + SHA1=`git rev-parse HEAD` && + test_commit def && + test_commit xyz && + echo "`git rev-parse HEAD` $SHA1" >.git/info/grafts && + cat >expected <<-\EOF && + xyz + abc + EOF + git log --format=%s -2 >actual && + test_cmp expected actual && + git worktree add --detach grafted master && + git --git-dir=grafted/.git log --format=%s -2 >actual && + test_cmp expected actual +' + +test_expect_success '"add" from relative HEAD' ' + test_commit a && + test_commit b && + test_commit c && + git rev-parse HEAD~1 >expected && + git worktree add relhead HEAD~1 && + git -C relhead rev-parse HEAD >actual && + test_cmp expected actual +' + +test_expect_success '"add -b" with <branch> omitted' ' + git worktree add -b burble flornk && + test_cmp_rev HEAD burble +' + +test_expect_success '"add --detach" with <branch> omitted' ' + git worktree add --detach fishhook && + git rev-parse HEAD >expected && + git -C fishhook rev-parse HEAD >actual && + test_cmp expected actual && + test_must_fail git -C fishhook symbolic-ref HEAD +' + +test_expect_success '"add" with <branch> omitted' ' + git worktree add wiffle/bat && + test_cmp_rev HEAD bat +' + +test_expect_success '"add" auto-vivify does not clobber existing branch' ' + test_commit c1 && + test_commit c2 && + git branch precious HEAD~1 && + test_must_fail git worktree add precious && + test_cmp_rev HEAD~1 precious && + test_path_is_missing precious +' + +test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' ' + git worktree add --detach mish/mash && + test_must_fail git rev-parse mash -- && + test_must_fail git -C mish/mash symbolic-ref HEAD +' + +test_expect_success '"add" -b/-B mutually exclusive' ' + test_must_fail git worktree add -b poodle -B poodle bamboo master +' + +test_expect_success '"add" -b/--detach mutually exclusive' ' + test_must_fail git worktree add -b poodle --detach bamboo master +' + +test_expect_success '"add" -B/--detach mutually exclusive' ' + test_must_fail git worktree add -B poodle --detach bamboo master +' + +test_expect_success 'local clone from linked checkout' ' + git clone --local here here-clone && + ( cd here-clone && git fsck ) +' + +test_done diff --git a/t/t2026-worktree-prune.sh b/t/t2026-worktree-prune.sh new file mode 100755 index 0000000000..a0f1e3bb80 --- /dev/null +++ b/t/t2026-worktree-prune.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +test_description='prune $GIT_DIR/worktrees' + +. ./test-lib.sh + +test_expect_success initialize ' + git commit --allow-empty -m init +' + +test_expect_success 'worktree prune on normal repo' ' + git worktree prune && + test_must_fail git worktree prune abc +' + +test_expect_success 'prune files inside $GIT_DIR/worktrees' ' + mkdir .git/worktrees && + : >.git/worktrees/abc && + git worktree prune --verbose >actual && + cat >expect <<EOF && +Removing worktrees/abc: not a valid directory +EOF + test_i18ncmp expect actual && + ! test -f .git/worktrees/abc && + ! test -d .git/worktrees +' + +test_expect_success 'prune directories without gitdir' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + cat >expect <<EOF && +Removing worktrees/def: gitdir file does not exist +EOF + git worktree prune --verbose >actual && + test_i18ncmp expect actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success SANITY 'prune directories with unreadable gitdir' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + : >.git/worktrees/def/gitdir && + chmod u-r .git/worktrees/def/gitdir && + git worktree prune --verbose >actual && + test_i18ngrep "Removing worktrees/def: unable to read gitdir file" actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success 'prune directories with invalid gitdir' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + : >.git/worktrees/def/gitdir && + git worktree prune --verbose >actual && + test_i18ngrep "Removing worktrees/def: invalid gitdir file" actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success 'prune directories with gitdir pointing to nowhere' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + echo "$(pwd)"/nowhere >.git/worktrees/def/gitdir && + git worktree prune --verbose >actual && + test_i18ngrep "Removing worktrees/def: gitdir file points to non-existent location" actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success 'not prune locked checkout' ' + test_when_finished rm -r .git/worktrees && + mkdir -p .git/worktrees/ghi && + : >.git/worktrees/ghi/locked && + git worktree prune && + test -d .git/worktrees/ghi +' + +test_expect_success 'not prune recent checkouts' ' + test_when_finished rm -r .git/worktrees && + mkdir zz && + mkdir -p .git/worktrees/jlm && + echo "$(pwd)"/zz >.git/worktrees/jlm/gitdir && + rmdir zz && + git worktree prune --verbose --expire=2.days.ago && + test -d .git/worktrees/jlm +' + +test_expect_success 'not prune proper checkouts' ' + test_when_finished rm -r .git/worktrees && + git worktree add --detach "$PWD/nop" master && + git worktree prune && + test -d .git/worktrees/nop +' + +test_done diff --git a/t/t2027-worktree-list.sh b/t/t2027-worktree-list.sh new file mode 100755 index 0000000000..1b1b65a6b0 --- /dev/null +++ b/t/t2027-worktree-list.sh @@ -0,0 +1,99 @@ +#!/bin/sh + +test_description='test git worktree list' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit init +' + +test_expect_success 'rev-parse --git-common-dir on main worktree' ' + git rev-parse --git-common-dir >actual && + echo .git >expected && + test_cmp expected actual && + mkdir sub && + git -C sub rev-parse --git-common-dir >actual2 && + echo sub/.git >expected2 && + test_cmp expected2 actual2 +' + +test_expect_success '"list" all worktrees from main' ' + echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect && + test_when_finished "rm -rf here && git worktree prune" && + git worktree add --detach here master && + echo "$(git -C here rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >>expect && + git worktree list | sed "s/ */ /g" >actual && + test_cmp expect actual +' + +test_expect_success '"list" all worktrees from linked' ' + echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect && + test_when_finished "rm -rf here && git worktree prune" && + git worktree add --detach here master && + echo "$(git -C here rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >>expect && + git -C here worktree list | sed "s/ */ /g" >actual && + test_cmp expect actual +' + +test_expect_success '"list" all worktrees --porcelain' ' + echo "worktree $(git rev-parse --show-toplevel)" >expect && + echo "HEAD $(git rev-parse HEAD)" >>expect && + echo "branch $(git symbolic-ref HEAD)" >>expect && + echo >>expect && + test_when_finished "rm -rf here && git worktree prune" && + git worktree add --detach here master && + echo "worktree $(git -C here rev-parse --show-toplevel)" >>expect && + echo "HEAD $(git rev-parse HEAD)" >>expect && + echo "detached" >>expect && + echo >>expect && + git worktree list --porcelain >actual && + test_cmp expect actual +' + +test_expect_success 'bare repo setup' ' + git init --bare bare1 && + echo "data" >file1 && + git add file1 && + git commit -m"File1: add data" && + git push bare1 master && + git reset --hard HEAD^ +' + +test_expect_success '"list" all worktrees from bare main' ' + test_when_finished "rm -rf there && git -C bare1 worktree prune" && + git -C bare1 worktree add --detach ../there master && + echo "$(pwd)/bare1 (bare)" >expect && + echo "$(git -C there rev-parse --show-toplevel) $(git -C there rev-parse --short HEAD) (detached HEAD)" >>expect && + git -C bare1 worktree list | sed "s/ */ /g" >actual && + test_cmp expect actual +' + +test_expect_success '"list" all worktrees --porcelain from bare main' ' + test_when_finished "rm -rf there && git -C bare1 worktree prune" && + git -C bare1 worktree add --detach ../there master && + echo "worktree $(pwd)/bare1" >expect && + echo "bare" >>expect && + echo >>expect && + echo "worktree $(git -C there rev-parse --show-toplevel)" >>expect && + echo "HEAD $(git -C there rev-parse HEAD)" >>expect && + echo "detached" >>expect && + echo >>expect && + git -C bare1 worktree list --porcelain >actual && + test_cmp expect actual +' + +test_expect_success '"list" all worktrees from linked with a bare main' ' + test_when_finished "rm -rf there && git -C bare1 worktree prune" && + git -C bare1 worktree add --detach ../there master && + echo "$(pwd)/bare1 (bare)" >expect && + echo "$(git -C there rev-parse --show-toplevel) $(git -C there rev-parse --short HEAD) (detached HEAD)" >>expect && + git -C there worktree list | sed "s/ */ /g" >actual && + test_cmp expect actual +' + +test_expect_success 'bare repo cleanup' ' + rm -rf bare1 +' + +test_done diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index e16b15d3e5..314c73c5a7 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -84,6 +84,8 @@ test_expect_success 'non-qualified update in subdir updates from the root' ' ( cd dir1 && echo even more >>sub2 && + git --literal-pathspecs add -u && + echo even more >>sub2 && git add -u ) && : >expect && diff --git a/t/t2202-add-addremove.sh b/t/t2202-add-addremove.sh index fc8b59e7f7..6a5a3166b1 100755 --- a/t/t2202-add-addremove.sh +++ b/t/t2202-add-addremove.sh @@ -14,6 +14,7 @@ test_expect_success setup ' echo expect echo ignored ) >.gitignore && + git --literal-pathspecs add --all && >will-remove && git add --all && test_tick && diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh index 88be904c09..c525656b2c 100755 --- a/t/t3000-ls-files-others.sh +++ b/t/t3000-ls-files-others.sh @@ -65,6 +65,13 @@ test_expect_success '--no-empty-directory hides empty directory' ' test_cmp expected3 output ' +test_expect_success 'ls-files --others handles non-submodule .git' ' + mkdir not-a-submodule && + echo foo >not-a-submodule/.git && + git ls-files -o >output && + test_cmp expected1 output +' + test_expect_success SYMLINKS 'ls-files --others with symlinked submodule' ' git init super && git init sub && diff --git a/t/t3020-ls-files-error-unmatch.sh b/t/t3020-ls-files-error-unmatch.sh index ca01053bcc..124e73b8e6 100755 --- a/t/t3020-ls-files-error-unmatch.sh +++ b/t/t3020-ls-files-error-unmatch.sh @@ -22,7 +22,7 @@ test_expect_success \ 'test_must_fail git ls-files --error-unmatch foo bar-does-not-match' test_expect_success \ - 'git ls-files --error-unmatch should succeed eith matched paths.' \ + 'git ls-files --error-unmatch should succeed with matched paths.' \ 'git ls-files --error-unmatch foo bar' test_done diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index 82e18548c3..6224187632 100755 --- a/t/t3030-merge-recursive.sh +++ b/t/t3030-merge-recursive.sh @@ -629,5 +629,35 @@ test_expect_failure 'merge-recursive rename vs. rename/symlink' ' test_cmp expected actual ' +test_expect_success 'merging with triple rename across D/F conflict' ' + git reset --hard HEAD && + git checkout -b main && + git rm -rf . && + + echo "just a file" >sub1 && + mkdir -p sub2 && + echo content1 >sub2/file1 && + echo content2 >sub2/file2 && + echo content3 >sub2/file3 && + mkdir simple && + echo base >simple/bar && + git add -A && + test_tick && + git commit -m base && + + git checkout -b other && + echo more >>simple/bar && + test_tick && + git commit -a -m changesimplefile && + + git checkout main && + git rm sub1 && + git mv sub2 sub1 && + test_tick && + git commit -m changefiletodir && + + test_tick && + git merge other +' test_done diff --git a/t/t3033-merge-toplevel.sh b/t/t3033-merge-toplevel.sh new file mode 100755 index 0000000000..46aadc410b --- /dev/null +++ b/t/t3033-merge-toplevel.sh @@ -0,0 +1,136 @@ +#!/bin/sh + +test_description='"git merge" top-level frontend' + +. ./test-lib.sh + +t3033_reset () { + git checkout -B master two && + git branch -f left three && + git branch -f right four +} + +test_expect_success setup ' + test_commit one && + git branch left && + git branch right && + test_commit two && + git checkout left && + test_commit three && + git checkout right && + test_commit four && + git checkout master +' + +# Local branches + +test_expect_success 'merge an octopus into void' ' + t3033_reset && + git checkout --orphan test && + git rm -fr . && + test_must_fail git merge left right && + test_must_fail git rev-parse --verify HEAD && + git diff --quiet && + test_must_fail git rev-parse HEAD +' + +test_expect_success 'merge an octopus, fast-forward (ff)' ' + t3033_reset && + git reset --hard one && + git merge left right && + # one is ancestor of three (left) and four (right) + test_must_fail git rev-parse --verify HEAD^3 && + git rev-parse HEAD^1 HEAD^2 | sort >actual && + git rev-parse three four | sort >expect && + test_cmp expect actual +' + +test_expect_success 'merge octopus, non-fast-forward (ff)' ' + t3033_reset && + git reset --hard one && + git merge --no-ff left right && + # one is ancestor of three (left) and four (right) + test_must_fail git rev-parse --verify HEAD^4 && + git rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual && + git rev-parse one three four | sort >expect && + test_cmp expect actual +' + +test_expect_success 'merge octopus, fast-forward (does not ff)' ' + t3033_reset && + git merge left right && + # two (master) is not an ancestor of three (left) and four (right) + test_must_fail git rev-parse --verify HEAD^4 && + git rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual && + git rev-parse two three four | sort >expect && + test_cmp expect actual +' + +test_expect_success 'merge octopus, non-fast-forward' ' + t3033_reset && + git merge --no-ff left right && + test_must_fail git rev-parse --verify HEAD^4 && + git rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual && + git rev-parse two three four | sort >expect && + test_cmp expect actual +' + +# The same set with FETCH_HEAD + +test_expect_success 'merge FETCH_HEAD octopus into void' ' + t3033_reset && + git checkout --orphan test && + git rm -fr . && + git fetch . left right && + test_must_fail git merge FETCH_HEAD && + test_must_fail git rev-parse --verify HEAD && + git diff --quiet && + test_must_fail git rev-parse HEAD +' + +test_expect_success 'merge FETCH_HEAD octopus fast-forward (ff)' ' + t3033_reset && + git reset --hard one && + git fetch . left right && + git merge FETCH_HEAD && + # one is ancestor of three (left) and four (right) + test_must_fail git rev-parse --verify HEAD^3 && + git rev-parse HEAD^1 HEAD^2 | sort >actual && + git rev-parse three four | sort >expect && + test_cmp expect actual +' + +test_expect_success 'merge FETCH_HEAD octopus non-fast-forward (ff)' ' + t3033_reset && + git reset --hard one && + git fetch . left right && + git merge --no-ff FETCH_HEAD && + # one is ancestor of three (left) and four (right) + test_must_fail git rev-parse --verify HEAD^4 && + git rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual && + git rev-parse one three four | sort >expect && + test_cmp expect actual +' + +test_expect_success 'merge FETCH_HEAD octopus fast-forward (does not ff)' ' + t3033_reset && + git fetch . left right && + git merge FETCH_HEAD && + # two (master) is not an ancestor of three (left) and four (right) + test_must_fail git rev-parse --verify HEAD^4 && + git rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual && + git rev-parse two three four | sort >expect && + test_cmp expect actual +' + +test_expect_success 'merge FETCH_HEAD octopus non-fast-forward' ' + t3033_reset && + git fetch . left right && + git merge --no-ff FETCH_HEAD && + test_must_fail git rev-parse --verify HEAD^4 && + git rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual && + git rev-parse two three four | sort >expect && + test_cmp expect actual +' + +test_done diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index ddea49808d..a897248490 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -59,7 +59,7 @@ test_expect_success 'git branch -l d/e/f should create a branch and a log' ' 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_must_fail git reflog exists refs/heads/d/e/f ' test_expect_success 'git branch j/k should work after branch j has been deleted' ' @@ -82,13 +82,13 @@ test_expect_success 'git branch -m dumps usage' ' 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 + git reflog exists 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 + git reflog exists refs/heads/n ' test_expect_success 'git branch -m o/o o should fail when o/p exists' ' @@ -267,12 +267,12 @@ 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_path_is_file .git/logs/refs/heads/s/s && + git reflog exists refs/heads/s/s && git branch -l s/t && - test_path_is_file .git/logs/refs/heads/s/t && + git reflog exists 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 reflog exists refs/heads/s ' test_expect_success 'config information was renamed, too' ' @@ -446,6 +446,13 @@ test_expect_success '--set-upstream-to fails on a non-ref' ' test_must_fail git branch --set-upstream-to HEAD^{} ' +test_expect_success '--set-upstream-to fails on locked config' ' + test_when_finished "rm -f .git/config.lock" && + >.git/config.lock && + git branch locked && + test_must_fail git branch --set-upstream-to locked +' + test_expect_success 'use --set-upstream-to modify HEAD' ' test_config branch.master.remote foo && test_config branch.master.merge foo && @@ -466,6 +473,13 @@ 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 '--unset-upstream should fail if config is locked' ' + test_when_finished "rm -f .git/config.lock" && + git branch --set-upstream-to locked && + >.git/config.lock && + test_must_fail git branch --unset-upstream +' + test_expect_success 'test --unset-upstream on HEAD' ' git branch my14 && test_config branch.master.remote foo && @@ -579,7 +593,7 @@ test_expect_success 'avoid ambiguous track' ' git config remote.ambi1.fetch refs/heads/lalala:refs/heads/master && git config remote.ambi2.url lilili && git config remote.ambi2.fetch refs/heads/lilili:refs/heads/master && - git branch all1 master && + test_must_fail git branch all1 master && test -z "$(git config branch.all1.merge)" ' diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index f51d0f3cad..4261403cf6 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -106,6 +106,19 @@ EOF test_i18ncmp expect actual ' +test_expect_success 'git branch shows detached HEAD properly after checkout --detach' ' + git checkout master && + cat >expect <<EOF && +* (HEAD detached at $(git rev-parse --short HEAD^0)) + branch-one + branch-two + master +EOF + git checkout --detach && + git branch >actual && + test_i18ncmp expect actual +' + test_expect_success 'git branch shows detached HEAD properly after moving' ' cat >expect <<EOF && * (HEAD detached from $(git rev-parse --short HEAD)) @@ -143,4 +156,32 @@ EOF test_i18ncmp expect actual ' +test_expect_success 'git branch `--sort` option' ' + cat >expect <<-\EOF && + * (HEAD detached from fromtag) + branch-two + branch-one + master + EOF + git branch --sort=objectsize >actual && + test_i18ncmp expect actual +' + +test_expect_success 'git branch --points-at option' ' + cat >expect <<-\EOF && + branch-one + master + EOF + git branch --points-at=branch-one >actual && + test_cmp expect actual +' + +test_expect_success 'ambiguous branch/tag not marked' ' + git tag ambiguous && + git branch ambiguous && + echo " ambiguous" >expect && + git branch --list ambiguous >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh index aa9eb3a3e5..db244d2f88 100755 --- a/t/t3210-pack-refs.sh +++ b/t/t3210-pack-refs.sh @@ -160,6 +160,13 @@ test_expect_success 'pack ref directly below refs/' ' test_path_is_missing .git/refs/top ' +test_expect_success 'do not pack ref in refs/bisect' ' + git update-ref refs/bisect/local HEAD && + git pack-refs --all --prune && + ! grep refs/bisect/local .git/packed-refs >/dev/null && + test_path_is_file .git/refs/bisect/local +' + test_expect_success 'disable reflogs' ' git config core.logallrefupdates false && rm -rf .git/logs @@ -169,7 +176,7 @@ test_expect_success 'create packed foo/bar/baz branch' ' git branch foo/bar/baz && git pack-refs --all --prune && test_path_is_missing .git/refs/heads/foo/bar/baz && - test_path_is_missing .git/logs/refs/heads/foo/bar/baz + test_must_fail git reflog exists refs/heads/foo/bar/baz ' test_expect_success 'notice d/f conflict with existing directory' ' @@ -187,4 +194,21 @@ test_expect_success 'notice d/f conflict with existing ref' ' test_must_fail git branch foo/bar/baz/lots/of/extra/components ' +test_expect_success 'timeout if packed-refs.lock exists' ' + LOCK=.git/packed-refs.lock && + >"$LOCK" && + test_when_finished "rm -f $LOCK" && + test_must_fail git pack-refs --all --prune +' + +test_expect_success 'retry acquiring packed-refs.lock' ' + LOCK=.git/packed-refs.lock && + >"$LOCK" && + test_when_finished "wait; rm -f $LOCK" && + { + ( sleep 1 ; rm -f $LOCK ) & + } && + git -c core.packedrefstimeout=3000 pack-refs --all --prune +' + test_done diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh index 8cffd35fb0..cd70274ea5 100755 --- a/t/t3301-notes.sh +++ b/t/t3301-notes.sh @@ -1122,6 +1122,12 @@ test_expect_success 'git notes copy diagnoses too many or too few parameters' ' test_must_fail git notes copy one two three ' +test_expect_success 'git notes get-ref expands refs/heads/master to refs/notes/refs/heads/master' ' + test_unconfig core.notesRef && + sane_unset GIT_NOTES_REF && + test "$(git notes --ref=refs/heads/master get-ref)" = "refs/notes/refs/heads/master" +' + test_expect_success 'git notes get-ref (no overrides)' ' test_unconfig core.notesRef && sane_unset GIT_NOTES_REF && diff --git a/t/t3309-notes-merge-auto-resolve.sh b/t/t3309-notes-merge-auto-resolve.sh index 461fd84755..14c2adf970 100755 --- a/t/t3309-notes-merge-auto-resolve.sh +++ b/t/t3309-notes-merge-auto-resolve.sh @@ -298,6 +298,13 @@ test_expect_success 'merge z into y with invalid strategy => Fail/No changes' ' verify_notes y y ' +test_expect_success 'merge z into y with invalid configuration option => Fail/No changes' ' + git config core.notesRef refs/notes/y && + test_must_fail git -c notes.mergeStrategy="foo" notes merge z && + # Verify no changes (y) + verify_notes y y +' + cat <<EOF | sort >expect_notes_ours 68b8630d25516028bed862719855b3d6768d7833 $commit_sha15 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14 @@ -365,6 +372,28 @@ test_expect_success 'reset to pre-merge state (y)' ' verify_notes y y ' +test_expect_success 'merge z into y with "ours" configuration option => Non-conflicting 3-way merge' ' + git -c notes.mergeStrategy="ours" notes merge z && + verify_notes y ours +' + +test_expect_success 'reset to pre-merge state (y)' ' + git update-ref refs/notes/y refs/notes/y^1 && + # Verify pre-merge state + verify_notes y y +' + +test_expect_success 'merge z into y with "ours" per-ref configuration option => Non-conflicting 3-way merge' ' + git -c notes.y.mergeStrategy="ours" notes merge z && + verify_notes y ours +' + +test_expect_success 'reset to pre-merge state (y)' ' + git update-ref refs/notes/y refs/notes/y^1 && + # Verify pre-merge state + verify_notes y y +' + cat <<EOF | sort >expect_notes_theirs 9b4b2c61f0615412da3c10f98ff85b57c04ec765 $commit_sha15 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14 @@ -432,6 +461,17 @@ test_expect_success 'reset to pre-merge state (y)' ' verify_notes y y ' +test_expect_success 'merge z into y with "theirs" strategy overriding configuration option "ours" => Non-conflicting 3-way merge' ' + git -c notes.mergeStrategy="ours" notes merge --strategy=theirs z && + verify_notes y theirs +' + +test_expect_success 'reset to pre-merge state (y)' ' + git update-ref refs/notes/y refs/notes/y^1 && + # Verify pre-merge state + verify_notes y y +' + cat <<EOF | sort >expect_notes_union 7c4e546efd0fe939f876beb262ece02797880b54 $commit_sha15 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14 @@ -505,6 +545,34 @@ test_expect_success 'reset to pre-merge state (y)' ' verify_notes y y ' +test_expect_success 'merge z into y with "union" strategy overriding per-ref configuration => Non-conflicting 3-way merge' ' + git -c notes.y.mergeStrategy="theirs" notes merge --strategy=union z && + verify_notes y union +' + +test_expect_success 'reset to pre-merge state (y)' ' + git update-ref refs/notes/y refs/notes/y^1 && + # Verify pre-merge state + verify_notes y y +' + +test_expect_success 'merge z into y with "union" per-ref overriding general configuration => Non-conflicting 3-way merge' ' + git -c notes.y.mergeStrategy="union" -c notes.mergeStrategy="theirs" notes merge z && + verify_notes y union +' + +test_expect_success 'reset to pre-merge state (y)' ' + git update-ref refs/notes/y refs/notes/y^1 && + # Verify pre-merge state + verify_notes y y +' + +test_expect_success 'merge z into y with "manual" per-ref only checks specific ref configuration => Conflicting 3-way merge' ' + test_must_fail git -c notes.z.mergeStrategy="union" notes merge z && + git notes merge --abort && + verify_notes y y +' + cat <<EOF | sort >expect_notes_union2 d682107b8bf7a7aea1e537a8d5cb6a12b60135f1 $commit_sha15 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14 @@ -644,4 +712,15 @@ test_expect_success 'merge y into z with "cat_sort_uniq" strategy => Non-conflic verify_notes z cat_sort_uniq ' +test_expect_success 'reset to pre-merge state (z)' ' + git update-ref refs/notes/z refs/notes/z^1 && + # Verify pre-merge state + verify_notes z z +' + +test_expect_success 'merge y into z with "cat_sort_uniq" strategy configuration option => Non-conflicting 3-way merge' ' + git -c notes.mergeStrategy="cat_sort_uniq" notes merge y && + verify_notes z cat_sort_uniq +' + test_done diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh index 195bb97f85..d5572121da 100755 --- a/t/t3310-notes-merge-manual-resolve.sh +++ b/t/t3310-notes-merge-manual-resolve.sh @@ -314,6 +314,18 @@ y and z notes on 1st commit EOF +test_expect_success 'do not allow mixing --commit and --abort' ' + test_must_fail git notes merge --commit --abort +' + +test_expect_success 'do not allow mixing --commit and --strategy' ' + test_must_fail git notes merge --commit --strategy theirs +' + +test_expect_success 'do not allow mixing --abort and --strategy' ' + test_must_fail git notes merge --abort --strategy theirs +' + test_expect_success 'finalize conflicting merge (z => m)' ' # Resolve conflicts and finalize merge cat >.git/NOTES_MERGE_WORKTREE/$commit_sha1 <<EOF && diff --git a/t/t3320-notes-merge-worktrees.sh b/t/t3320-notes-merge-worktrees.sh new file mode 100755 index 0000000000..1f71d589f5 --- /dev/null +++ b/t/t3320-notes-merge-worktrees.sh @@ -0,0 +1,72 @@ +#!/bin/sh +# +# Copyright (c) 2015 Twitter, Inc +# + +test_description='Test merging of notes trees in multiple worktrees' + +. ./test-lib.sh + +test_expect_success 'setup commit' ' + test_commit tantrum +' + +commit_tantrum=$(git rev-parse tantrum^{commit}) + +test_expect_success 'setup notes ref (x)' ' + git config core.notesRef refs/notes/x && + git notes add -m "x notes on tantrum" tantrum +' + +test_expect_success 'setup local branch (y)' ' + git update-ref refs/notes/y refs/notes/x && + git config core.notesRef refs/notes/y && + git notes remove tantrum +' + +test_expect_success 'setup remote branch (z)' ' + git update-ref refs/notes/z refs/notes/x && + git config core.notesRef refs/notes/z && + git notes add -f -m "conflicting notes on tantrum" tantrum +' + +test_expect_success 'modify notes ref ourselves (x)' ' + git config core.notesRef refs/notes/x && + git notes add -f -m "more conflicting notes on tantrum" tantrum +' + +test_expect_success 'create some new worktrees' ' + git worktree add -b newbranch worktree master && + git worktree add -b newbranch2 worktree2 master +' + +test_expect_success 'merge z into y fails and sets NOTES_MERGE_REF' ' + git config core.notesRef refs/notes/y && + test_must_fail git notes merge z && + echo "ref: refs/notes/y" >expect && + test_cmp .git/NOTES_MERGE_REF expect +' + +test_expect_success 'merge z into y while mid-merge in another workdir fails' ' + ( + cd worktree && + git config core.notesRef refs/notes/y && + test_must_fail git notes merge z 2>err && + grep "A notes merge into refs/notes/y is already in-progress at" err + ) && + test_path_is_missing .git/worktrees/worktree/NOTES_MERGE_REF +' + +test_expect_success 'merge z into x while mid-merge on y succeeds' ' + ( + cd worktree2 && + git config core.notesRef refs/notes/x && + test_must_fail git notes merge z 2>&1 >out && + grep "Automatic notes merge failed" out && + grep -v "A notes merge into refs/notes/x is already in-progress in" out + ) && + echo "ref: refs/notes/x" >expect && + test_cmp .git/worktrees/worktree2/NOTES_MERGE_REF expect +' + +test_done diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh index 5a27ec9b5e..8f64505e4f 100755 --- a/t/t3402-rebase-merge.sh +++ b/t/t3402-rebase-merge.sh @@ -47,7 +47,7 @@ test_expect_success setup ' ' test_expect_success 'reference merge' ' - git merge -s recursive "reference merge" HEAD master + git merge -s recursive -m "reference merge" master ' PRE_REBASE=$(git rev-parse test-rebase) diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 467e6c1ed5..544f9ad508 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -961,13 +961,13 @@ test_expect_success 'rebase -i produces readable reflog' ' 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 + rebase -i (pick): H + rebase -i (pick): G + rebase -i (start): checkout I EOF - tail -n 4 .git/logs/HEAD | - sed -e "s/.* //" >actual && + git reflog -n4 HEAD | + sed "s/[^:]*: //" >actual && test_cmp expect actual ' @@ -1006,6 +1006,22 @@ test_expect_success 'rebase -i with --strategy and -X' ' test $(cat file1) = Z ' +test_expect_success 'interrupted rebase -i with --strategy and -X' ' + git checkout -b conflict-merge-use-theirs-interrupted conflict-branch && + git reset --hard HEAD^ && + >breakpoint && + git add breakpoint && + git commit -m "breakpoint for interactive mode" && + echo five >conflict && + echo Z >file1 && + git commit -a -m "one file conflict" && + set_fake_editor && + FAKE_LINES="edit 1 2" git rebase -i --strategy=recursive -Xours conflict-branch && + git rebase --continue && + 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" && @@ -1123,4 +1139,154 @@ test_expect_success 'rebase --continue removes CHERRY_PICK_HEAD' ' test ! -f .git/CHERRY_PICK_HEAD ' +rebase_setup_and_clean () { + test_when_finished " + git checkout master && + test_might_fail git branch -D $1 && + test_might_fail git rebase --abort + " && + git checkout -b $1 master +} + +test_expect_success 'drop' ' + rebase_setup_and_clean drop-test && + set_fake_editor && + FAKE_LINES="1 drop 2 3 drop 4 5" git rebase -i --root && + test E = $(git cat-file commit HEAD | sed -ne \$p) && + test C = $(git cat-file commit HEAD^ | sed -ne \$p) && + test A = $(git cat-file commit HEAD^^ | sed -ne \$p) +' + +cat >expect <<EOF +Successfully rebased and updated refs/heads/missing-commit. +EOF + +test_expect_success 'rebase -i respects rebase.missingCommitsCheck = ignore' ' + test_config rebase.missingCommitsCheck ignore && + rebase_setup_and_clean missing-commit && + set_fake_editor && + FAKE_LINES="1 2 3 4" \ + git rebase -i --root 2>actual && + test D = $(git cat-file commit HEAD | sed -ne \$p) && + test_cmp expect actual +' + +cat >expect <<EOF +Warning: some commits may have been dropped accidentally. +Dropped commits (newer to older): + - $(git rev-list --pretty=oneline --abbrev-commit -1 master) +To avoid this message, use "drop" to explicitly remove a commit. + +Use 'git config rebase.missingCommitsCheck' to change the level of warnings. +The possible behaviours are: ignore, warn, error. + +Successfully rebased and updated refs/heads/missing-commit. +EOF + +test_expect_success 'rebase -i respects rebase.missingCommitsCheck = warn' ' + test_config rebase.missingCommitsCheck warn && + rebase_setup_and_clean missing-commit && + set_fake_editor && + FAKE_LINES="1 2 3 4" \ + git rebase -i --root 2>actual && + test_cmp expect actual && + test D = $(git cat-file commit HEAD | sed -ne \$p) +' + +cat >expect <<EOF +Warning: some commits may have been dropped accidentally. +Dropped commits (newer to older): + - $(git rev-list --pretty=oneline --abbrev-commit -1 master) + - $(git rev-list --pretty=oneline --abbrev-commit -1 master~2) +To avoid this message, use "drop" to explicitly remove a commit. + +Use 'git config rebase.missingCommitsCheck' to change the level of warnings. +The possible behaviours are: ignore, warn, error. + +You can fix this with 'git rebase --edit-todo'. +Or you can abort the rebase with 'git rebase --abort'. +EOF + +test_expect_success 'rebase -i respects rebase.missingCommitsCheck = error' ' + test_config rebase.missingCommitsCheck error && + rebase_setup_and_clean missing-commit && + set_fake_editor && + test_must_fail env FAKE_LINES="1 2 4" \ + git rebase -i --root 2>actual && + test_cmp expect actual && + cp .git/rebase-merge/git-rebase-todo.backup \ + .git/rebase-merge/git-rebase-todo && + FAKE_LINES="1 2 drop 3 4 drop 5" \ + git rebase --edit-todo && + git rebase --continue && + test D = $(git cat-file commit HEAD | sed -ne \$p) && + test B = $(git cat-file commit HEAD^ | sed -ne \$p) +' + +cat >expect <<EOF +Warning: the command isn't recognized in the following line: + - badcmd $(git rev-list --oneline -1 master~1) + +You can fix this with 'git rebase --edit-todo'. +Or you can abort the rebase with 'git rebase --abort'. +EOF + +test_expect_success 'static check of bad command' ' + rebase_setup_and_clean bad-cmd && + set_fake_editor && + test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \ + git rebase -i --root 2>actual && + test_cmp expect actual && + FAKE_LINES="1 2 3 drop 4 5" git rebase --edit-todo && + git rebase --continue && + test E = $(git cat-file commit HEAD | sed -ne \$p) && + test C = $(git cat-file commit HEAD^ | sed -ne \$p) +' + +test_expect_success 'tabs and spaces are accepted in the todolist' ' + rebase_setup_and_clean indented-comment && + write_script add-indent.sh <<-\EOF && + ( + # Turn single spaces into space/tab mix + sed "1s/ / /g; 2s/ / /g; 3s/ / /g" "$1" + printf "\n\t# comment\n #more\n\t # comment\n" + ) >"$1.new" + mv "$1.new" "$1" + EOF + test_set_editor "$(pwd)/add-indent.sh" && + git rebase -i HEAD^^^ && + test E = $(git cat-file commit HEAD | sed -ne \$p) +' + +cat >expect <<EOF +Warning: the SHA-1 is missing or isn't a commit in the following line: + - edit XXXXXXX False commit + +You can fix this with 'git rebase --edit-todo'. +Or you can abort the rebase with 'git rebase --abort'. +EOF + +test_expect_success 'static check of bad SHA-1' ' + rebase_setup_and_clean bad-sha && + set_fake_editor && + test_must_fail env FAKE_LINES="1 2 edit fakesha 3 4 5 #" \ + git rebase -i --root 2>actual && + test_cmp expect actual && + FAKE_LINES="1 2 4 5 6" git rebase --edit-todo && + git rebase --continue && + test E = $(git cat-file commit HEAD | sed -ne \$p) +' + +test_expect_success 'editor saves as CR/LF' ' + git checkout -b with-crlf && + write_script add-crs.sh <<-\EOF && + sed -e "s/\$/Q/" <"$1" | tr Q "\\015" >"$1".new && + mv -f "$1".new "$1" + EOF + ( + test_set_editor "$(pwd)/add-crs.sh" && + git rebase -i HEAD^ + ) +' + test_done diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh index 41370ab998..8f53e54ce4 100755 --- a/t/t3415-rebase-autosquash.sh +++ b/t/t3415-rebase-autosquash.sh @@ -250,4 +250,25 @@ test_expect_success 'squash! fixup!' ' test_auto_fixup_fixup squash fixup ' +test_expect_success 'autosquash with custom inst format' ' + git reset --hard base && + git config --add rebase.instructionFormat "[%an @ %ar] %s" && + echo 2 >file1 && + git add -u && + test_tick && + git commit -m "squash! $(git rev-parse --short HEAD^)" && + echo 1 >file1 && + git add -u && + test_tick && + git commit -m "squash! $(git log -n 1 --format=%s HEAD~2)" && + git tag final-squash-instFmt && + test_tick && + git rebase --autosquash -i HEAD~4 && + git log --oneline >actual && + test_line_count = 3 actual && + git diff --exit-code final-squash-instFmt && + test 1 = "$(git cat-file blob HEAD^:file1)" && + test 2 = $(git cat-file commit HEAD^ | grep squash | wc -l) +' + test_done diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index 2680375628..4428b9086e 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -40,6 +40,25 @@ test_expect_success 'non-interactive rebase --continue works with touched file' git rebase --continue ' +test_expect_success 'non-interactive rebase --continue with rerere enabled' ' + test_config rerere.enabled true && + test_when_finished "test_might_fail git rebase --abort" && + git reset --hard commit-new-file-F2-on-topic-branch && + git checkout master && + rm -fr .git/rebase-* && + + test_must_fail git rebase --onto master master topic && + echo "Resolved" >F2 && + git add F2 && + cp F2 F2.expected && + git rebase --continue && + + git reset --hard commit-new-file-F2-on-topic-branch && + git checkout master && + test_must_fail git rebase --onto master master topic && + test_cmp F2.expected F2 +' + test_expect_success 'rebase --continue can not be used with other options' ' test_must_fail git rebase -v --continue && test_must_fail git rebase --continue -v diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh index d783f03d3f..944154b2e0 100755 --- a/t/t3420-rebase-autostash.sh +++ b/t/t3420-rebase-autostash.sh @@ -37,6 +37,16 @@ testrebase() { type=$1 dotest=$2 + test_expect_success "rebase$type: dirty worktree, --no-autostash" ' + 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 && + test_when_finished git checkout feature-branch && + echo dirty >>file3 && + test_must_fail git rebase$type --no-autostash unrelated-onto-branch + ' + test_expect_success "rebase$type: dirty worktree, non-conflicting rebase" ' test_config rebase.autostash true && git reset --hard && diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 24ddd8a704..deae948c76 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -326,15 +326,34 @@ test_expect_success 'split hunk "add -p (edit)"' ' # 2. Correct version applies the (not)edited version, and asks # about the next hunk, against which we say q and program # exits. - for a in s e q n q q - do - echo $a - done | + printf "%s\n" s e q n q q | EDITOR=: git add -p && git diff >actual && ! grep "^+15" actual ' +test_expect_failure 'split hunk "add -p (no, yes, edit)"' ' + cat >test <<-\EOF && + 5 + 10 + 20 + 21 + 30 + 31 + 40 + 50 + 60 + EOF + git reset && + # test sequence is s(plit), n(o), y(es), e(dit) + # q n q q is there to make sure we exit at the end. + printf "%s\n" s n y e q n q q | + EDITOR=: git add -p 2>error && + test_must_be_empty error && + git diff >actual && + ! grep "^+31" actual +' + test_expect_success 'patch mode ignores unmerged entries' ' git reset --hard && test_commit conflict && diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh index 75cf3ff9bd..509084e1a7 100755 --- a/t/t3901-i18n-patch.sh +++ b/t/t3901-i18n-patch.sh @@ -251,4 +251,66 @@ test_expect_success 'rebase --merge (L/U)' ' check_encoding 2 8859 ' +test_expect_success 'am (U/U)' ' + # Apply UTF-8 patches with UTF-8 commitencoding + git config i18n.commitencoding UTF-8 && + . "$TEST_DIRECTORY"/t3901-utf8.txt && + + git reset --hard master && + git am out-u1 out-u2 && + + check_encoding 2 +' + +test_expect_success !MINGW 'am (L/L)' ' + # Apply ISO-8859-1 patches with ISO-8859-1 commitencoding + git config i18n.commitencoding ISO8859-1 && + . "$TEST_DIRECTORY"/t3901-8859-1.txt && + + git reset --hard master && + git am out-l1 out-l2 && + + check_encoding 2 8859 +' + +test_expect_success 'am (U/L)' ' + # Apply ISO-8859-1 patches with UTF-8 commitencoding + git config i18n.commitencoding UTF-8 && + . "$TEST_DIRECTORY"/t3901-utf8.txt && + git reset --hard master && + + # am specifies --utf8 by default. + git am out-l1 out-l2 && + + check_encoding 2 +' + +test_expect_success 'am --no-utf8 (U/L)' ' + # Apply ISO-8859-1 patches with UTF-8 commitencoding + git config i18n.commitencoding UTF-8 && + . "$TEST_DIRECTORY"/t3901-utf8.txt && + + git reset --hard master && + git am --no-utf8 out-l1 out-l2 2>err && + + # commit-tree will warn that the commit message does not contain valid UTF-8 + # as mailinfo did not convert it + grep "did not conform" err && + + check_encoding 2 +' + +test_expect_success !MINGW 'am (L/U)' ' + # Apply UTF-8 patches with ISO-8859-1 commitencoding + git config i18n.commitencoding ISO8859-1 && + . "$TEST_DIRECTORY"/t3901-8859-1.txt && + + git reset --hard master && + # mailinfo will re-code the commit message to the charset specified by + # i18n.commitencoding + git am out-u1 out-u2 && + + check_encoding 2 8859 +' + test_done diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index f5f18b7d21..2142c1fa92 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -672,7 +672,7 @@ test_expect_success 'store updates stash ref and reflog' ' ! 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 reflog --format=%H stash| grep $STASH_ID && git stash pop && grep quux bazzy ' diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh index 70655c1848..38e730090f 100755 --- a/t/t3904-stash-patch.sh +++ b/t/t3904-stash-patch.sh @@ -1,9 +1,15 @@ #!/bin/sh -test_description='git checkout --patch' +test_description='stash -p' . ./lib-patch-mode.sh -test_expect_success PERL 'setup' ' +if ! test_have_prereq PERL +then + skip_all='skipping stash -p tests, perl not available' + test_done +fi + +test_expect_success 'setup' ' mkdir dir && echo parent > dir/foo && echo dummy > bar && @@ -20,7 +26,7 @@ test_expect_success PERL 'setup' ' # note: order of files with unstaged changes: HEAD bar dir/foo -test_expect_success PERL 'saying "n" does nothing' ' +test_expect_success 'saying "n" does nothing' ' set_state HEAD HEADfile_work HEADfile_index && set_state dir/foo work index && (echo n; echo n; echo n) | test_must_fail git stash save -p && @@ -29,7 +35,7 @@ test_expect_success PERL 'saying "n" does nothing' ' verify_state dir/foo work index ' -test_expect_success PERL 'git stash -p' ' +test_expect_success 'git stash -p' ' (echo y; echo n; echo y) | git stash save -p && verify_state HEAD committed HEADfile_index && verify_saved_state bar && @@ -41,7 +47,7 @@ test_expect_success PERL 'git stash -p' ' verify_state dir/foo work head ' -test_expect_success PERL 'git stash -p --no-keep-index' ' +test_expect_success 'git stash -p --no-keep-index' ' set_state HEAD HEADfile_work HEADfile_index && set_state bar bar_work bar_index && set_state dir/foo work index && @@ -56,7 +62,7 @@ test_expect_success PERL 'git stash -p --no-keep-index' ' verify_state dir/foo work index ' -test_expect_success PERL 'git stash --no-keep-index -p' ' +test_expect_success 'git stash --no-keep-index -p' ' set_state HEAD HEADfile_work HEADfile_index && set_state bar bar_work bar_index && set_state dir/foo work index && @@ -71,8 +77,31 @@ test_expect_success PERL 'git stash --no-keep-index -p' ' verify_state dir/foo work index ' -test_expect_success PERL 'none of this moved HEAD' ' +test_expect_success 'none of this moved HEAD' ' verify_saved_head ' +test_expect_failure 'stash -p with split hunk' ' + git reset --hard && + cat >test <<-\EOF && + aaa + bbb + ccc + EOF + git add test && + git commit -m "initial" && + cat >test <<-\EOF && + aaa + added line 1 + bbb + added line 2 + ccc + EOF + printf "%s\n" s n y q | + test_might_fail git stash -p 2>error && + ! test_must_be_empty error && + grep "added line 1" test && + ! grep "added line 2" test +' + test_done diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 890db1174f..646c4750ec 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -1431,4 +1431,18 @@ test_expect_success 'cover letter auto user override' ' test_line_count = 2 list ' +test_expect_success 'format-patch --zero-commit' ' + git format-patch --zero-commit --stdout v2..v1 >patch2 && + grep "^From " patch2 | sort | uniq >actual && + echo "From $_z40 Mon Sep 17 00:00:00 2001" >expect && + test_cmp expect actual +' + +test_expect_success 'From line has expected format' ' + git format-patch --stdout v2..v1 >patch2 && + grep "^From " patch2 >from && + grep "^From $_x40 Mon Sep 17 00:00:00 2001$" patch2 >filtered && + test_cmp from filtered +' + test_done diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 604a838c1a..2434157aa7 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -9,138 +9,144 @@ test_description='Test special whitespace in diff engine. . ./test-lib.sh . "$TEST_DIRECTORY"/diff-lib.sh -# Ray Lehtiniemi's example +test_expect_success "Ray Lehtiniemi's example" ' + cat <<-\EOF >x && + do { + nothing; + } while (0); + EOF + git update-index --add x && -cat << EOF > x -do { - nothing; -} while (0); -EOF + cat <<-\EOF >x && + do + { + nothing; + } + while (0); + EOF + + cat <<-\EOF >expect && + diff --git a/x b/x + index adf3937..6edc172 100644 + --- a/x + +++ b/x + @@ -1,3 +1,5 @@ + -do { + +do + +{ + nothing; + -} while (0); + +} + +while (0); + EOF -git update-index --add x + git diff >out && + test_cmp expect out && -cat << EOF > x -do -{ - nothing; -} -while (0); -EOF + git diff -w >out && + test_cmp expect out && -cat << EOF > expect -diff --git a/x b/x -index adf3937..6edc172 100644 ---- a/x -+++ b/x -@@ -1,3 +1,5 @@ --do { -+do -+{ - nothing; --} while (0); -+} -+while (0); -EOF + git diff -b >out && + test_cmp expect out +' -git diff > out -test_expect_success "Ray's example without options" 'test_cmp expect out' +test_expect_success 'another test, without options' ' + tr Q "\015" <<-\EOF >x && + whitespace at beginning + whitespace change + whitespace in the middle + whitespace at end + unchanged line + CR at endQ + EOF -git diff -w > out -test_expect_success "Ray's example with -w" 'test_cmp expect out' + git update-index x && -git diff -b > out -test_expect_success "Ray's example with -b" 'test_cmp expect out' + tr "_" " " <<-\EOF >x && + _ whitespace at beginning + whitespace change + white space in the middle + whitespace at end__ + unchanged line + CR at end + EOF -tr 'Q' '\015' << EOF > x -whitespace at beginning -whitespace change -whitespace in the middle -whitespace at end -unchanged line -CR at endQ -EOF + tr "Q_" "\015 " <<-\EOF >expect && + diff --git a/x b/x + index d99af23..22d9f73 100644 + --- a/x + +++ b/x + @@ -1,6 +1,6 @@ + -whitespace at beginning + -whitespace change + -whitespace in the middle + -whitespace at end + + whitespace at beginning + +whitespace change + +white space in the middle + +whitespace at end__ + unchanged line + -CR at endQ + +CR at end + EOF -git update-index x + git diff >out && + test_cmp expect out && -tr '_' ' ' << EOF > x - whitespace at beginning -whitespace change -white space in the middle -whitespace at end__ -unchanged line -CR at end -EOF + >expect && + git diff -w >out && + test_cmp expect out && -tr 'Q_' '\015 ' << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 ---- a/x -+++ b/x -@@ -1,6 +1,6 @@ --whitespace at beginning --whitespace change --whitespace in the middle --whitespace at end -+ whitespace at beginning -+whitespace change -+white space in the middle -+whitespace at end__ - unchanged line --CR at endQ -+CR at end -EOF -git diff > out -test_expect_success 'another test, without options' 'test_cmp expect out' + git diff -w -b >out && + test_cmp expect out && -cat << EOF > expect -EOF -git diff -w > out -test_expect_success 'another test, with -w' 'test_cmp expect out' -git diff -w -b > out -test_expect_success 'another test, with -w -b' 'test_cmp expect out' -git diff -w --ignore-space-at-eol > out -test_expect_success 'another test, with -w --ignore-space-at-eol' 'test_cmp expect out' -git diff -w -b --ignore-space-at-eol > out -test_expect_success 'another test, with -w -b --ignore-space-at-eol' 'test_cmp expect out' - -tr 'Q_' '\015 ' << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 ---- a/x -+++ b/x -@@ -1,6 +1,6 @@ --whitespace at beginning -+ whitespace at beginning - whitespace change --whitespace in the middle -+white space in the middle - whitespace at end__ - unchanged line - CR at end -EOF -git diff -b > out -test_expect_success 'another test, with -b' 'test_cmp expect out' -git diff -b --ignore-space-at-eol > out -test_expect_success 'another test, with -b --ignore-space-at-eol' 'test_cmp expect out' - -tr 'Q_' '\015 ' << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 ---- a/x -+++ b/x -@@ -1,6 +1,6 @@ --whitespace at beginning --whitespace change --whitespace in the middle -+ whitespace at beginning -+whitespace change -+white space in the middle - whitespace at end__ - unchanged line - CR at end -EOF -git diff --ignore-space-at-eol > out -test_expect_success 'another test, with --ignore-space-at-eol' 'test_cmp expect out' + git diff -w --ignore-space-at-eol >out && + test_cmp expect out && + + git diff -w -b --ignore-space-at-eol >out && + test_cmp expect out && + + + tr "Q_" "\015 " <<-\EOF >expect && + diff --git a/x b/x + index d99af23..22d9f73 100644 + --- a/x + +++ b/x + @@ -1,6 +1,6 @@ + -whitespace at beginning + +_ whitespace at beginning + whitespace change + -whitespace in the middle + +white space in the middle + whitespace at end__ + unchanged line + CR at end + EOF + git diff -b >out && + test_cmp expect out && + + git diff -b --ignore-space-at-eol >out && + test_cmp expect out && + + tr "Q_" "\015 " <<-\EOF >expect && + diff --git a/x b/x + index d99af23..22d9f73 100644 + --- a/x + +++ b/x + @@ -1,6 +1,6 @@ + -whitespace at beginning + -whitespace change + -whitespace in the middle + +_ whitespace at beginning + +whitespace change + +white space in the middle + whitespace at end__ + unchanged line + CR at end + EOF + git diff --ignore-space-at-eol >out && + test_cmp expect out +' test_expect_success 'ignore-blank-lines: only new lines' ' test_seq 5 >x && @@ -489,291 +495,219 @@ test_expect_success 'ignore-blank-lines: mix changes and blank lines' ' ' test_expect_success 'check mixed spaces and tabs in indent' ' - # This is indented with SP HT SP. - echo " foo();" > x && + echo " foo();" >x && git diff --check | grep "space before tab in indent" - ' test_expect_success 'check mixed tabs and spaces in indent' ' - # This is indented with HT SP HT. - echo " foo();" > x && + echo " foo();" >x && git diff --check | grep "space before tab in indent" - ' test_expect_success 'check with no whitespace errors' ' - git commit -m "snapshot" && - echo "foo();" > x && + echo "foo();" >x && git diff --check - ' test_expect_success 'check with trailing whitespace' ' - - echo "foo(); " > x && + echo "foo(); " >x && test_must_fail git diff --check - ' test_expect_success 'check with space before tab in indent' ' - # indent has space followed by hard tab - echo " foo();" > x && + echo " foo();" >x && test_must_fail git diff --check - ' test_expect_success '--check and --exit-code are not exclusive' ' - git checkout x && git diff --check --exit-code - ' test_expect_success '--check and --quiet are not exclusive' ' - git diff --check --quiet - ' test_expect_success 'check staged with no whitespace errors' ' - - echo "foo();" > x && + echo "foo();" >x && git add x && git diff --cached --check - ' test_expect_success 'check staged with trailing whitespace' ' - - echo "foo(); " > x && + echo "foo(); " >x && git add x && test_must_fail git diff --cached --check - ' test_expect_success 'check staged with space before tab in indent' ' - # indent has space followed by hard tab - echo " foo();" > x && + echo " foo();" >x && git add x && test_must_fail git diff --cached --check - ' test_expect_success 'check with no whitespace errors (diff-index)' ' - - echo "foo();" > x && + echo "foo();" >x && git add x && git diff-index --check HEAD - ' test_expect_success 'check with trailing whitespace (diff-index)' ' - - echo "foo(); " > x && + echo "foo(); " >x && git add x && test_must_fail git diff-index --check HEAD - ' test_expect_success 'check with space before tab in indent (diff-index)' ' - # indent has space followed by hard tab - echo " foo();" > x && + echo " foo();" >x && git add x && test_must_fail git diff-index --check HEAD - ' test_expect_success 'check staged with no whitespace errors (diff-index)' ' - - echo "foo();" > x && + echo "foo();" >x && git add x && git diff-index --cached --check HEAD - ' test_expect_success 'check staged with trailing whitespace (diff-index)' ' - - echo "foo(); " > x && + echo "foo(); " >x && git add x && test_must_fail git diff-index --cached --check HEAD - ' test_expect_success 'check staged with space before tab in indent (diff-index)' ' - # indent has space followed by hard tab - echo " foo();" > x && + echo " foo();" >x && git add x && test_must_fail git diff-index --cached --check HEAD - ' test_expect_success 'check with no whitespace errors (diff-tree)' ' - - echo "foo();" > x && + echo "foo();" >x && git commit -m "new commit" x && git diff-tree --check HEAD^ HEAD - ' test_expect_success 'check with trailing whitespace (diff-tree)' ' - - echo "foo(); " > x && + echo "foo(); " >x && git commit -m "another commit" x && test_must_fail git diff-tree --check HEAD^ HEAD - ' test_expect_success 'check with space before tab in indent (diff-tree)' ' - # indent has space followed by hard tab - echo " foo();" > x && + echo " foo();" >x && git commit -m "yet another" x && test_must_fail git diff-tree --check HEAD^ HEAD - ' test_expect_success 'check trailing whitespace (trailing-space: off)' ' - git config core.whitespace "-trailing-space" && - echo "foo (); " > x && + echo "foo (); " >x && git diff --check - ' test_expect_success 'check trailing whitespace (trailing-space: on)' ' - git config core.whitespace "trailing-space" && - echo "foo (); " > x && + echo "foo (); " >x && test_must_fail git diff --check - ' test_expect_success 'check space before tab in indent (space-before-tab: off)' ' - # indent contains space followed by HT git config core.whitespace "-space-before-tab" && - echo " foo ();" > x && + echo " foo ();" >x && git diff --check - ' test_expect_success 'check space before tab in indent (space-before-tab: on)' ' - # indent contains space followed by HT git config core.whitespace "space-before-tab" && - echo " foo (); " > x && + echo " foo (); " >x && test_must_fail git diff --check - ' test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' ' - git config core.whitespace "-indent-with-non-tab" && - echo " foo ();" > x && + echo " foo ();" >x && git diff --check - ' test_expect_success 'check spaces as indentation (indent-with-non-tab: on)' ' - git config core.whitespace "indent-with-non-tab" && - echo " foo ();" > x && + echo " foo ();" >x && test_must_fail git diff --check - ' test_expect_success 'ditto, but tabwidth=9' ' - git config core.whitespace "indent-with-non-tab,tabwidth=9" && git diff --check - ' test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab: on)' ' - git config core.whitespace "indent-with-non-tab" && - echo " foo ();" > x && + echo " foo ();" >x && test_must_fail git diff --check - ' test_expect_success 'ditto, but tabwidth=10' ' - git config core.whitespace "indent-with-non-tab,tabwidth=10" && test_must_fail git diff --check - ' test_expect_success 'ditto, but tabwidth=20' ' - git config core.whitespace "indent-with-non-tab,tabwidth=20" && git diff --check - ' test_expect_success 'check tabs as indentation (tab-in-indent: off)' ' - git config core.whitespace "-tab-in-indent" && - echo " foo ();" > x && + echo " foo ();" >x && git diff --check - ' test_expect_success 'check tabs as indentation (tab-in-indent: on)' ' - git config core.whitespace "tab-in-indent" && - echo " foo ();" > x && + echo " foo ();" >x && test_must_fail git diff --check - ' test_expect_success 'check tabs and spaces as indentation (tab-in-indent: on)' ' - git config core.whitespace "tab-in-indent" && - echo " foo ();" > x && + echo " foo ();" >x && test_must_fail git diff --check - ' test_expect_success 'ditto, but tabwidth=1 (must be irrelevant)' ' - git config core.whitespace "tab-in-indent,tabwidth=1" && test_must_fail git diff --check - ' test_expect_success 'check tab-in-indent and indent-with-non-tab conflict' ' - git config core.whitespace "tab-in-indent,indent-with-non-tab" && - echo "foo ();" > x && + echo "foo ();" >x && test_must_fail git diff --check - ' test_expect_success 'check tab-in-indent excluded from wildcard whitespace attribute' ' - git config --unset core.whitespace && - echo "x whitespace" > .gitattributes && - echo " foo ();" > x && + echo "x whitespace" >.gitattributes && + echo " foo ();" >x && git diff --check && rm -f .gitattributes - ' test_expect_success 'line numbers in --check output are correct' ' - - echo "" > x && - echo "foo(); " >> x && + echo "" >x && + echo "foo(); " >>x && git diff --check | grep "x:2:" - ' test_expect_success 'checkdiff detects new trailing blank lines (1)' ' @@ -876,29 +810,127 @@ test_expect_success 'setup diff colors' ' git config color.diff.old red && git config color.diff.new green && git config color.diff.commit yellow && - git config color.diff.whitespace "normal red" && + git config color.diff.whitespace blue && git config core.autocrlf false ' -cat >expected <<\EOF -<BOLD>diff --git a/x b/x<RESET> -<BOLD>index 9daeafb..2874b91 100644<RESET> -<BOLD>--- a/x<RESET> -<BOLD>+++ b/x<RESET> -<CYAN>@@ -1 +1,4 @@<RESET> - test<RESET> -<GREEN>+<RESET><GREEN>{<RESET> -<GREEN>+<RESET><BRED> <RESET> -<GREEN>+<RESET><GREEN>}<RESET> -EOF test_expect_success 'diff that introduces a line with only tabs' ' git config core.whitespace blank-at-eol && git reset --hard && - echo "test" > x && + echo "test" >x && git commit -m "initial" x && - echo "{NTN}" | tr "NT" "\n\t" >> x && + echo "{NTN}" | tr "NT" "\n\t" >>x && git -c color.diff=always diff | test_decode_color >current && + + cat >expected <<-\EOF && + <BOLD>diff --git a/x b/x<RESET> + <BOLD>index 9daeafb..2874b91 100644<RESET> + <BOLD>--- a/x<RESET> + <BOLD>+++ b/x<RESET> + <CYAN>@@ -1 +1,4 @@<RESET> + test<RESET> + <GREEN>+<RESET><GREEN>{<RESET> + <GREEN>+<RESET><BLUE> <RESET> + <GREEN>+<RESET><GREEN>}<RESET> + EOF + + test_cmp expected current +' + +test_expect_success 'diff that introduces and removes ws breakages' ' + git reset --hard && + { + echo "0. blank-at-eol " && + echo "1. blank-at-eol " + } >x && + git commit -a --allow-empty -m preimage && + { + echo "0. blank-at-eol " && + echo "1. still-blank-at-eol " && + echo "2. and a new line " + } >x && + + git -c color.diff=always diff | + test_decode_color >current && + + cat >expected <<-\EOF && + <BOLD>diff --git a/x b/x<RESET> + <BOLD>index d0233a2..700886e 100644<RESET> + <BOLD>--- a/x<RESET> + <BOLD>+++ b/x<RESET> + <CYAN>@@ -1,2 +1,3 @@<RESET> + 0. blank-at-eol <RESET> + <RED>-1. blank-at-eol <RESET> + <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET> + <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET> + EOF + + test_cmp expected current +' + +test_expect_success 'the same with --ws-error-highlight' ' + git reset --hard && + { + echo "0. blank-at-eol " && + echo "1. blank-at-eol " + } >x && + git commit -a --allow-empty -m preimage && + { + echo "0. blank-at-eol " && + echo "1. still-blank-at-eol " && + echo "2. and a new line " + } >x && + + git -c color.diff=always diff --ws-error-highlight=default,old | + test_decode_color >current && + + cat >expected <<-\EOF && + <BOLD>diff --git a/x b/x<RESET> + <BOLD>index d0233a2..700886e 100644<RESET> + <BOLD>--- a/x<RESET> + <BOLD>+++ b/x<RESET> + <CYAN>@@ -1,2 +1,3 @@<RESET> + 0. blank-at-eol <RESET> + <RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET> + <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET> + <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET> + EOF + + test_cmp expected current && + + git -c color.diff=always diff --ws-error-highlight=all | + test_decode_color >current && + + cat >expected <<-\EOF && + <BOLD>diff --git a/x b/x<RESET> + <BOLD>index d0233a2..700886e 100644<RESET> + <BOLD>--- a/x<RESET> + <BOLD>+++ b/x<RESET> + <CYAN>@@ -1,2 +1,3 @@<RESET> + <RESET>0. blank-at-eol<RESET><BLUE> <RESET> + <RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET> + <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET> + <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET> + EOF + + test_cmp expected current && + + git -c color.diff=always diff --ws-error-highlight=none | + test_decode_color >current && + + cat >expected <<-\EOF && + <BOLD>diff --git a/x b/x<RESET> + <BOLD>index d0233a2..700886e 100644<RESET> + <BOLD>--- a/x<RESET> + <BOLD>+++ b/x<RESET> + <CYAN>@@ -1,2 +1,3 @@<RESET> + 0. blank-at-eol <RESET> + <RED>-1. blank-at-eol <RESET> + <GREEN>+1. still-blank-at-eol <RESET> + <GREEN>+2. and a new line <RESET> + EOF + test_cmp expected current ' diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 1dbaa3864a..67373dc44e 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -31,6 +31,7 @@ diffpatterns=" cpp csharp fortran + fountain html java matlab diff --git a/t/t4018/fountain-scene b/t/t4018/fountain-scene new file mode 100644 index 0000000000..6b3257d680 --- /dev/null +++ b/t/t4018/fountain-scene @@ -0,0 +1,4 @@ +EXT. STREET RIGHT OUTSIDE - DAY + +CHARACTER +You didn't say the magic phrase, "ChangeMe". diff --git a/t/t4056-diff-order.sh b/t/t4056-diff-order.sh index c0460bb0e5..43dd474a12 100755 --- a/t/t4056-diff-order.sh +++ b/t/t4056-diff-order.sh @@ -68,6 +68,12 @@ test_expect_success POSIXPERM,SANITY 'unreadable orderfile' ' test_must_fail git diff -Ounreadable_file --name-only HEAD^..HEAD ' +test_expect_success "orderfile using option from subdir with --output" ' + mkdir subdir && + git -C subdir diff -O../order_file_1 --output ../actual --name-only HEAD^..HEAD && + test_cmp expect_1 actual +' + for i in 1 2 do test_expect_success "orderfile using option ($i)" ' diff --git a/t/t4136-apply-check.sh b/t/t4136-apply-check.sh index a321f7c245..4b0a374b63 100755 --- a/t/t4136-apply-check.sh +++ b/t/t4136-apply-check.sh @@ -16,4 +16,17 @@ test_expect_success 'apply --check exits non-zero with unrecognized input' ' EOF ' +test_expect_success 'apply exits non-zero with no-op patch' ' + cat >input <<-\EOF && + diff --get a/1 b/1 + index 6696ea4..606eddd 100644 + --- a/1 + +++ b/1 + @@ -1,1 +1,1 @@ + 1 + EOF + test_must_fail git apply --stat input && + test_must_fail git apply --check input +' + test_done diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 306e6f39ac..b41bd17264 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -67,6 +67,19 @@ test_expect_success 'setup: messages' ' EOF + cat >scissors-msg <<-\EOF && + Test git-am with scissors line + + This line should be included in the commit message. + EOF + + cat - scissors-msg >no-scissors-msg <<-\EOF && + This line should not be included in the commit message with --scissors enabled. + + - - >8 - - remove everything above this line - - >8 - - + + EOF + signoff="Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" ' @@ -104,6 +117,52 @@ test_expect_success setup ' echo "X-Fake-Field: Line Three" && git format-patch --stdout first | sed -e "1d" } > patch1-ws.eml && + { + sed -ne "1p" msg && + echo && + echo "From: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>" && + echo "Date: $GIT_AUTHOR_DATE" && + echo && + sed -e "1,2d" msg && + echo && + echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" && + echo "---" && + git diff-tree --no-commit-id --stat -p second + } >patch1-stgit.eml && + mkdir stgit-series && + cp patch1-stgit.eml stgit-series/patch && + { + echo "# This series applies on GIT commit $(git rev-parse first)" && + echo "patch" + } >stgit-series/series && + { + echo "# HG changeset patch" && + echo "# User $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>" && + echo "# Date $test_tick 25200" && + echo "# $(git show --pretty="%aD" -s second)" && + echo "# Node ID $_z40" && + echo "# Parent $_z40" && + cat msg && + echo && + echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" && + echo && + git diff-tree --no-commit-id -p second + } >patch1-hg.eml && + + + echo scissors-file >scissors-file && + git add scissors-file && + git commit -F scissors-msg && + git tag scissors && + git format-patch --stdout scissors^ >scissors-patch.eml && + git reset --hard HEAD^ && + + echo no-scissors-file >no-scissors-file && + git add no-scissors-file && + git commit -F no-scissors-msg && + git tag no-scissors && + git format-patch --stdout no-scissors^ >no-scissors-patch.eml && + git reset --hard HEAD^ && sed -n -e "3,\$p" msg >file && git add file && @@ -154,6 +213,18 @@ test_expect_success 'am applies patch correctly' ' test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)" ' +test_expect_success 'am fails if index is dirty' ' + test_when_finished "rm -f dirtyfile" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + echo dirtyfile >dirtyfile && + git add dirtyfile && + test_must_fail git am patch1 && + test_path_is_dir .git/rebase-apply && + test_cmp_rev first HEAD +' + test_expect_success 'am applies patch e-mail not in a mbox' ' rm -fr .git/rebase-apply && git reset --hard && @@ -187,6 +258,183 @@ test_expect_success 'am applies patch e-mail with preceding whitespace' ' test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)" ' +test_expect_success 'am applies stgit patch' ' + rm -fr .git/rebase-apply && + git checkout -f first && + git am patch1-stgit.eml && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + test_cmp_rev second^ HEAD^ +' + +test_expect_success 'am --patch-format=stgit applies stgit patch' ' + rm -fr .git/rebase-apply && + git checkout -f first && + git am --patch-format=stgit <patch1-stgit.eml && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + test_cmp_rev second^ HEAD^ +' + +test_expect_success 'am applies stgit series' ' + rm -fr .git/rebase-apply && + git checkout -f first && + git am stgit-series/series && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + test_cmp_rev second^ HEAD^ +' + +test_expect_success 'am applies hg patch' ' + rm -fr .git/rebase-apply && + git checkout -f first && + git am patch1-hg.eml && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + test_cmp_rev second^ HEAD^ +' + +test_expect_success 'am --patch-format=hg applies hg patch' ' + rm -fr .git/rebase-apply && + git checkout -f first && + git am --patch-format=hg <patch1-hg.eml && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + test_cmp_rev second^ HEAD^ +' + +test_expect_success 'am with applypatch-msg hook' ' + test_when_finished "rm -f .git/hooks/applypatch-msg" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + mkdir -p .git/hooks && + write_script .git/hooks/applypatch-msg <<-\EOF && + cat "$1" >actual-msg && + echo hook-message >"$1" + EOF + git am patch1 && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + echo hook-message >expected && + git log -1 --format=format:%B >actual && + test_cmp expected actual && + git log -1 --format=format:%B second >expected && + test_cmp expected actual-msg +' + +test_expect_success 'am with failing applypatch-msg hook' ' + test_when_finished "rm -f .git/hooks/applypatch-msg" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + mkdir -p .git/hooks && + write_script .git/hooks/applypatch-msg <<-\EOF && + exit 1 + EOF + test_must_fail git am patch1 && + test_path_is_dir .git/rebase-apply && + git diff --exit-code first && + test_cmp_rev first HEAD +' + +test_expect_success 'am with pre-applypatch hook' ' + test_when_finished "rm -f .git/hooks/pre-applypatch" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + mkdir -p .git/hooks && + write_script .git/hooks/pre-applypatch <<-\EOF && + git diff first >diff.actual + exit 0 + EOF + git am patch1 && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + git diff first..second >diff.expected && + test_cmp diff.expected diff.actual +' + +test_expect_success 'am with failing pre-applypatch hook' ' + test_when_finished "rm -f .git/hooks/pre-applypatch" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + mkdir -p .git/hooks && + write_script .git/hooks/pre-applypatch <<-\EOF && + exit 1 + EOF + test_must_fail git am patch1 && + test_path_is_dir .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev first HEAD +' + +test_expect_success 'am with post-applypatch hook' ' + test_when_finished "rm -f .git/hooks/post-applypatch" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + mkdir -p .git/hooks && + write_script .git/hooks/post-applypatch <<-\EOF && + git rev-parse HEAD >head.actual + git diff second >diff.actual + exit 0 + EOF + git am patch1 && + test_path_is_missing .git/rebase-apply && + test_cmp_rev second HEAD && + git rev-parse second >head.expected && + test_cmp head.expected head.actual && + git diff second >diff.expected && + test_cmp diff.expected diff.actual +' + +test_expect_success 'am with failing post-applypatch hook' ' + test_when_finished "rm -f .git/hooks/post-applypatch" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + mkdir -p .git/hooks && + write_script .git/hooks/post-applypatch <<-\EOF && + git rev-parse HEAD >head.actual + exit 1 + EOF + git am patch1 && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + git rev-parse second >head.expected && + test_cmp head.expected head.actual +' + +test_expect_success 'am --scissors cuts the message at the scissors line' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout second && + git am --scissors scissors-patch.eml && + test_path_is_missing .git/rebase-apply && + git diff --exit-code scissors && + test_cmp_rev scissors HEAD +' + +test_expect_success 'am --no-scissors overrides mailinfo.scissors' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout second && + test_config mailinfo.scissors true && + git am --no-scissors no-scissors-patch.eml && + test_path_is_missing .git/rebase-apply && + git diff --exit-code no-scissors && + test_cmp_rev no-scissors HEAD +' + test_expect_success 'setup: new author and committer' ' GIT_AUTHOR_NAME="Another Thor" && GIT_AUTHOR_EMAIL="a.thor@example.com" && @@ -274,15 +522,21 @@ test_expect_success 'am --keep-non-patch really keeps the non-patch part' ' grep "^\[foo\] third" actual ' -test_expect_success 'am -3 falls back to 3-way merge' ' +test_expect_success 'setup am -3' ' rm -fr .git/rebase-apply && git reset --hard && - git checkout -b lorem2 master2 && + git checkout -b base3way master2 && sed -n -e "3,\$p" msg >file && head -n 9 msg >>file && git add file && test_tick && - git commit -m "copied stuff" && + git commit -m "copied stuff" +' + +test_expect_success 'am -3 falls back to 3-way merge' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout -b lorem2 base3way && git am -3 lorem-move.patch && test_path_is_missing .git/rebase-apply && git diff --exit-code lorem @@ -291,17 +545,31 @@ test_expect_success 'am -3 falls back to 3-way merge' ' test_expect_success 'am -3 -p0 can read --no-prefix patch' ' rm -fr .git/rebase-apply && git reset --hard && - git checkout -b lorem3 master2 && - sed -n -e "3,\$p" msg >file && - head -n 9 msg >>file && - git add file && - test_tick && - git commit -m "copied stuff" && + git checkout -b lorem3 base3way && git am -3 -p0 lorem-zero.patch && test_path_is_missing .git/rebase-apply && git diff --exit-code lorem ' +test_expect_success 'am with config am.threeWay falls back to 3-way merge' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout -b lorem4 base3way && + test_config am.threeWay 1 && + git am lorem-move.patch && + test_path_is_missing .git/rebase-apply && + git diff --exit-code lorem +' + +test_expect_success 'am with config am.threeWay overridden by --no-3way' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout -b lorem5 base3way && + test_config am.threeWay 1 && + test_must_fail git am --no-3way lorem-move.patch && + test_path_is_dir .git/rebase-apply +' + test_expect_success 'am can rename a file' ' grep "^rename from" rename.patch && rm -fr .git/rebase-apply && @@ -338,12 +606,7 @@ test_expect_success 'am -3 can rename a file after falling back to 3-way merge' test_expect_success 'am -3 -q is quiet' ' rm -fr .git/rebase-apply && git checkout -f lorem2 && - git reset master2 --hard && - sed -n -e "3,\$p" msg >file && - head -n 9 msg >>file && - git add file && - test_tick && - git commit -m "copied stuff" && + git reset base3way --hard && git am -3 -q lorem-move.patch >output.out 2>&1 && ! test -s output.out ' @@ -370,6 +633,20 @@ test_expect_success 'am --abort removes a stray directory' ' test_path_is_missing .git/rebase-apply ' +test_expect_success 'am refuses patches when paused' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout lorem2^^ && + + test_must_fail git am lorem-move.patch && + test_path_is_dir .git/rebase-apply && + test_cmp_rev lorem2^^ HEAD && + + test_must_fail git am <lorem-move.patch && + test_path_is_dir .git/rebase-apply && + test_cmp_rev lorem2^^ HEAD +' + test_expect_success 'am --resolved works' ' echo goodbye >expected && rm -fr .git/rebase-apply && @@ -384,6 +661,31 @@ test_expect_success 'am --resolved works' ' test_cmp expected another ' +test_expect_success 'am --resolved fails if index has no changes' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout lorem2^^ && + test_must_fail git am lorem-move.patch && + test_path_is_dir .git/rebase-apply && + test_cmp_rev lorem2^^ HEAD && + test_must_fail git am --resolved && + test_path_is_dir .git/rebase-apply && + test_cmp_rev lorem2^^ HEAD +' + +test_expect_success 'am --resolved fails if index has unmerged entries' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout second && + test_must_fail git am -3 lorem-move.patch && + test_path_is_dir .git/rebase-apply && + test_cmp_rev second HEAD && + test_must_fail git am --resolved >err && + test_path_is_dir .git/rebase-apply && + test_cmp_rev second HEAD && + test_i18ngrep "still have unmerged paths" err +' + test_expect_success 'am takes patches from a Pine mailbox' ' rm -fr .git/rebase-apply && git reset --hard && @@ -548,6 +850,18 @@ test_expect_success 'am --message-id really adds the message id' ' test_cmp expected actual ' +test_expect_success 'am.messageid really adds the message id' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout HEAD^ && + test_config am.messageid true && + git am patch1.eml && + test_path_is_missing .git/rebase-apply && + git cat-file commit HEAD | tail -n1 >actual && + grep Message-Id patch1.eml >expected && + test_cmp expected actual +' + test_expect_success 'am --message-id -s signs off after the message id' ' rm -fr .git/rebase-apply && git reset --hard && @@ -559,4 +873,88 @@ test_expect_success 'am --message-id -s signs off after the message id' ' test_cmp expected actual ' +test_expect_success 'am -3 works with rerere' ' + rm -fr .git/rebase-apply && + git reset --hard && + + # make patches one->two and two->three... + test_commit one file && + test_commit two file && + test_commit three file && + git format-patch -2 --stdout >seq.patch && + + # and create a situation that conflicts... + git reset --hard one && + test_commit other file && + + # enable rerere... + test_config rerere.enabled true && + test_when_finished "rm -rf .git/rr-cache" && + + # ...and apply. Our resolution is to skip the first + # patch, and the rerere the second one. + test_must_fail git am -3 seq.patch && + test_must_fail git am --skip && + echo resolved >file && + git add file && + git am --resolved && + + # now apply again, and confirm that rerere engaged (we still + # expect failure from am because rerere does not auto-commit + # for us). + git reset --hard other && + test_must_fail git am -3 seq.patch && + test_must_fail git am --skip && + echo resolved >expect && + test_cmp expect file +' + +test_expect_success 'am -s unexpected trailer block' ' + rm -fr .git/rebase-apply && + git reset --hard && + echo signed >file && + git add file && + cat >msg <<-EOF && + subject here + + Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> + [jc: tweaked log message] + Signed-off-by: J C H <j@c.h> + EOF + git commit -F msg && + git cat-file commit HEAD | sed -e '1,/^$/d' >original && + git format-patch --stdout -1 >patch && + + git reset --hard HEAD^ && + git am -s patch && + ( + cat original && + echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" + ) >expect && + git cat-file commit HEAD | sed -e '1,/^$/d' >actual && + test_cmp expect actual && + + cat >msg <<-\EOF && + subject here + + We make sure that there is a blank line between the log + message proper and Signed-off-by: line added. + EOF + git reset HEAD^ && + git commit -F msg file && + git cat-file commit HEAD | sed -e '1,/^$/d' >original && + git format-patch --stdout -1 >patch && + + git reset --hard HEAD^ && + git am -s patch && + + ( + cat original && + echo && + echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" + ) >expect && + git cat-file commit HEAD | sed -e '1,/^$/d' >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh index 833e7b2cea..ea5ace99a1 100755 --- a/t/t4151-am-abort.sh +++ b/t/t4151-am-abort.sh @@ -95,6 +95,21 @@ test_expect_success 'am --abort will keep the local commits intact' ' test_cmp expect actual ' +test_expect_success 'am --abort will keep dirty index intact' ' + git reset --hard initial && + echo dirtyfile >dirtyfile && + cp dirtyfile dirtyfile.expected && + git add dirtyfile && + test_must_fail git am 0001-*.patch && + test_cmp_rev initial HEAD && + test_path_is_file dirtyfile && + test_cmp dirtyfile.expected dirtyfile && + git am --abort && + test_cmp_rev initial HEAD && + test_path_is_file dirtyfile && + test_cmp dirtyfile.expected dirtyfile +' + test_expect_success 'am -3 stops on conflict on unborn branch' ' git checkout -f --orphan orphan && git reset && @@ -153,4 +168,28 @@ test_expect_success 'am --abort on unborn branch will keep local commits intact' test_cmp expect actual ' +test_expect_success 'am --skip leaves index stat info alone' ' + git checkout -f --orphan skip-stat-info && + git reset && + test_commit skip-should-be-untouched && + test-chmtime =0 skip-should-be-untouched.t && + git update-index --refresh && + git diff-files --exit-code --quiet && + test_must_fail git am 0001-*.patch && + git am --skip && + git diff-files --exit-code --quiet +' + +test_expect_success 'am --abort leaves index stat info alone' ' + git checkout -f --orphan abort-stat-info && + git reset && + test_commit abort-should-be-untouched && + test-chmtime =0 abort-should-be-untouched.t && + git update-index --refresh && + git diff-files --exit-code --quiet && + test_must_fail git am 0001-*.patch && + git am --abort && + git diff-files --exit-code --quiet +' + test_done diff --git a/t/t4153-am-resume-override-opts.sh b/t/t4153-am-resume-override-opts.sh new file mode 100755 index 0000000000..7c013d84d5 --- /dev/null +++ b/t/t4153-am-resume-override-opts.sh @@ -0,0 +1,102 @@ +#!/bin/sh + +test_description='git-am command-line options override saved options' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh + +format_patch () { + git format-patch --stdout -1 "$1" >"$1".eml +} + +test_expect_success 'setup' ' + test_commit initial file && + test_commit first file && + + git checkout initial && + git mv file file2 && + test_tick && + git commit -m renamed-file && + git tag renamed-file && + + git checkout -b side initial && + test_commit side1 file && + test_commit side2 file && + + format_patch side1 && + format_patch side2 +' + +test_expect_success TTY '--3way overrides --no-3way' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout renamed-file && + + # Applying side1 will fail as the file has been renamed. + test_must_fail git am --no-3way side[12].eml && + test_path_is_dir .git/rebase-apply && + test_cmp_rev renamed-file HEAD && + test -z "$(git ls-files -u)" && + + # Applying side1 with am --3way will succeed due to the threeway-merge. + # Applying side2 will fail as --3way does not apply to it. + test_must_fail test_terminal git am --3way </dev/zero && + test_path_is_dir .git/rebase-apply && + test side1 = "$(cat file2)" +' + +test_expect_success '--no-quiet overrides --quiet' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + + # Applying side1 will be quiet. + test_must_fail git am --quiet side[123].eml >out && + test_path_is_dir .git/rebase-apply && + ! test_i18ngrep "^Applying: " out && + echo side1 >file && + git add file && + + # Applying side1 will not be quiet. + # Applying side2 will be quiet. + git am --no-quiet --continue >out && + echo "Applying: side1" >expected && + test_i18ncmp expected out +' + +test_expect_success '--signoff overrides --no-signoff' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + + test_must_fail git am --no-signoff side[12].eml && + test_path_is_dir .git/rebase-apply && + echo side1 >file && + git add file && + git am --signoff --continue && + + # Applied side1 will be signed off + echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected && + git cat-file commit HEAD^ | grep "Signed-off-by:" >actual && + test_cmp expected actual && + + # Applied side2 will not be signed off + test $(git cat-file commit HEAD | grep -c "Signed-off-by:") -eq 0 +' + +test_expect_success TTY '--reject overrides --no-reject' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + rm -f file.rej && + + test_must_fail git am --no-reject side1.eml && + test_path_is_dir .git/rebase-apply && + test_path_is_missing file.rej && + + test_must_fail test_terminal git am --reject </dev/zero && + test_path_is_dir .git/rebase-apply && + test_path_is_file file.rej +' + +test_done diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 1b2e981a00..cb82eb7e66 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -146,7 +146,30 @@ test_expect_success 'git log --follow' ' actual=$(git log --follow --pretty="format:%s" ichi) && expect=$(echo third ; echo second ; echo initial) && verbose test "$actual" = "$expect" +' + +test_expect_success 'git config log.follow works like --follow' ' + test_config log.follow true && + actual=$(git log --pretty="format:%s" ichi) && + expect=$(echo third ; echo second ; echo initial) && + verbose test "$actual" = "$expect" +' + +test_expect_success 'git config log.follow does not die with multiple paths' ' + test_config log.follow true && + git log --pretty="format:%s" ichi ein +' + +test_expect_success 'git config log.follow does not die with no paths' ' + test_config log.follow true && + git log -- +' +test_expect_success 'git config log.follow is overridden by --no-follow' ' + test_config log.follow true && + actual=$(git log --no-follow --pretty="format:%s" ichi) && + expect="third" && + verbose test "$actual" = "$expect" ' cat > expect << EOF @@ -871,4 +894,47 @@ test_expect_success 'log --graph --no-walk is forbidden' ' test_must_fail git log --graph --no-walk ' +test_expect_success 'log diagnoses bogus HEAD' ' + git init empty && + test_must_fail git -C empty log 2>stderr && + test_i18ngrep does.not.have.any.commits stderr && + echo 1234abcd >empty/.git/refs/heads/master && + test_must_fail git -C empty log 2>stderr && + test_i18ngrep broken stderr && + echo "ref: refs/heads/invalid.lock" >empty/.git/HEAD && + test_must_fail git -C empty log 2>stderr && + test_i18ngrep broken stderr && + test_must_fail git -C empty log --default totally-bogus 2>stderr && + test_i18ngrep broken stderr +' + +test_expect_success 'set up --source tests' ' + git checkout --orphan source-a && + test_commit one && + test_commit two && + git checkout -b source-b HEAD^ && + test_commit three +' + +test_expect_success 'log --source paints branch names' ' + cat >expect <<-\EOF && + 09e12a9 source-b three + 8e393e1 source-a two + 1ac6c77 source-b one + EOF + git log --oneline --source source-a source-b >actual && + test_cmp expect actual +' + +test_expect_success 'log --source paints tag names' ' + git tag -m tagged source-tag && + cat >expect <<-\EOF && + 09e12a9 source-tag three + 8e393e1 source-a two + 1ac6c77 source-tag one + EOF + git log --oneline --source source-tag source-a >actual && + test_cmp expect actual +' + test_done diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh index 654addaae3..cca23383c5 100755 --- a/t/t5004-archive-corner-cases.sh +++ b/t/t5004-archive-corner-cases.sh @@ -115,4 +115,44 @@ test_expect_success 'archive empty subtree by direct pathspec' ' check_dir extract sub ' +ZIPINFO=zipinfo + +test_lazy_prereq ZIPINFO ' + n=$("$ZIPINFO" "$TEST_DIRECTORY"/t5004/empty.zip | sed -n "2s/.* //p") + test "x$n" = "x0" +' + +test_expect_success ZIPINFO 'zip archive with many entries' ' + # add a directory with 256 files + mkdir 00 && + for a in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + for b in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + : >00/$a$b + done + done && + git add 00 && + git commit -m "256 files in 1 directory" && + + # duplicate it to get 65536 files in 256 directories + subtree=$(git write-tree --prefix=00/) && + for c in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + for d in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + echo "040000 tree $subtree $c$d" + done + done >tree && + tree=$(git mktree <tree) && + + # zip them + git archive -o many.zip $tree && + + # check the number of entries in the ZIP file directory + expr 65536 + 256 >expect && + "$ZIPINFO" many.zip | head -2 | sed -n "2s/.* //p" >actual && + test_cmp expect actual +' + test_done diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 61bc8da560..3dc5ec4dd3 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -259,7 +259,7 @@ EOF thirtyeight=${tag#??} && rm -f .git/objects/${tag%$thirtyeight}/$thirtyeight && git index-pack --strict tag-test-${pack1}.pack 2>err && - grep "^error:.* expected .tagger. line" err + grep "^warning:.* expected .tagger. line" err ' test_done diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index 0794d33dad..def203c724 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -218,6 +218,8 @@ test_expect_success 'gc: prune old objects after local clone' ' ' test_expect_success 'garbage report in count-objects -v' ' + test_when_finished "rm -f .git/objects/pack/fake*" && + test_when_finished "rm -f .git/objects/pack/foo*" && : >.git/objects/pack/foo && : >.git/objects/pack/foo.bar && : >.git/objects/pack/foo.keep && @@ -243,6 +245,26 @@ EOF test_cmp expected actual ' +test_expect_success 'clean pack garbage with gc' ' + test_when_finished "rm -f .git/objects/pack/fake*" && + test_when_finished "rm -f .git/objects/pack/foo*" && + : >.git/objects/pack/foo.keep && + : >.git/objects/pack/foo.pack && + : >.git/objects/pack/fake.idx && + : >.git/objects/pack/fake2.keep && + : >.git/objects/pack/fake2.idx && + : >.git/objects/pack/fake3.keep && + git gc && + git count-objects -v 2>stderr && + grep "^warning:" stderr | sort >actual && + cat >expected <<\EOF && +warning: no corresponding .idx or .pack: .git/objects/pack/fake3.keep +warning: no corresponding .idx: .git/objects/pack/foo.keep +warning: no corresponding .idx: .git/objects/pack/foo.pack +EOF + test_cmp expected actual +' + test_expect_success 'prune .git/shallow' ' SHA1=`echo hi|git commit-tree HEAD^{tree}` && echo $SHA1 >.git/shallow && diff --git a/t/t5312-prune-corruption.sh b/t/t5312-prune-corruption.sh index 8e98b44083..da9d59940d 100755 --- a/t/t5312-prune-corruption.sh +++ b/t/t5312-prune-corruption.sh @@ -12,7 +12,7 @@ delete objects that cannot be recovered. test_expect_success 'disable reflogs' ' git config core.logallrefupdates false && - rm -rf .git/logs + git reflog expire --expire=all --all ' test_expect_success 'create history reachable only from a bogus-named ref' ' diff --git a/t/t5313-pack-bounds-checks.sh b/t/t5313-pack-bounds-checks.sh new file mode 100755 index 0000000000..a8a587abc3 --- /dev/null +++ b/t/t5313-pack-bounds-checks.sh @@ -0,0 +1,179 @@ +#!/bin/sh + +test_description='bounds-checking of access to mmapped on-disk file formats' +. ./test-lib.sh + +clear_base () { + test_when_finished 'restore_base' && + rm -f $base +} + +restore_base () { + cp base-backup/* .git/objects/pack/ +} + +do_pack () { + pack_objects=$1; shift + sha1=$( + for i in $pack_objects + do + echo $i + done | git pack-objects "$@" .git/objects/pack/pack + ) && + pack=.git/objects/pack/pack-$sha1.pack && + idx=.git/objects/pack/pack-$sha1.idx && + chmod +w $pack $idx && + test_when_finished 'rm -f "$pack" "$idx"' +} + +munge () { + printf "$3" | dd of="$1" bs=1 conv=notrunc seek=$2 +} + +# Offset in a v2 .idx to its initial and extended offset tables. For an index +# with "nr" objects, this is: +# +# magic(4) + version(4) + fan-out(4*256) + sha1s(20*nr) + crc(4*nr), +# +# for the initial, and another ofs(4*nr) past that for the extended. +# +ofs_table () { + echo $((4 + 4 + 4*256 + 20*$1 + 4*$1)) +} +extended_table () { + echo $(($(ofs_table "$1") + 4*$1)) +} + +test_expect_success 'set up base packfile and variables' ' + # the hash of this content starts with ff, which + # makes some later computations much simpler + echo 74 >file && + git add file && + git commit -m base && + git repack -ad && + base=$(echo .git/objects/pack/*) && + chmod +w $base && + mkdir base-backup && + cp $base base-backup/ && + object=$(git rev-parse HEAD:file) +' + +test_expect_success 'pack/index object count mismatch' ' + do_pack $object && + munge $pack 8 "\377\0\0\0" && + clear_base && + + # We enumerate the objects from the completely-fine + # .idx, but notice later that the .pack is bogus + # and fail to show any data. + echo "$object missing" >expect && + git cat-file --batch-all-objects --batch-check >actual && + test_cmp expect actual && + + # ...and here fail to load the object (without segfaulting), + # but fallback to a good copy if available. + test_must_fail git cat-file blob $object && + restore_base && + git cat-file blob $object >actual && + test_cmp file actual && + + # ...and make sure that index-pack --verify, which has its + # own reading routines, does not segfault. + test_must_fail git index-pack --verify $pack +' + +test_expect_success 'matched bogus object count' ' + do_pack $object && + munge $pack 8 "\377\0\0\0" && + munge $idx $((255 * 4)) "\377\0\0\0" && + clear_base && + + # Unlike above, we should notice early that the .idx is totally + # bogus, and not even enumerate its contents. + >expect && + git cat-file --batch-all-objects --batch-check >actual && + test_cmp expect actual && + + # But as before, we can do the same object-access checks. + test_must_fail git cat-file blob $object && + restore_base && + git cat-file blob $object >actual && + test_cmp file actual && + + test_must_fail git index-pack --verify $pack +' + +# Note that we cannot check the fallback case for these +# further .idx tests, as we notice the problem in functions +# whose interface doesn't allow an error return (like use_pack()), +# and thus we just die(). +# +# There's also no point in doing enumeration tests, as +# we are munging offsets here, which are about looking up +# specific objects. + +test_expect_success 'bogus object offset (v1)' ' + do_pack $object --index-version=1 && + munge $idx $((4 * 256)) "\377\0\0\0" && + clear_base && + test_must_fail git cat-file blob $object && + test_must_fail git index-pack --verify $pack +' + +test_expect_success 'bogus object offset (v2, no msb)' ' + do_pack $object --index-version=2 && + munge $idx $(ofs_table 1) "\0\377\0\0" && + clear_base && + test_must_fail git cat-file blob $object && + test_must_fail git index-pack --verify $pack +' + +test_expect_success 'bogus offset into v2 extended table' ' + do_pack $object --index-version=2 && + munge $idx $(ofs_table 1) "\377\0\0\0" && + clear_base && + test_must_fail git cat-file blob $object && + test_must_fail git index-pack --verify $pack +' + +test_expect_success 'bogus offset inside v2 extended table' ' + # We need two objects here, so we can plausibly require + # an extended table (if the first object were larger than 2^31). + do_pack "$object $(git rev-parse HEAD)" --index-version=2 && + + # We have to make extra room for the table, so we cannot + # just munge in place as usual. + { + dd if=$idx bs=1 count=$(($(ofs_table 2) + 4)) && + printf "\200\0\0\0" && + printf "\377\0\0\0\0\0\0\0" && + dd if=$idx bs=1 skip=$(extended_table 2) + } >tmp && + mv tmp "$idx" && + clear_base && + test_must_fail git cat-file blob $object && + test_must_fail git index-pack --verify $pack +' + +test_expect_success 'bogus OFS_DELTA in packfile' ' + # Generate a pack with a delta in it. + base=$(test-genrandom foo 3000 | git hash-object --stdin -w) && + delta=$(test-genrandom foo 2000 | git hash-object --stdin -w) && + do_pack "$base $delta" --delta-base-offset && + rm -f .git/objects/??/* && + + # Double check that we have the delta we expect. + echo $base >expect && + echo $delta | git cat-file --batch-check="%(deltabase)" >actual && + test_cmp expect actual && + + # Now corrupt it. We assume the varint size for the delta is small + # enough to fit in the first byte (which it should be, since it + # is a pure deletion from the base), and that original ofs_delta + # takes 2 bytes (which it should, as it should be ~3000). + ofs=$(git show-index <$idx | grep $delta | cut -d" " -f1) && + munge $pack $(($ofs + 1)) "\177\377" && + test_must_fail git cat-file blob $delta >/dev/null +' + +test_done diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh index 69ee13c8be..a3e12d295a 100755 --- a/t/t5504-fetch-receive-strict.sh +++ b/t/t5504-fetch-receive-strict.sh @@ -100,8 +100,11 @@ test_expect_success 'push with receive.fsckobjects' ' git config receive.fsckobjects true && git config transfer.fsckobjects false ) && - test_must_fail git push --porcelain dst master:refs/heads/test >act && - test_cmp exp act + test_must_fail ok=sigpipe git push --porcelain dst master:refs/heads/test >act && + { + test_cmp exp act || + ! test -s act + } ' test_expect_success 'push with transfer.fsckobjects' ' @@ -111,8 +114,58 @@ test_expect_success 'push with transfer.fsckobjects' ' cd dst && git config transfer.fsckobjects true ) && - test_must_fail git push --porcelain dst master:refs/heads/test >act && - test_cmp exp act + test_must_fail ok=sigpipe git push --porcelain dst master:refs/heads/test >act +' + +cat >bogus-commit <<\EOF +tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 +author Bugs Bunny 1234567890 +0000 +committer Bugs Bunny <bugs@bun.ni> 1234567890 +0000 + +This commit object intentionally broken +EOF + +test_expect_success 'push with receive.fsck.skipList' ' + commit="$(git hash-object -t commit -w --stdin <bogus-commit)" && + git push . $commit:refs/heads/bogus && + rm -rf dst && + git init dst && + git --git-dir=dst/.git config receive.fsckObjects true && + test_must_fail git push --porcelain dst bogus && + git --git-dir=dst/.git config receive.fsck.skipList SKIP && + echo $commit >dst/.git/SKIP && + git push --porcelain dst bogus +' + +test_expect_success 'push with receive.fsck.missingEmail=warn' ' + commit="$(git hash-object -t commit -w --stdin <bogus-commit)" && + git push . $commit:refs/heads/bogus && + rm -rf dst && + git init dst && + git --git-dir=dst/.git config receive.fsckobjects true && + test_must_fail git push --porcelain dst bogus && + git --git-dir=dst/.git config \ + receive.fsck.missingEmail warn && + git push --porcelain dst bogus >act 2>&1 && + grep "missingEmail" act && + git --git-dir=dst/.git branch -D bogus && + git --git-dir=dst/.git config --add \ + receive.fsck.missingEmail ignore && + git --git-dir=dst/.git config --add \ + receive.fsck.badDate warn && + git push --porcelain dst bogus >act 2>&1 && + test_must_fail grep "missingEmail" act +' + +test_expect_success \ + 'receive.fsck.unterminatedHeader=warn triggers error' ' + rm -rf dst && + git init dst && + git --git-dir=dst/.git config receive.fsckobjects true && + git --git-dir=dst/.git config \ + receive.fsck.unterminatedheader warn && + test_must_fail git push --porcelain dst HEAD >act 2>&1 && + grep "Cannot demote unterminatedheader" act ' test_done diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 7a8499ce66..013e03dee2 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -919,6 +919,28 @@ test_expect_success 'new remote' ' cmp expect actual ' +get_url_test () { + cat >expect && + git remote get-url "$@" >actual && + test_cmp expect actual +} + +test_expect_success 'get-url on new remote' ' + echo foo | get_url_test someremote && + echo foo | get_url_test --all someremote && + echo foo | get_url_test --push someremote && + echo foo | get_url_test --push --all someremote +' + +test_expect_success 'remote set-url with locked config' ' + test_when_finished "rm -f .git/config.lock" && + git config --get-all remote.someremote.url >expect && + >.git/config.lock && + test_must_fail git remote set-url someremote baz && + git config --get-all remote.someremote.url >actual && + cmp expect actual +' + test_expect_success 'remote set-url bar' ' git remote set-url someremote bar && echo bar >expect && @@ -961,6 +983,13 @@ test_expect_success 'remote set-url --push zot' ' cmp expect actual ' +test_expect_success 'get-url with different urls' ' + echo baz | get_url_test someremote && + echo baz | get_url_test --all someremote && + echo zot | get_url_test --push someremote && + echo zot | get_url_test --push --all someremote +' + test_expect_success 'remote set-url --push qux zot' ' git remote set-url --push someremote qux zot && echo qux >expect && @@ -995,6 +1024,14 @@ test_expect_success 'remote set-url --push --add aaa' ' cmp expect actual ' +test_expect_success 'get-url on multi push remote' ' + echo foo | get_url_test --push someremote && + get_url_test --push --all someremote <<-\EOF + foo + aaa + EOF +' + test_expect_success 'remote set-url --push bar aaa' ' git remote set-url --push someremote bar aaa && echo foo >expect && @@ -1039,6 +1076,14 @@ test_expect_success 'remote set-url --add bbb' ' cmp expect actual ' +test_expect_success 'get-url on multi fetch remote' ' + echo baz | get_url_test someremote && + get_url_test --all someremote <<-\EOF + baz + bbb + EOF +' + test_expect_success 'remote set-url --delete .*' ' test_must_fail git remote set-url --delete someremote .\* && echo "YYY" >expect && @@ -1108,6 +1153,7 @@ 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 get-url origin newurl test_extra_arg set-url origin newurl oldurl # show takes any number of args # prune takes any number of args diff --git a/t/t5507-remote-environment.sh b/t/t5507-remote-environment.sh new file mode 100755 index 0000000000..e6149295b1 --- /dev/null +++ b/t/t5507-remote-environment.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +test_description='check environment showed to remote side of transports' +. ./test-lib.sh + +test_expect_success 'set up "remote" push situation' ' + test_commit one && + git config push.default current && + git init remote +' + +test_expect_success 'set up fake ssh' ' + GIT_SSH_COMMAND="f() { + cd \"\$TRASH_DIRECTORY\" && + eval \"\$2\" + }; f" && + export GIT_SSH_COMMAND && + export TRASH_DIRECTORY +' + +# due to receive.denyCurrentBranch=true +test_expect_success 'confirm default push fails' ' + test_must_fail git push remote +' + +test_expect_success 'config does not travel over same-machine push' ' + test_must_fail git -c receive.denyCurrentBranch=false push remote +' + +test_expect_success 'config does not travel over ssh push' ' + test_must_fail git -c receive.denyCurrentBranch=false push host:remote +' + +test_done diff --git a/t/t5509-fetch-push-namespaces.sh b/t/t5509-fetch-push-namespaces.sh index cc0b31f6b0..bc44ac36d5 100755 --- a/t/t5509-fetch-push-namespaces.sh +++ b/t/t5509-fetch-push-namespaces.sh @@ -82,4 +82,45 @@ test_expect_success 'mirroring a repository using a ref namespace' ' ) ' +test_expect_success 'hide namespaced refs with transfer.hideRefs' ' + GIT_NAMESPACE=namespace \ + git -C pushee -c transfer.hideRefs=refs/tags \ + ls-remote "ext::git %s ." >actual && + printf "$commit1\trefs/heads/master\n" >expected && + test_cmp expected actual +' + +test_expect_success 'check that transfer.hideRefs does not match unstripped refs' ' + GIT_NAMESPACE=namespace \ + git -C pushee -c transfer.hideRefs=refs/namespaces/namespace/refs/tags \ + ls-remote "ext::git %s ." >actual && + printf "$commit1\trefs/heads/master\n" >expected && + printf "$commit0\trefs/tags/0\n" >>expected && + printf "$commit1\trefs/tags/1\n" >>expected && + test_cmp expected actual +' + +test_expect_success 'hide full refs with transfer.hideRefs' ' + GIT_NAMESPACE=namespace \ + git -C pushee -c transfer.hideRefs="^refs/namespaces/namespace/refs/tags" \ + ls-remote "ext::git %s ." >actual && + printf "$commit1\trefs/heads/master\n" >expected && + test_cmp expected actual +' + +test_expect_success 'try to update a hidden ref' ' + test_config -C pushee transfer.hideRefs refs/heads/master && + test_must_fail git -C original push pushee-namespaced master +' + +test_expect_success 'try to update a ref that is not hidden' ' + test_config -C pushee transfer.hideRefs refs/namespaces/namespace/refs/heads/master && + git -C original push pushee-namespaced master +' + +test_expect_success 'try to update a hidden full ref' ' + test_config -C pushee transfer.hideRefs "^refs/namespaces/namespace/refs/heads/master" && + test_must_fail git -C original push pushee-namespaced master +' + test_done diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 0ba9db0884..e3ee4bd700 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -708,4 +708,17 @@ test_expect_success 'fetching a one-level ref works' ' ) ' +test_expect_success 'fetching with auto-gc does not lock up' ' + write_script askyesno <<-\EOF && + echo "$*" && + false + EOF + git clone "file://$D" auto-gc && + test_commit test2 && + cd auto-gc && + git config gc.autoPackLimit 1 && + GIT_ASK_YESNO="$D/askyesno" git fetch >fetch.out 2>&1 && + ! grep "Should I try again" fetch.out +' + test_done diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index de6db86ccf..f541f30bc2 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -71,15 +71,18 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me' test_refspec push ':refs/remotes/frotz/delete me' invalid test_refspec fetch ':refs/remotes/frotz/HEAD to me' invalid -test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid -test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid +test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' +test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' -test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid -test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid +test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' +test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid +test_refspec fetch 'refs/heads/*g*/for-linus:refs/remotes/mine/*' invalid +test_refspec push 'refs/heads/*g*/for-linus:refs/remotes/mine/*' invalid + test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*' test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*' diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 3bd9759e0f..aadaac515e 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -128,6 +128,11 @@ test_expect_success 'Report match with --exit-code' ' test_cmp expect actual ' +test_expect_success 'set up some extra tags for ref hiding' ' + git tag magic/one && + git tag magic/two +' + for configsection in transfer uploadpack do test_expect_success "Hide some refs with $configsection.hiderefs" ' @@ -138,6 +143,24 @@ do sed -e "/ refs\/tags\//d" >expect && test_cmp expect actual ' + + test_expect_success "Override hiding of $configsection.hiderefs" ' + test_when_finished "test_unconfig $configsection.hiderefs" && + git config --add $configsection.hiderefs refs/tags && + git config --add $configsection.hiderefs "!refs/tags/magic" && + git config --add $configsection.hiderefs refs/tags/magic/one && + git ls-remote . >actual && + grep refs/tags/magic/two actual && + ! grep refs/tags/magic/one actual + ' + done +test_expect_success 'overrides work between mixed transfer/upload-pack hideRefs' ' + test_config uploadpack.hiderefs refs/tags && + test_config transfer.hiderefs "!refs/tags/magic" && + git ls-remote . >actual && + grep refs/tags/magic actual +' + test_done diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 8a5f2363a9..0a87e195ea 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -1120,6 +1120,61 @@ test_expect_success 'fetch exact SHA1' ' ) ' +for configallowtipsha1inwant in true false +do + test_expect_success "shallow fetch reachable SHA1 (but not a ref), allowtipsha1inwant=$configallowtipsha1inwant" ' + mk_empty testrepo && + ( + cd testrepo && + git config uploadpack.allowtipsha1inwant $configallowtipsha1inwant && + git commit --allow-empty -m foo && + git commit --allow-empty -m bar + ) && + SHA1=$(git --git-dir=testrepo/.git rev-parse HEAD^) && + mk_empty shallow && + ( + cd shallow && + test_must_fail git fetch --depth=1 ../testrepo/.git $SHA1 && + git --git-dir=../testrepo/.git config uploadpack.allowreachablesha1inwant true && + git fetch --depth=1 ../testrepo/.git $SHA1 && + git cat-file commit $SHA1 + ) + ' + + test_expect_success "deny fetch unreachable SHA1, allowtipsha1inwant=$configallowtipsha1inwant" ' + mk_empty testrepo && + ( + cd testrepo && + git config uploadpack.allowtipsha1inwant $configallowtipsha1inwant && + git commit --allow-empty -m foo && + git commit --allow-empty -m bar && + git commit --allow-empty -m xyz + ) && + SHA1_1=$(git --git-dir=testrepo/.git rev-parse HEAD^^) && + SHA1_2=$(git --git-dir=testrepo/.git rev-parse HEAD^) && + SHA1_3=$(git --git-dir=testrepo/.git rev-parse HEAD) && + ( + cd testrepo && + git reset --hard $SHA1_2 && + git cat-file commit $SHA1_1 && + git cat-file commit $SHA1_3 + ) && + mk_empty shallow && + ( + cd shallow && + test_must_fail ok=sigpipe git fetch ../testrepo/.git $SHA1_3 && + test_must_fail ok=sigpipe git fetch ../testrepo/.git $SHA1_1 && + git --git-dir=../testrepo/.git config uploadpack.allowreachablesha1inwant true && + git fetch ../testrepo/.git $SHA1_1 && + git cat-file commit $SHA1_1 && + test_must_fail git cat-file commit $SHA1_2 && + git fetch ../testrepo/.git $SHA1_2 && + git cat-file commit $SHA1_2 && + test_must_fail ok=sigpipe git fetch ../testrepo/.git $SHA1_3 + ) + ' +done + test_expect_success 'fetch follows tags by default' ' mk_test testrepo heads/master && rm -fr src dst && diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index 227d293350..a0013ee32f 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -9,36 +9,27 @@ modify () { mv "$2.x" "$2" } -D=`pwd` - test_expect_success setup ' - echo file >file && git add file && git commit -a -m original - ' test_expect_success 'pulling into void' ' - mkdir cloned && - cd cloned && - git init && - git pull .. -' - -cd "$D" - -test_expect_success 'checking the results' ' + git init cloned && + ( + cd cloned && + git pull .. + ) && test -f file && test -f cloned/file && test_cmp file cloned/file ' test_expect_success 'pulling into void using master:master' ' - mkdir cloned-uho && + git init cloned-uho && ( cd cloned-uho && - git init && git pull .. master:master ) && test -f file && @@ -71,7 +62,6 @@ test_expect_success 'pulling into void does not overwrite staged files' ' ) ' - test_expect_success 'pulling into void does not remove new staged files' ' git init cloned-staged-new && ( @@ -86,17 +76,29 @@ test_expect_success 'pulling into void does not remove new staged files' ' ) ' -test_expect_success 'test . as a remote' ' +test_expect_success 'pulling into void must not create an octopus' ' + git init cloned-octopus && + ( + cd cloned-octopus && + test_must_fail git pull .. master master && + ! test -f file + ) +' +test_expect_success 'test . as a remote' ' git branch copy master && git config branch.copy.remote . && git config branch.copy.merge refs/heads/master && echo updated >file && git commit -a -m updated && git checkout copy && - test `cat file` = file && + test "$(cat file)" = file && git pull && - test `cat file` = updated + test "$(cat file)" = updated && + git reflog -1 >reflog.actual && + sed "s/^[0-9a-f][0-9a-f]*/OBJID/" reflog.actual >reflog.fuzzy && + echo "OBJID HEAD@{0}: pull: Fast-forward" >reflog.expected && + test_cmp reflog.expected reflog.fuzzy ' test_expect_success 'the default remote . should not break explicit pull' ' @@ -105,9 +107,120 @@ test_expect_success 'the default remote . should not break explicit pull' ' git commit -a -m modified && git checkout copy && git reset --hard HEAD^ && - test `cat file` = file && + test "$(cat file)" = file && git pull . second && - test `cat file` = modified + test "$(cat file)" = modified && + git reflog -1 >reflog.actual && + sed "s/^[0-9a-f][0-9a-f]*/OBJID/" reflog.actual >reflog.fuzzy && + echo "OBJID HEAD@{0}: pull . second: Fast-forward" >reflog.expected && + test_cmp reflog.expected reflog.fuzzy +' + +test_expect_success 'fail if wildcard spec does not match any refs' ' + git checkout -b test copy^ && + test_when_finished "git checkout -f copy && git branch -D test" && + test "$(cat file)" = file && + test_must_fail git pull . "refs/nonexisting1/*:refs/nonexisting2/*" 2>err && + test_i18ngrep "no candidates for merging" err && + test "$(cat file)" = file +' + +test_expect_success 'fail if no branches specified with non-default remote' ' + git remote add test_remote . && + test_when_finished "git remote remove test_remote" && + git checkout -b test copy^ && + test_when_finished "git checkout -f copy && git branch -D test" && + test "$(cat file)" = file && + test_config branch.test.remote origin && + test_must_fail git pull test_remote 2>err && + test_i18ngrep "specify a branch on the command line" err && + test "$(cat file)" = file +' + +test_expect_success 'fail if not on a branch' ' + git remote add origin . && + test_when_finished "git remote remove origin" && + git checkout HEAD^ && + test_when_finished "git checkout -f copy" && + test "$(cat file)" = file && + test_must_fail git pull 2>err && + test_i18ngrep "not currently on a branch" err && + test "$(cat file)" = file +' + +test_expect_success 'fail if no configuration for current branch' ' + git remote add test_remote . && + test_when_finished "git remote remove test_remote" && + git checkout -b test copy^ && + test_when_finished "git checkout -f copy && git branch -D test" && + test_config branch.test.remote test_remote && + test "$(cat file)" = file && + test_must_fail git pull 2>err && + test_i18ngrep "no tracking information" err && + test "$(cat file)" = file +' + +test_expect_success 'pull --all: fail if no configuration for current branch' ' + git remote add test_remote . && + test_when_finished "git remote remove test_remote" && + git checkout -b test copy^ && + test_when_finished "git checkout -f copy && git branch -D test" && + test_config branch.test.remote test_remote && + test "$(cat file)" = file && + test_must_fail git pull --all 2>err && + test_i18ngrep "There is no tracking information" err && + test "$(cat file)" = file +' + +test_expect_success 'fail if upstream branch does not exist' ' + git checkout -b test copy^ && + test_when_finished "git checkout -f copy && git branch -D test" && + test_config branch.test.remote . && + test_config branch.test.merge refs/heads/nonexisting && + test "$(cat file)" = file && + test_must_fail git pull 2>err && + test_i18ngrep "no such ref was fetched" err && + test "$(cat file)" = file +' + +test_expect_success 'fail if the index has unresolved entries' ' + git checkout -b third second^ && + test_when_finished "git checkout -f copy && git branch -D third" && + test "$(cat file)" = file && + test_commit modified2 file && + test -z "$(git ls-files -u)" && + test_must_fail git pull . second && + test -n "$(git ls-files -u)" && + cp file expected && + test_must_fail git pull . second 2>err && + test_i18ngrep "Pull is not possible because you have unmerged files" err && + test_cmp expected file && + git add file && + test -z "$(git ls-files -u)" && + test_must_fail git pull . second 2>err && + test_i18ngrep "You have not concluded your merge" err && + test_cmp expected file +' + +test_expect_success 'fast-forwards working tree if branch head is updated' ' + git checkout -b third second^ && + test_when_finished "git checkout -f copy && git branch -D third" && + test "$(cat file)" = file && + git pull . second:third 2>err && + test_i18ngrep "fetch updated the current branch head" err && + test "$(cat file)" = modified && + test "$(git rev-parse third)" = "$(git rev-parse second)" +' + +test_expect_success 'fast-forward fails with conflicting work tree' ' + git checkout -b third second^ && + test_when_finished "git checkout -f copy && git branch -D third" && + test "$(cat file)" = file && + echo conflict >file && + test_must_fail git pull . second:third 2>err && + test_i18ngrep "Cannot fast-forward your working tree" err && + test "$(cat file)" = conflict && + test "$(git rev-parse third)" = "$(git rev-parse second)" ' test_expect_success '--rebase' ' @@ -120,23 +233,43 @@ test_expect_success '--rebase' ' git commit -m "new file" && git tag before-rebase && git pull --rebase . copy && - test $(git rev-parse HEAD^) = $(git rev-parse copy) && - test new = $(git show HEAD:file2) + test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" && + test new = "$(git show HEAD:file2)" ' + +test_expect_success '--rebase fails with multiple branches' ' + git reset --hard before-rebase && + test_must_fail git pull --rebase . copy master 2>err && + test "$(git rev-parse HEAD)" = "$(git rev-parse before-rebase)" && + test_i18ngrep "Cannot rebase onto multiple branches" err && + test modified = "$(git show HEAD:file)" +' + +test_expect_success 'pull --rebase succeeds with dirty working directory and rebase.autostash set' ' + test_config rebase.autostash true && + git reset --hard before-rebase && + echo dirty >new_file && + git add new_file && + git pull --rebase . copy && + test_cmp_rev HEAD^ copy && + test "$(cat new_file)" = dirty && + test "$(cat file)" = "modified again" +' + test_expect_success 'pull.rebase' ' git reset --hard before-rebase && test_config pull.rebase true && git pull . copy && - test $(git rev-parse HEAD^) = $(git rev-parse copy) && - test new = $(git show HEAD:file2) + test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" && + test new = "$(git show HEAD:file2)" ' test_expect_success 'branch.to-rebase.rebase' ' git reset --hard before-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) + test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" && + test new = "$(git show HEAD:file2)" ' test_expect_success 'branch.to-rebase.rebase should override pull.rebase' ' @@ -144,8 +277,8 @@ test_expect_success 'branch.to-rebase.rebase should override pull.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) + 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 @@ -164,33 +297,33 @@ 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 "$(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 "$(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 "$(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 "$(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' ' @@ -203,25 +336,25 @@ 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 "$(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 "$(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 "$(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' ' @@ -233,8 +366,8 @@ test_expect_success '--rebase overrides pull.rebase=preserve and flattens keep-m 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 "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" && + test file3 = "$(git show HEAD:file3.t)" ' test_expect_success '--rebase with rebased upstream' ' @@ -251,10 +384,18 @@ test_expect_success '--rebase with rebased upstream' ' git tag to-rebase-orig && git pull --rebase me copy && test "conflicting modification" = "$(cat file)" && - test file = $(cat file2) + test file = "$(cat file2)" ' +test_expect_success '--rebase -f with rebased upstream' ' + test_when_finished "test_might_fail git rebase --abort" && + git reset --hard to-rebase-orig && + git pull --rebase -f me copy && + test "conflicting modification" = "$(cat file)" && + test file = "$(cat file2)" +' + test_expect_success '--rebase with rebased default upstream' ' git update-ref refs/remotes/me/copy copy-orig && @@ -262,7 +403,7 @@ test_expect_success '--rebase with rebased default upstream' ' git reset --hard to-rebase-orig && git pull --rebase && test "conflicting modification" = "$(cat file)" && - test file = $(cat file2) + test file = "$(cat file2)" ' @@ -283,7 +424,7 @@ test_expect_success 'pull --rebase dies early with dirty working directory' ' git checkout to-rebase && git update-ref refs/remotes/me/copy copy^ && - COPY=$(git rev-parse --verify me/copy) && + COPY="$(git rev-parse --verify me/copy)" && git rebase --onto $COPY copy && test_config branch.to-rebase.remote me && test_config branch.to-rebase.merge refs/heads/copy && @@ -291,10 +432,10 @@ test_expect_success 'pull --rebase dies early with dirty working directory' ' echo dirty >> file && git add file && test_must_fail git pull && - test $COPY = $(git rev-parse --verify me/copy) && + test "$COPY" = "$(git rev-parse --verify me/copy)" && git checkout HEAD -- file && git pull && - test $COPY != $(git rev-parse --verify me/copy) + test "$COPY" != "$(git rev-parse --verify me/copy)" ' @@ -309,6 +450,21 @@ test_expect_success 'pull --rebase works on branch yet to be born' ' test_cmp expect actual ' +test_expect_success 'pull --rebase fails on unborn branch with staged changes' ' + test_when_finished "rm -rf empty_repo2" && + git init empty_repo2 && + ( + cd empty_repo2 && + echo staged-file >staged-file && + git add staged-file && + test "$(git ls-files)" = staged-file && + test_must_fail git pull --rebase .. master 2>err && + test "$(git ls-files)" = staged-file && + test "$(git show :staged-file)" = staged-file && + test_i18ngrep "unborn branch with changes added to the index" err + ) +' + test_expect_success 'setup for detecting upstreamed changes' ' mkdir src && (cd src && diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh index 453aba53f4..18372caa15 100755 --- a/t/t5521-pull-options.sh +++ b/t/t5521-pull-options.sh @@ -117,4 +117,31 @@ test_expect_success 'git pull --all' ' ) ' +test_expect_success 'git pull --dry-run' ' + test_when_finished "rm -rf clonedry" && + git init clonedry && + ( + cd clonedry && + git pull --dry-run ../parent && + test_path_is_missing .git/FETCH_HEAD && + test_path_is_missing .git/refs/heads/master && + test_path_is_missing .git/index && + test_path_is_missing file + ) +' + +test_expect_success 'git pull --all --dry-run' ' + test_when_finished "rm -rf cloneddry" && + git init clonedry && + ( + cd clonedry && + git remote add origin ../parent && + git pull --all --dry-run && + test_path_is_missing .git/FETCH_HEAD && + test_path_is_missing .git/refs/remotes/origin/master && + test_path_is_missing .git/index && + test_path_is_missing file + ) +' + test_done diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh index 6507487c1a..198ce84754 100755 --- a/t/t5531-deep-submodule-push.sh +++ b/t/t5531-deep-submodule-push.sh @@ -64,7 +64,12 @@ test_expect_success 'push fails if submodule commit not on remote' ' cd work && git add gar/bage && git commit -m "Third commit for gar/bage" && - test_must_fail git push --recurse-submodules=check ../pub.git master + # the push should fail with --recurse-submodules=check + # on the command line... + test_must_fail git push --recurse-submodules=check ../pub.git master && + + # ...or if specified in the configuration.. + test_must_fail git -c push.recurseSubmodules=check push ../pub.git master ) ' @@ -79,6 +84,216 @@ test_expect_success 'push succeeds after commit was pushed to remote' ' ) ' +test_expect_success 'push succeeds if submodule commit not on remote but using on-demand on command line' ' + ( + cd work/gar/bage && + >recurse-on-demand-on-command-line && + git add recurse-on-demand-on-command-line && + git commit -m "Recurse on-demand on command line junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse on-demand on command line for gar/bage" && + git push --recurse-submodules=on-demand ../pub.git master && + # Check that the supermodule commit got there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + # Check that the submodule commit got there too + cd gar/bage && + git diff --quiet origin/master master + ) +' + +test_expect_success 'push succeeds if submodule commit not on remote but using on-demand from config' ' + ( + cd work/gar/bage && + >recurse-on-demand-from-config && + git add recurse-on-demand-from-config && + git commit -m "Recurse on-demand from config junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse on-demand from config for gar/bage" && + git -c push.recurseSubmodules=on-demand push ../pub.git master && + # Check that the supermodule commit got there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + # Check that the submodule commit got there too + cd gar/bage && + git diff --quiet origin/master master + ) +' + +test_expect_success 'push recurse-submodules on command line overrides config' ' + ( + cd work/gar/bage && + >recurse-check-on-command-line-overriding-config && + git add recurse-check-on-command-line-overriding-config && + git commit -m "Recurse on command-line overriding config junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse on command-line overriding config for gar/bage" && + + # Ensure that we can override on-demand in the config + # to just check submodules + test_must_fail git -c push.recurseSubmodules=on-demand push --recurse-submodules=check ../pub.git master && + # Check that the supermodule commit did not get there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master^ && + # Check that the submodule commit did not get there + (cd gar/bage && git diff --quiet origin/master master^) && + + # Ensure that we can override check in the config to + # disable submodule recursion entirely + (cd gar/bage && git diff --quiet origin/master master^) && + git -c push.recurseSubmodules=on-demand push --recurse-submodules=no ../pub.git master && + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + (cd gar/bage && git diff --quiet origin/master master^) && + + # Ensure that we can override check in the config to + # disable submodule recursion entirely (alternative form) + git -c push.recurseSubmodules=on-demand push --no-recurse-submodules ../pub.git master && + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + (cd gar/bage && git diff --quiet origin/master master^) && + + # Ensure that we can override check in the config to + # push the submodule too + git -c push.recurseSubmodules=check push --recurse-submodules=on-demand ../pub.git master && + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + (cd gar/bage && git diff --quiet origin/master master) + ) +' + +test_expect_success 'push recurse-submodules last one wins on command line' ' + ( + cd work/gar/bage && + >recurse-check-on-command-line-overriding-earlier-command-line && + git add recurse-check-on-command-line-overriding-earlier-command-line && + git commit -m "Recurse on command-line overridiing earlier command-line junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse on command-line overriding earlier command-line for gar/bage" && + + # should result in "check" + test_must_fail git push --recurse-submodules=on-demand --recurse-submodules=check ../pub.git master && + # Check that the supermodule commit did not get there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master^ && + # Check that the submodule commit did not get there + (cd gar/bage && git diff --quiet origin/master master^) && + + # should result in "no" + git push --recurse-submodules=on-demand --recurse-submodules=no ../pub.git master && + # Check that the supermodule commit did get there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + # Check that the submodule commit did not get there + (cd gar/bage && git diff --quiet origin/master master^) && + + # should result in "no" + git push --recurse-submodules=on-demand --no-recurse-submodules ../pub.git master && + # Check that the submodule commit did not get there + (cd gar/bage && git diff --quiet origin/master master^) && + + # But the options in the other order should push the submodule + git push --recurse-submodules=check --recurse-submodules=on-demand ../pub.git master && + # Check that the submodule commit did get there + git fetch ../pub.git && + (cd gar/bage && git diff --quiet origin/master master) + ) +' + +test_expect_success 'push succeeds if submodule commit not on remote using on-demand from cmdline overriding config' ' + ( + cd work/gar/bage && + >recurse-on-demand-on-command-line-overriding-config && + git add recurse-on-demand-on-command-line-overriding-config && + git commit -m "Recurse on-demand on command-line overriding config junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse on-demand on command-line overriding config for gar/bage" && + git -c push.recurseSubmodules=check push --recurse-submodules=on-demand ../pub.git master && + # Check that the supermodule commit got there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + # Check that the submodule commit got there + cd gar/bage && + git diff --quiet origin/master master + ) +' + +test_expect_success 'push succeeds if submodule commit disabling recursion from cmdline overriding config' ' + ( + cd work/gar/bage && + >recurse-disable-on-command-line-overriding-config && + git add recurse-disable-on-command-line-overriding-config && + git commit -m "Recurse disable on command-line overriding config junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse disable on command-line overriding config for gar/bage" && + git -c push.recurseSubmodules=check push --recurse-submodules=no ../pub.git master && + # Check that the supermodule commit got there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + # But that the submodule commit did not + ( cd gar/bage && git diff --quiet origin/master master^ ) && + # Now push it to avoid confusing future tests + git push --recurse-submodules=on-demand ../pub.git master + ) +' + +test_expect_success 'push succeeds if submodule commit disabling recursion from cmdline (alternative form) overriding config' ' + ( + cd work/gar/bage && + >recurse-disable-on-command-line-alt-overriding-config && + git add recurse-disable-on-command-line-alt-overriding-config && + git commit -m "Recurse disable on command-line alternative overriding config junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse disable on command-line alternative overriding config for gar/bage" && + git -c push.recurseSubmodules=check push --no-recurse-submodules ../pub.git master && + # Check that the supermodule commit got there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + # But that the submodule commit did not + ( cd gar/bage && git diff --quiet origin/master master^ ) && + # Now push it to avoid confusing future tests + git push --recurse-submodules=on-demand ../pub.git master + ) +' + +test_expect_success 'push fails if recurse submodules option passed as yes' ' + ( + cd work/gar/bage && + >recurse-push-fails-if-recurse-submodules-passed-as-yes && + git add recurse-push-fails-if-recurse-submodules-passed-as-yes && + git commit -m "Recurse push fails if recurse submodules option passed as yes" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse push fails if recurse submodules option passed as yes for gar/bage" && + test_must_fail git push --recurse-submodules=yes ../pub.git master && + test_must_fail git -c push.recurseSubmodules=yes push ../pub.git master && + git push --recurse-submodules=on-demand ../pub.git master + ) +' + test_expect_success 'push fails when commit on multiple branches if one branch has no remote' ' ( cd work/gar/bage && diff --git a/t/t5533-push-cas.sh b/t/t5533-push-cas.sh index c402d8d3d7..c7320121ec 100755 --- a/t/t5533-push-cas.sh +++ b/t/t5533-push-cas.sh @@ -25,7 +25,8 @@ test_expect_success 'push to update (protected)' ' ( cd dst && test_commit D && - test_must_fail git push --force-with-lease=master:master origin master + test_must_fail git push --force-with-lease=master:master origin master 2>err && + grep "stale info" err ) && git ls-remote . refs/heads/master >expect && git ls-remote src refs/heads/master >actual && @@ -37,7 +38,8 @@ test_expect_success 'push to update (protected, forced)' ' ( cd dst && test_commit D && - git push --force --force-with-lease=master:master origin master + git push --force --force-with-lease=master:master origin master 2>err && + grep "forced update" err ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && @@ -101,7 +103,8 @@ test_expect_success 'push to update (allowed, tracking)' ' ( cd dst && test_commit D && - git push --force-with-lease=master origin master + git push --force-with-lease=master origin master 2>err && + ! grep "forced update" err ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && @@ -114,7 +117,8 @@ test_expect_success 'push to update (allowed even though no-ff)' ' cd dst && git reset --hard HEAD^ && test_commit D && - git push --force-with-lease=master origin master + git push --force-with-lease=master origin master 2>err && + grep "forced update" err ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && @@ -147,7 +151,8 @@ test_expect_success 'push to delete (allowed)' ' setup_srcdst_basic && ( cd dst && - git push --force-with-lease=master origin :master + git push --force-with-lease=master origin :master 2>err && + grep deleted err ) && >expect && git ls-remote src refs/heads/master >actual && diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index aa73eeaef8..9fafcf1945 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -44,10 +44,6 @@ POST() { test_cmp exp act } -log_div() { - return 0 -} - . "$TEST_DIRECTORY"/t556x_common expect_aliased() { diff --git a/t/t5561-http-backend.sh b/t/t5561-http-backend.sh index 19afe96698..90e0d6f0fe 100755 --- a/t/t5561-http-backend.sh +++ b/t/t5561-http-backend.sh @@ -29,15 +29,9 @@ POST() { test_cmp exp act } -log_div() { - echo >>"$HTTPD_ROOT_PATH"/access.log - echo "### $1" >>"$HTTPD_ROOT_PATH"/access.log - echo "###" >>"$HTTPD_ROOT_PATH"/access.log -} - . "$TEST_DIRECTORY"/t556x_common -cat >exp <<EOF +grep '^[^#]' >exp <<EOF ### refs/heads/master ### diff --git a/t/t556x_common b/t/t556x_common index 82926cfdb7..359fcfe32b 100755 --- a/t/t556x_common +++ b/t/t556x_common @@ -52,21 +52,17 @@ get_static_files() { SMART=smart GIT_HTTP_EXPORT_ALL=1 && export GIT_HTTP_EXPORT_ALL test_expect_success 'direct refs/heads/master not found' ' - log_div "refs/heads/master" && GET refs/heads/master "404 Not Found" ' test_expect_success 'static file is ok' ' - log_div "getanyfile default" && get_static_files "200 OK" ' SMART=smart_noexport unset GIT_HTTP_EXPORT_ALL test_expect_success 'no export by default' ' - log_div "no git-daemon-export-ok" && get_static_files "404 Not Found" ' test_expect_success 'export if git-daemon-export-ok' ' - log_div "git-daemon-export-ok" && (cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && touch git-daemon-export-ok ) && @@ -75,47 +71,39 @@ test_expect_success 'export if git-daemon-export-ok' ' SMART=smart GIT_HTTP_EXPORT_ALL=1 && export GIT_HTTP_EXPORT_ALL test_expect_success 'static file if http.getanyfile true is ok' ' - log_div "getanyfile true" && config http.getanyfile true && get_static_files "200 OK" ' test_expect_success 'static file if http.getanyfile false fails' ' - log_div "getanyfile false" && config http.getanyfile false && get_static_files "403 Forbidden" ' test_expect_success 'http.uploadpack default enabled' ' - log_div "uploadpack default" && GET info/refs?service=git-upload-pack "200 OK" && POST git-upload-pack 0000 "200 OK" ' test_expect_success 'http.uploadpack true' ' - log_div "uploadpack true" && config http.uploadpack true && GET info/refs?service=git-upload-pack "200 OK" && POST git-upload-pack 0000 "200 OK" ' test_expect_success 'http.uploadpack false' ' - log_div "uploadpack false" && config http.uploadpack false && GET info/refs?service=git-upload-pack "403 Forbidden" && POST git-upload-pack 0000 "403 Forbidden" ' test_expect_success 'http.receivepack default disabled' ' - log_div "receivepack default" && GET info/refs?service=git-receive-pack "403 Forbidden" && POST git-receive-pack 0000 "403 Forbidden" ' test_expect_success 'http.receivepack true' ' - log_div "receivepack true" && config http.receivepack true && GET info/refs?service=git-receive-pack "200 OK" && POST git-receive-pack 0000 "200 OK" ' test_expect_success 'http.receivepack false' ' - log_div "receivepack false" && config http.receivepack false && GET info/refs?service=git-receive-pack "403 Forbidden" && POST git-receive-pack 0000 "403 Forbidden" diff --git a/t/t5571-pre-push-hook.sh b/t/t5571-pre-push-hook.sh index 6f9916a390..ba975bb355 100755 --- a/t/t5571-pre-push-hook.sh +++ b/t/t5571-pre-push-hook.sh @@ -109,23 +109,20 @@ test_expect_success 'push to URL' ' 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_expect_success 'set up many-ref tests' ' + { + nr=1000 + while test $nr -lt 2000 + do + nr=$(( $nr + 1 )) + echo "create refs/heads/b/$nr $COMMIT3" + done + } | git update-ref --stdin +' + +test_expect_success 'sigpipe does not cause pre-push hook failure' ' + echo "exit 0" | write_script "$HOOK" && + git push parent1 "refs/heads/b/*:refs/heads/b/*" +' test_done diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index bfdaf75966..9b34f3c615 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -496,4 +496,11 @@ test_expect_success 'shallow clone locally' ' ( cd ddsstt && git fsck ) ' +test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' ' + rm -rf dst.git && + GIT_TRACE_PACKFILE=$PWD/tmp.pack git clone --no-local --bare src dst.git && + git init --bare replay.git && + git -C replay.git index-pack -v --stdin <tmp.pack +' + test_done diff --git a/t/t5603-clone-dirname.sh b/t/t5603-clone-dirname.sh new file mode 100755 index 0000000000..d5af758129 --- /dev/null +++ b/t/t5603-clone-dirname.sh @@ -0,0 +1,106 @@ +#!/bin/sh + +test_description='check output directory names used by git-clone' +. ./test-lib.sh + +# we use a fake ssh wrapper that ignores the arguments +# entirely; we really only care that we get _some_ repo, +# as the real test is what clone does on the local side +test_expect_success 'setup ssh wrapper' ' + write_script "$TRASH_DIRECTORY/ssh-wrapper" <<-\EOF && + git upload-pack "$TRASH_DIRECTORY" + EOF + GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper" && + export GIT_SSH && + export TRASH_DIRECTORY +' + +# make sure that cloning $1 results in local directory $2 +test_clone_dir () { + url=$1; shift + dir=$1; shift + expect=success + bare=non-bare + clone_opts= + for i in "$@" + do + case "$i" in + fail) + expect=failure + ;; + bare) + bare=bare + clone_opts=--bare + ;; + esac + done + test_expect_$expect "clone of $url goes to $dir ($bare)" " + rm -rf $dir && + git clone $clone_opts $url && + test_path_is_dir $dir + " +} + +# basic syntax with bare and non-bare variants +test_clone_dir host:foo foo +test_clone_dir host:foo foo.git bare +test_clone_dir host:foo.git foo +test_clone_dir host:foo.git foo.git bare +test_clone_dir host:foo/.git foo +test_clone_dir host:foo/.git foo.git bare + +# similar, but using ssh URL rather than host:path syntax +test_clone_dir ssh://host/foo foo +test_clone_dir ssh://host/foo foo.git bare +test_clone_dir ssh://host/foo.git foo +test_clone_dir ssh://host/foo.git foo.git bare +test_clone_dir ssh://host/foo/.git foo +test_clone_dir ssh://host/foo/.git foo.git bare + +# we should remove trailing slashes and .git suffixes +test_clone_dir ssh://host/foo/ foo +test_clone_dir ssh://host/foo/// foo +test_clone_dir ssh://host/foo/.git/ foo +test_clone_dir ssh://host/foo.git/ foo +test_clone_dir ssh://host/foo.git/// foo +test_clone_dir ssh://host/foo///.git/ foo +test_clone_dir ssh://host/foo/.git/// foo + +test_clone_dir host:foo/ foo +test_clone_dir host:foo/// foo +test_clone_dir host:foo.git/ foo +test_clone_dir host:foo/.git/ foo +test_clone_dir host:foo.git/// foo +test_clone_dir host:foo///.git/ foo +test_clone_dir host:foo/.git/// foo + +# omitting the path should default to the hostname +test_clone_dir ssh://host/ host +test_clone_dir ssh://host:1234/ host +test_clone_dir ssh://user@host/ host +test_clone_dir host:/ host + +# auth materials should be redacted +test_clone_dir ssh://user:password@host/ host +test_clone_dir ssh://user:password@host:1234/ host +test_clone_dir ssh://user:passw@rd@host:1234/ host +test_clone_dir user@host:/ host +test_clone_dir user:password@host:/ host +test_clone_dir user:passw@rd@host:/ host + +# auth-like material should not be dropped +test_clone_dir ssh://host/foo@bar foo@bar +test_clone_dir ssh://host/foo@bar.git foo@bar +test_clone_dir ssh://user:password@host/foo@bar foo@bar +test_clone_dir ssh://user:passw@rd@host/foo@bar.git foo@bar + +test_clone_dir host:/foo@bar foo@bar +test_clone_dir host:/foo@bar.git foo@bar +test_clone_dir user:password@host:/foo@bar foo@bar +test_clone_dir user:passw@rd@host:/foo@bar.git foo@bar + +# trailing port-like numbers should not be stripped for paths +test_clone_dir ssh://user:password@host/test:1234 1234 +test_clone_dir ssh://user:password@host/test:1234.git 1234 + +test_done diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh index 3e783fc450..dfa1bf79c5 100755 --- a/t/t5700-clone-reference.sh +++ b/t/t5700-clone-reference.sh @@ -10,49 +10,51 @@ base_dir=`pwd` U=$base_dir/UPLOAD_LOG -test_expect_success 'preparing first repository' \ -'test_create_repo A && cd A && -echo first > file1 && -git add file1 && -git commit -m initial' - -cd "$base_dir" - -test_expect_success 'preparing second repository' \ -'git clone A B && cd B && -echo second > file2 && -git add file2 && -git commit -m addition && -git repack -a -d && -git prune' - -cd "$base_dir" - -test_expect_success 'cloning with reference (-l -s)' \ -'git clone -l -s --reference B A C' - -cd "$base_dir" - -test_expect_success 'existence of info/alternates' \ -'test_line_count = 2 C/.git/objects/info/alternates' - -cd "$base_dir" +# create a commit in repo $1 with name $2 +commit_in () { + ( + cd "$1" && + echo "$2" >"$2" && + git add "$2" && + git commit -m "$2" + ) +} + +# check that there are $2 loose objects in repo $1 +test_objcount () { + echo "$2" >expect && + git -C "$1" count-objects >actual.raw && + cut -d' ' -f1 <actual.raw >actual && + test_cmp expect actual +} + +test_expect_success 'preparing first repository' ' + test_create_repo A && + commit_in A file1 +' -test_expect_success 'pulling from reference' \ -'cd C && -git pull ../B master' +test_expect_success 'preparing second repository' ' + git clone A B && + commit_in B file2 && + git -C B repack -ad && + git -C B prune +' -cd "$base_dir" +test_expect_success 'cloning with reference (-l -s)' ' + git clone -l -s --reference B A C +' -test_expect_success 'that reference gets used' \ -'cd C && -echo "0 objects, 0 kilobytes" > expected && -git count-objects > current && -test_cmp expected current' +test_expect_success 'existence of info/alternates' ' + test_line_count = 2 C/.git/objects/info/alternates +' -cd "$base_dir" +test_expect_success 'pulling from reference' ' + git -C C pull ../B master +' -rm -f "$U.D" +test_expect_success 'that reference gets used' ' + test_objcount C 0 +' test_expect_success 'cloning with reference (no -l -s)' ' GIT_TRACE_PACKET=$U.D git clone --reference B "file://$(pwd)/A" D @@ -63,95 +65,69 @@ test_expect_success 'fetched no objects' ' ! grep " want" "$U.D" ' -cd "$base_dir" - -test_expect_success 'existence of info/alternates' \ -'test_line_count = 1 D/.git/objects/info/alternates' - -cd "$base_dir" - -test_expect_success 'pulling from reference' \ -'cd D && git pull ../B master' - -cd "$base_dir" - -test_expect_success 'that reference gets used' \ -'cd D && echo "0 objects, 0 kilobytes" > expected && -git count-objects > current && -test_cmp expected current' - -cd "$base_dir" +test_expect_success 'existence of info/alternates' ' + test_line_count = 1 D/.git/objects/info/alternates +' -test_expect_success 'updating origin' \ -'cd A && -echo third > file3 && -git add file3 && -git commit -m update && -git repack -a -d && -git prune' +test_expect_success 'pulling from reference' ' + git -C D pull ../B master +' -cd "$base_dir" +test_expect_success 'that reference gets used' ' + test_objcount D 0 +' -test_expect_success 'pulling changes from origin' \ -'cd C && -git pull origin' +test_expect_success 'updating origin' ' + commit_in A file3 && + git -C A repack -ad && + git -C A prune +' -cd "$base_dir" +test_expect_success 'pulling changes from origin' ' + git -C C pull origin +' # the 2 local objects are commit and tree from the merge -test_expect_success 'that alternate to origin gets used' \ -'cd C && -echo "2 objects" > expected && -git count-objects | cut -d, -f1 > current && -test_cmp expected current' - -cd "$base_dir" - -test_expect_success 'pulling changes from origin' \ -'cd D && -git pull origin' +test_expect_success 'that alternate to origin gets used' ' + test_objcount C 2 +' -cd "$base_dir" +test_expect_success 'pulling changes from origin' ' + git -C D pull origin +' # the 5 local objects are expected; file3 blob, commit in A to add it # and its tree, and 2 are our tree and the merge commit. -test_expect_success 'check objects expected to exist locally' \ -'cd D && -echo "5 objects" > expected && -git count-objects | cut -d, -f1 > current && -test_cmp expected current' - -cd "$base_dir" - -test_expect_success 'preparing alternate repository #1' \ -'test_create_repo F && cd F && -echo first > file1 && -git add file1 && -git commit -m initial' - -cd "$base_dir" - -test_expect_success 'cloning alternate repo #2 and adding changes to repo #1' \ -'git clone F G && cd F && -echo second > file2 && -git add file2 && -git commit -m addition' +test_expect_success 'check objects expected to exist locally' ' + test_objcount D 5 +' -cd "$base_dir" +test_expect_success 'preparing alternate repository #1' ' + test_create_repo F && + commit_in F file1 +' -test_expect_success 'cloning alternate repo #1, using #2 as reference' \ -'git clone --reference G F H' +test_expect_success 'cloning alternate repo #2 and adding changes to repo #1' ' + git clone F G && + commit_in F file2 +' -cd "$base_dir" +test_expect_success 'cloning alternate repo #1, using #2 as reference' ' + git clone --reference G F H +' -test_expect_success 'cloning with reference being subset of source (-l -s)' \ -'git clone -l -s --reference A B E' +test_expect_success 'cloning with reference being subset of source (-l -s)' ' + git clone -l -s --reference A B E +' -cd "$base_dir" +test_expect_success 'cloning with multiple references drops duplicates' ' + git clone -s --reference B --reference A --reference B A dups && + test_line_count = 2 dups/.git/objects/info/alternates +' test_expect_success 'clone with reference from a tagged repository' ' ( - cd A && git tag -a -m 'tagged' HEAD + cd A && git tag -a -m tagged HEAD ) && git clone --reference=A A I ' @@ -168,8 +144,6 @@ test_expect_success 'prepare branched repository' ' ) ' -rm -f "$U.K" - test_expect_success 'fetch with incomplete alternates' ' git init K && echo "$base_dir/A/.git/objects" >K/.git/objects/info/alternates && @@ -214,5 +188,37 @@ test_expect_success 'clone and dissociate from reference' ' test_must_fail git -C R fsck && git -C S fsck ' +test_expect_success 'clone, dissociate from partial reference and repack' ' + rm -fr P Q R && + git init P && + ( + cd P && + test_commit one && + git repack && + test_commit two && + git repack + ) && + git clone --bare P Q && + ( + cd P && + git checkout -b second && + test_commit three && + git repack + ) && + git clone --bare --dissociate --reference=P Q R && + ls R/objects/pack/*.pack >packs.txt && + test_line_count = 1 packs.txt +' + +test_expect_success 'clone, dissociate from alternates' ' + rm -fr A B C && + test_create_repo A && + commit_in A file1 && + git clone --reference=A A B && + test_line_count = 1 B/.git/objects/info/alternates && + git clone --local --dissociate B C && + ! test -f C/.git/objects/info/alternates && + ( cd C && git fsck ) +' test_done diff --git a/t/t5801-remote-helpers.sh b/t/t5801-remote-helpers.sh index c9d3ed14c3..362b1581e0 100755 --- a/t/t5801-remote-helpers.sh +++ b/t/t5801-remote-helpers.sh @@ -242,13 +242,6 @@ clean_mark () { sort >$(basename "$1") } -cmp_marks () { - test_when_finished "rm -rf git.marks testgit.marks" && - clean_mark ".git/testgit/$1/git.marks" && - clean_mark ".git/testgit/$1/testgit.marks" && - test_cmp git.marks testgit.marks -} - test_expect_success 'proper failure checks for fetching' ' (cd local && test_must_fail env GIT_REMOTE_TESTGIT_FAILURE=1 git fetch 2>error && @@ -258,12 +251,15 @@ test_expect_success 'proper failure checks for fetching' ' ' test_expect_success 'proper failure checks for pushing' ' + test_when_finished "rm -rf local/git.marks local/testgit.marks" && (cd local && git checkout -b crash master && echo crash >>file && git commit -a -m crash && test_must_fail env GIT_REMOTE_TESTGIT_FAILURE=1 git push --all && - cmp_marks origin + clean_mark ".git/testgit/origin/git.marks" && + clean_mark ".git/testgit/origin/testgit.marks" && + test_cmp git.marks testgit.marks ) ' diff --git a/t/t5802-connect-helper.sh b/t/t5802-connect-helper.sh index 878faf2b63..b7a7f9d588 100755 --- a/t/t5802-connect-helper.sh +++ b/t/t5802-connect-helper.sh @@ -69,4 +69,32 @@ test_expect_success 'update backfilled tag without primary transfer' ' test_cmp expect actual ' + +test_expect_success 'set up fake git-daemon' ' + mkdir remote && + git init --bare remote/one.git && + mkdir remote/host && + git init --bare remote/host/two.git && + write_script fake-daemon <<-\EOF && + git daemon --inetd \ + --informative-errors \ + --export-all \ + --base-path="$TRASH_DIRECTORY/remote" \ + --interpolated-path="$TRASH_DIRECTORY/remote/%H%D" \ + "$TRASH_DIRECTORY/remote" + EOF + export TRASH_DIRECTORY && + PATH=$TRASH_DIRECTORY:$PATH +' + +test_expect_success 'ext command can connect to git daemon (no vhost)' ' + rm -rf dst && + git clone "ext::fake-daemon %G/one.git" dst +' + +test_expect_success 'ext command can connect to git daemon (vhost)' ' + rm -rf dst && + git clone "ext::fake-daemon %G/two.git %Vhost" dst +' + test_done diff --git a/t/t5813-proto-disable-ssh.sh b/t/t5813-proto-disable-ssh.sh index ad877d774a..a954ead8af 100755 --- a/t/t5813-proto-disable-ssh.sh +++ b/t/t5813-proto-disable-ssh.sh @@ -14,7 +14,7 @@ test_expect_success 'setup repository to clone' ' ' test_proto "host:path" ssh "remote:repo.git" -test_proto "ssh://" ssh "ssh://remote/$PWD/remote/repo.git" -test_proto "git+ssh://" ssh "git+ssh://remote/$PWD/remote/repo.git" +test_proto "ssh://" ssh "ssh://remote$PWD/remote/repo.git" +test_proto "git+ssh://" ssh "git+ssh://remote$PWD/remote/repo.git" test_done diff --git a/t/t6020-merge-df.sh b/t/t6020-merge-df.sh index 27c3d73961..2af1beec5f 100755 --- a/t/t6020-merge-df.sh +++ b/t/t6020-merge-df.sh @@ -24,7 +24,7 @@ test_expect_success 'prepare repository' ' ' test_expect_success 'Merge with d/f conflicts' ' - test_expect_code 1 git merge "merge msg" B master + test_expect_code 1 git merge -m "merge msg" master ' test_expect_success 'F/D conflict' ' diff --git a/t/t6021-merge-criss-cross.sh b/t/t6021-merge-criss-cross.sh index d15b313d4b..213deecab1 100755 --- a/t/t6021-merge-criss-cross.sh +++ b/t/t6021-merge-criss-cross.sh @@ -48,7 +48,7 @@ echo "1 " > file && git commit -m "C3" file && git branch C3 && -git merge "pre E3 merge" B A && +git merge -m "pre E3 merge" A && echo "1 2 3 changed in E3, branch B. New file size @@ -61,7 +61,7 @@ echo "1 " > file && git commit -m "E3" file && git checkout A && -git merge "pre D8 merge" A C3 && +git merge -m "pre D8 merge" C3 && echo "1 2 3 changed in C3, branch B @@ -73,7 +73,7 @@ echo "1 9" > file && git commit -m D8 file' -test_expect_success 'Criss-cross merge' 'git merge "final merge" A B' +test_expect_success 'Criss-cross merge' 'git merge -m "final merge" B' cat > file-expect <<EOF 1 diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh index 190ee903cf..20aee43f95 100755 --- a/t/t6023-merge-file.sh +++ b/t/t6023-merge-file.sh @@ -346,4 +346,17 @@ test_expect_success 'conflict at EOF without LF resolved by --union' \ printf "line1\nline2\nline3x\nline3y" >expect.txt && test_cmp expect.txt output.txt' +test_expect_success 'conflict sections match existing line endings' ' + printf "1\\r\\n2\\r\\n3" >crlf-orig.txt && + printf "1\\r\\n2\\r\\n4" >crlf-diff1.txt && + printf "1\\r\\n2\\r\\n5" >crlf-diff2.txt && + test_must_fail git -c core.eol=crlf merge-file -p \ + crlf-diff1.txt crlf-orig.txt crlf-diff2.txt >crlf.txt && + test $(tr "\015" Q <crlf.txt | grep "^[<=>].*Q$" | wc -l) = 3 && + test $(tr "\015" Q <crlf.txt | grep "[345]Q$" | wc -l) = 3 && + test_must_fail git -c core.eol=crlf merge-file -p \ + nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >nolf.txt && + test $(tr "\015" Q <nolf.txt | grep "^[<=>].*Q$" | wc -l) = 0 +' + test_done diff --git a/t/t6026-merge-attr.sh b/t/t6026-merge-attr.sh index 3c21938a68..04c0509c47 100755 --- a/t/t6026-merge-attr.sh +++ b/t/t6026-merge-attr.sh @@ -85,11 +85,12 @@ test_expect_success 'retry the merge with longer context' ' cat >./custom-merge <<\EOF #!/bin/sh -orig="$1" ours="$2" theirs="$3" exit="$4" +orig="$1" ours="$2" theirs="$3" exit="$4" path=$5 ( echo "orig is $orig" echo "ours is $ours" echo "theirs is $theirs" + echo "path is $path" echo "=== orig ===" cat "$orig" echo "=== ours ===" @@ -110,7 +111,7 @@ test_expect_success 'custom merge backend' ' git reset --hard anchor && git config --replace-all \ - merge.custom.driver "./custom-merge %O %A %B 0" && + merge.custom.driver "./custom-merge %O %A %B 0 %P" && git config --replace-all \ merge.custom.name "custom merge driver for testing" && @@ -121,7 +122,7 @@ test_expect_success 'custom merge backend' ' o=$(git unpack-file master^:text) && a=$(git unpack-file side^:text) && b=$(git unpack-file master:text) && - sh -c "./custom-merge $o $a $b 0" && + sh -c "./custom-merge $o $a $b 0 'text'" && sed -e 1,3d $a >check-2 && cmp check-1 check-2 && rm -f $o $a $b @@ -131,7 +132,7 @@ test_expect_success 'custom merge backend' ' git reset --hard anchor && git config --replace-all \ - merge.custom.driver "./custom-merge %O %A %B 1" && + merge.custom.driver "./custom-merge %O %A %B 1 %P" && git config --replace-all \ merge.custom.name "custom merge driver for testing" && @@ -148,9 +149,12 @@ test_expect_success 'custom merge backend' ' o=$(git unpack-file master^:text) && a=$(git unpack-file anchor:text) && b=$(git unpack-file master:text) && - sh -c "./custom-merge $o $a $b 0" && + sh -c "./custom-merge $o $a $b 0 'text'" && sed -e 1,3d $a >check-2 && cmp check-1 check-2 && + sed -e 1,3d -e 4q $a >check-3 && + echo "path is text" >expect && + cmp expect check-3 && rm -f $o $a $b ' diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 06b4868109..e74662ba5c 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -362,7 +362,7 @@ test_expect_success 'bisect starting with a detached HEAD' ' test_expect_success 'bisect errors out if bad and good are mistaken' ' git bisect reset && test_must_fail git bisect start $HASH2 $HASH4 2> rev_list_error && - grep "mistake good and bad" rev_list_error && + grep "mistook good and bad" rev_list_error && git bisect reset ' @@ -759,4 +759,139 @@ test_expect_success '"git bisect bad HEAD" behaves as "git bisect bad"' ' git bisect reset ' +test_expect_success 'bisect starts with only one new' ' + git bisect reset && + git bisect start && + git bisect new $HASH4 && + git bisect next +' + +test_expect_success 'bisect does not start with only one old' ' + git bisect reset && + git bisect start && + git bisect old $HASH1 && + test_must_fail git bisect next +' + +test_expect_success 'bisect start with one new and old' ' + git bisect reset && + git bisect start && + git bisect old $HASH1 && + git bisect new $HASH4 && + git bisect new && + git bisect new >bisect_result && + grep "$HASH2 is the first new commit" bisect_result && + git bisect log >log_to_replay.txt && + git bisect reset +' + +test_expect_success 'bisect replay with old and new' ' + git bisect replay log_to_replay.txt >bisect_result && + grep "$HASH2 is the first new commit" bisect_result && + git bisect reset +' + +test_expect_success 'bisect cannot mix old/new and good/bad' ' + git bisect start && + git bisect bad $HASH4 && + test_must_fail git bisect old $HASH1 +' + +test_expect_success 'bisect terms needs 0 or 1 argument' ' + git bisect reset && + test_must_fail git bisect terms only-one && + test_must_fail git bisect terms 1 2 && + test_must_fail git bisect terms 2>actual && + echo "no terms defined" >expected && + test_cmp expected actual +' + +test_expect_success 'bisect terms shows good/bad after start' ' + git bisect reset && + git bisect start HEAD $HASH1 && + git bisect terms --term-good >actual && + echo good >expected && + test_cmp expected actual && + git bisect terms --term-bad >actual && + echo bad >expected && + test_cmp expected actual +' + +test_expect_success 'bisect start with one term1 and term2' ' + git bisect reset && + git bisect start --term-old term2 --term-new term1 && + git bisect term2 $HASH1 && + git bisect term1 $HASH4 && + git bisect term1 && + git bisect term1 >bisect_result && + grep "$HASH2 is the first term1 commit" bisect_result && + git bisect log >log_to_replay.txt && + git bisect reset +' + +test_expect_success 'bisect replay with term1 and term2' ' + git bisect replay log_to_replay.txt >bisect_result && + grep "$HASH2 is the first term1 commit" bisect_result && + git bisect reset +' + +test_expect_success 'bisect start term1 term2' ' + git bisect reset && + git bisect start --term-new term1 --term-old term2 $HASH4 $HASH1 && + git bisect term1 && + git bisect term1 >bisect_result && + grep "$HASH2 is the first term1 commit" bisect_result && + git bisect log >log_to_replay.txt && + git bisect reset +' + +test_expect_success 'bisect cannot mix terms' ' + git bisect reset && + git bisect start --term-good term1 --term-bad term2 $HASH4 $HASH1 && + test_must_fail git bisect a && + test_must_fail git bisect b && + test_must_fail git bisect bad && + test_must_fail git bisect good && + test_must_fail git bisect new && + test_must_fail git bisect old +' + +test_expect_success 'bisect terms rejects invalid terms' ' + git bisect reset && + test_must_fail git bisect start --term-good invalid..term && + test_must_fail git bisect terms --term-bad invalid..term && + test_must_fail git bisect terms --term-good bad && + test_must_fail git bisect terms --term-good old && + test_must_fail git bisect terms --term-good skip && + test_must_fail git bisect terms --term-good reset && + test_path_is_missing .git/BISECT_TERMS +' + +test_expect_success 'bisect start --term-* does store terms' ' + git bisect reset && + git bisect start --term-bad=one --term-good=two && + git bisect terms >actual && + cat <<-EOF >expected && + Your current terms are two for the old state + and one for the new state. + EOF + test_cmp expected actual && + git bisect terms --term-bad >actual && + echo one >expected && + test_cmp expected actual && + git bisect terms --term-good >actual && + echo two >expected && + test_cmp expected actual +' + +test_expect_success 'bisect start takes options and revs in any order' ' + git bisect reset && + git bisect start --term-good one $HASH4 \ + --term-good two --term-bad bad-term \ + $HASH1 --term-good three -- && + (git bisect terms --term-bad && git bisect terms --term-good) >actual && + printf "%s\n%s\n" bad-term three >expected && + test_cmp expected actual +' + test_done diff --git a/t/t6031-merge-filemode.sh b/t/t6031-merge-filemode.sh new file mode 100755 index 0000000000..7d06461f13 --- /dev/null +++ b/t/t6031-merge-filemode.sh @@ -0,0 +1,100 @@ +#!/bin/sh + +test_description='merge: handle file mode' +. ./test-lib.sh + +test_expect_success 'set up mode change in one branch' ' + : >file1 && + git add file1 && + git commit -m initial && + git checkout -b a1 master && + : >dummy && + git add dummy && + git commit -m a && + git checkout -b b1 master && + test_chmod +x file1 && + git add file1 && + git commit -m b1 +' + +do_one_mode () { + strategy=$1 + us=$2 + them=$3 + test_expect_success "resolve single mode change ($strategy, $us)" ' + git checkout -f $us && + git merge -s $strategy $them && + git ls-files -s file1 | grep ^100755 + ' + + test_expect_success FILEMODE "verify executable bit on file ($strategy, $us)" ' + test -x file1 + ' +} + +do_one_mode recursive a1 b1 +do_one_mode recursive b1 a1 +do_one_mode resolve a1 b1 +do_one_mode resolve b1 a1 + +test_expect_success 'set up mode change in both branches' ' + git reset --hard HEAD && + git checkout -b a2 master && + : >file2 && + H=$(git hash-object file2) && + test_chmod +x file2 && + git commit -m a2 && + git checkout -b b2 master && + : >file2 && + git add file2 && + git commit -m b2 && + { + echo "100755 $H 2 file2" + echo "100644 $H 3 file2" + } >expect +' + +do_both_modes () { + strategy=$1 + test_expect_success "detect conflict on double mode change ($strategy)" ' + git reset --hard && + git checkout -f a2 && + test_must_fail git merge -s $strategy b2 && + git ls-files -u >actual && + test_cmp actual expect && + git ls-files -s file2 | grep ^100755 + ' + + test_expect_success FILEMODE "verify executable bit on file ($strategy)" ' + test -x file2 + ' +} + +# both sides are equivalent, so no need to run both ways +do_both_modes recursive +do_both_modes resolve + +test_expect_success 'set up delete/modechange scenario' ' + git reset --hard && + git checkout -b deletion master && + git rm file1 && + git commit -m deletion +' + +do_delete_modechange () { + strategy=$1 + us=$2 + them=$3 + test_expect_success "detect delete/modechange conflict ($strategy, $us)" ' + git reset --hard && + git checkout $us && + test_must_fail git merge -s $strategy $them + ' +} + +do_delete_modechange recursive b1 deletion +do_delete_modechange recursive deletion b1 +do_delete_modechange resolve b1 deletion +do_delete_modechange resolve deletion b1 + +test_done diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh deleted file mode 100755 index 6464a16a19..0000000000 --- a/t/t6031-merge-recursive.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/sh - -test_description='merge-recursive: handle file mode' -. ./test-lib.sh - -test_expect_success 'mode change in one branch: keep changed version' ' - : >file1 && - git add file1 && - git commit -m initial && - git checkout -b a1 master && - : >dummy && - git add dummy && - git commit -m a && - git checkout -b b1 master && - test_chmod +x file1 && - git add file1 && - git commit -m b1 && - git checkout a1 && - git merge-recursive master -- a1 b1 && - git ls-files -s file1 | grep ^100755 -' - -test_expect_success FILEMODE 'verify executable bit on file' ' - test -x file1 -' - -test_expect_success 'mode change in both branches: expect conflict' ' - git reset --hard HEAD && - git checkout -b a2 master && - : >file2 && - H=$(git hash-object file2) && - test_chmod +x file2 && - git commit -m a2 && - git checkout -b b2 master && - : >file2 && - git add file2 && - git commit -m b2 && - git checkout a2 && - ( - git merge-recursive master -- a2 b2 - test $? = 1 - ) && - git ls-files -u >actual && - ( - echo "100755 $H 2 file2" - echo "100644 $H 3 file2" - ) >expect && - test_cmp actual expect && - git ls-files -s file2 | grep ^100755 -' - -test_expect_success FILEMODE 'verify executable bit on file' ' - test -x file2 -' - -test_expect_success 'merging with triple rename across D/F conflict' ' - git reset --hard HEAD && - git checkout -b main && - git rm -rf . && - - echo "just a file" >sub1 && - mkdir -p sub2 && - echo content1 >sub2/file1 && - echo content2 >sub2/file2 && - echo content3 >sub2/file3 && - mkdir simple && - echo base >simple/bar && - git add -A && - test_tick && - git commit -m base && - - git checkout -b other && - echo more >>simple/bar && - test_tick && - git commit -a -m changesimplefile && - - git checkout main && - git rm sub1 && - git mv sub2 sub1 && - test_tick && - git commit -m changefiletodir && - - test_tick && - git merge other -' - -test_done diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index 4d5a25eedf..c630aba657 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -351,11 +351,15 @@ test_expect_success 'test --format long' ' test_cmp expected actual ' -test_expect_success 'setup a fake editor' ' - write_script fakeeditor <<-\EOF +test_expect_success 'setup fake editors' ' + write_script fakeeditor <<-\EOF && sed -e "s/A U Thor/A fake Thor/" "$1" >"$1.new" mv "$1.new" "$1" EOF + write_script failingfakeeditor <<-\EOF + ./fakeeditor "$@" + false + EOF ' test_expect_success '--edit with and without already replaced object' ' @@ -372,7 +376,7 @@ test_expect_success '--edit with and without already replaced object' ' test_expect_success '--edit and change nothing or command failed' ' git replace -d "$PARA3" && test_must_fail env GIT_EDITOR=true git replace --edit "$PARA3" && - test_must_fail env GIT_EDITOR="./fakeeditor;false" git replace --edit "$PARA3" && + test_must_fail env GIT_EDITOR="./failingfakeeditor" git replace --edit "$PARA3" && GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" && git replace -l | grep "$PARA3" && git cat-file commit "$PARA3" | grep "A fake Thor" diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index c0e5b2a627..85f269411c 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -113,6 +113,14 @@ check_describe A-3-* --long HEAD^^2 check_describe c-7-* --tags check_describe e-3-* --first-parent --tags +test_expect_success 'describe --contains defaults to HEAD without commit-ish' ' + echo "A^0" >expect && + git checkout A && + test_when_finished "git checkout -" && + git describe --contains >actual && + test_cmp expect actual +' + : >err.expect check_describe A --all A^0 test_expect_success 'no warning was displayed for A' ' diff --git a/t/t6133-pathspec-rev-dwim.sh b/t/t6133-pathspec-rev-dwim.sh new file mode 100755 index 0000000000..a290ffca0d --- /dev/null +++ b/t/t6133-pathspec-rev-dwim.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +test_description='test dwim of revs versus pathspecs in revision parser' +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit base && + echo content >"br[ack]ets" && + git add . && + test_tick && + git commit -m brackets +' + +test_expect_success 'non-rev wildcard dwims to pathspec' ' + git log -- "*.t" >expect && + git log "*.t" >actual && + test_cmp expect actual +' + +test_expect_success 'tree:path with metacharacters dwims to rev' ' + git show "HEAD:br[ack]ets" -- >expect && + git show "HEAD:br[ack]ets" >actual && + test_cmp expect actual +' + +test_expect_success '^{foo} with metacharacters dwims to rev' ' + git log "HEAD^{/b.*}" -- >expect && + git log "HEAD^{/b.*}" >actual && + test_cmp expect actual +' + +test_expect_success '@{foo} with metacharacters dwims to rev' ' + git log "HEAD@{now [or thereabouts]}" -- >expect && + git log "HEAD@{now [or thereabouts]}" >actual && + test_cmp expect actual +' + +test_expect_success ':/*.t from a subdir dwims to a pathspec' ' + mkdir subdir && + ( + cd subdir && + git log -- ":/*.t" >expect && + git log ":/*.t" >actual && + test_cmp expect actual + ) +' + +test_done diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index c66bf7981c..19a2823025 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -8,8 +8,8 @@ test_description='for-each-ref test' . ./test-lib.sh . "$TEST_DIRECTORY"/lib-gpg.sh -# Mon Jul 3 15:18:43 2006 +0000 -datestamp=1151939923 +# Mon Jul 3 23:18:43 2006 +0000 +datestamp=1151968723 setdate_and_increment () { GIT_COMMITTER_DATE="$datestamp +0200" datestamp=$(expr "$datestamp" + 1) @@ -28,7 +28,10 @@ test_expect_success setup ' git update-ref refs/remotes/origin/master master && git remote add origin nowhere && git config branch.master.remote origin && - git config branch.master.merge refs/heads/master + git config branch.master.merge refs/heads/master && + git remote add myfork elsewhere && + git config remote.pushdefault myfork && + git config push.default current ' test_atom() { @@ -46,10 +49,17 @@ test_atom() { } test_atom head refname refs/heads/master +test_atom head refname:short master +test_atom head refname:strip=1 heads/master +test_atom head refname:strip=2 master test_atom head upstream refs/remotes/origin/master +test_atom head upstream:short origin/master +test_atom head push refs/remotes/myfork/master +test_atom head push:short myfork/master test_atom head objecttype commit test_atom head objectsize 171 test_atom head objectname $(git rev-parse refs/heads/master) +test_atom head objectname:short $(git rev-parse --short refs/heads/master) test_atom head tree $(git rev-parse refs/heads/master^{tree}) test_atom head parent '' test_atom head numparent 0 @@ -57,21 +67,21 @@ 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 author 'A U Thor <author@example.com> 1151968724 +0200' test_atom head authorname 'A U Thor' test_atom head authoremail '<author@example.com>' -test_atom head authordate 'Mon Jul 3 17:18:44 2006 +0200' -test_atom head committer 'C O Mitter <committer@example.com> 1151939923 +0200' +test_atom head authordate 'Tue Jul 4 01:18:44 2006 +0200' +test_atom head committer 'C O Mitter <committer@example.com> 1151968723 +0200' test_atom head committername 'C O Mitter' test_atom head committeremail '<committer@example.com>' -test_atom head committerdate 'Mon Jul 3 17:18:43 2006 +0200' +test_atom head committerdate 'Tue Jul 4 01:18:43 2006 +0200' test_atom head tag '' test_atom head tagger '' test_atom head taggername '' test_atom head taggeremail '' test_atom head taggerdate '' -test_atom head creator 'C O Mitter <committer@example.com> 1151939923 +0200' -test_atom head creatordate 'Mon Jul 3 17:18:43 2006 +0200' +test_atom head creator 'C O Mitter <committer@example.com> 1151968723 +0200' +test_atom head creatordate 'Tue Jul 4 01:18:43 2006 +0200' test_atom head subject 'Initial' test_atom head contents:subject 'Initial' test_atom head body '' @@ -82,16 +92,19 @@ test_atom head contents 'Initial test_atom head HEAD '*' test_atom tag refname refs/tags/testtag +test_atom tag refname:short testtag test_atom tag upstream '' +test_atom tag push '' test_atom tag objecttype tag test_atom tag objectsize 154 test_atom tag objectname $(git rev-parse refs/tags/testtag) +test_atom tag objectname:short $(git rev-parse --short refs/tags/testtag) test_atom tag tree '' test_atom tag parent '' test_atom tag numparent '' test_atom tag object $(git rev-parse refs/tags/testtag^0) test_atom tag type 'commit' -test_atom tag '*objectname' '67a36f10722846e891fbada1ba48ed035de75581' +test_atom tag '*objectname' 'ea122842f48be4afb2d1fc6a4b96c05885ab7463' test_atom tag '*objecttype' 'commit' test_atom tag author '' test_atom tag authorname '' @@ -102,18 +115,18 @@ test_atom tag committername '' test_atom tag committeremail '' test_atom tag committerdate '' test_atom tag tag 'testtag' -test_atom tag tagger 'C O Mitter <committer@example.com> 1151939925 +0200' +test_atom tag tagger 'C O Mitter <committer@example.com> 1151968725 +0200' test_atom tag taggername 'C O Mitter' test_atom tag taggeremail '<committer@example.com>' -test_atom tag taggerdate 'Mon Jul 3 17:18:45 2006 +0200' -test_atom tag creator 'C O Mitter <committer@example.com> 1151939925 +0200' -test_atom tag creatordate 'Mon Jul 3 17:18:45 2006 +0200' -test_atom tag subject 'Tagging at 1151939927' -test_atom tag contents:subject 'Tagging at 1151939927' +test_atom tag taggerdate 'Tue Jul 4 01:18:45 2006 +0200' +test_atom tag creator 'C O Mitter <committer@example.com> 1151968725 +0200' +test_atom tag creatordate 'Tue Jul 4 01:18:45 2006 +0200' +test_atom tag subject 'Tagging at 1151968727' +test_atom tag contents:subject 'Tagging at 1151968727' test_atom tag body '' test_atom tag contents:body '' test_atom tag contents:signature '' -test_atom tag contents 'Tagging at 1151939927 +test_atom tag contents 'Tagging at 1151968727 ' test_atom tag HEAD ' ' @@ -121,6 +134,16 @@ test_expect_success 'Check invalid atoms names are errors' ' test_must_fail git for-each-ref --format="%(INVALID)" refs/heads ' +test_expect_success 'arguments to :strip must be positive integers' ' + test_must_fail git for-each-ref --format="%(refname:strip=0)" && + test_must_fail git for-each-ref --format="%(refname:strip=-1)" && + test_must_fail git for-each-ref --format="%(refname:strip=foo)" +' + +test_expect_success 'stripping refnames too far gives an error' ' + test_must_fail git for-each-ref --format="%(refname:strip=3)" +' + test_expect_success 'Check format specifiers are ignored in naming date atoms' ' git for-each-ref --format="%(authordate)" refs/heads && git for-each-ref --format="%(authordate:default) %(authordate)" refs/heads && @@ -141,84 +164,130 @@ test_expect_success 'Check invalid format specifiers are errors' ' test_must_fail git for-each-ref --format="%(authordate:INVALID)" refs/heads ' -cat >expected <<\EOF -'refs/heads/master' 'Mon Jul 3 17:18:43 2006 +0200' 'Mon Jul 3 17:18:44 2006 +0200' -'refs/tags/testtag' 'Mon Jul 3 17:18:45 2006 +0200' -EOF +test_date () { + f=$1 && + committer_date=$2 && + author_date=$3 && + tagger_date=$4 && + cat >expected <<-EOF && + 'refs/heads/master' '$committer_date' '$author_date' + 'refs/tags/testtag' '$tagger_date' + EOF + ( + git for-each-ref --shell \ + --format="%(refname) %(committerdate${f:+:$f}) %(authordate${f:+:$f})" \ + refs/heads && + git for-each-ref --shell \ + --format="%(refname) %(taggerdate${f:+:$f})" \ + refs/tags + ) >actual && + test_cmp expected actual +} test_expect_success 'Check unformatted date fields output' ' - (git for-each-ref --shell --format="%(refname) %(committerdate) %(authordate)" refs/heads && - git for-each-ref --shell --format="%(refname) %(taggerdate)" refs/tags) >actual && - test_cmp expected actual + test_date "" \ + "Tue Jul 4 01:18:43 2006 +0200" \ + "Tue Jul 4 01:18:44 2006 +0200" \ + "Tue Jul 4 01:18:45 2006 +0200" ' test_expect_success 'Check format "default" formatted date fields output' ' - f=default && - (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads && - git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual && - test_cmp expected actual + test_date default \ + "Tue Jul 4 01:18:43 2006 +0200" \ + "Tue Jul 4 01:18:44 2006 +0200" \ + "Tue Jul 4 01:18:45 2006 +0200" +' + +test_expect_success 'Check format "default-local" date fields output' ' + test_date default-local "Mon Jul 3 23:18:43 2006" "Mon Jul 3 23:18:44 2006" "Mon Jul 3 23:18:45 2006" ' # Don't know how to do relative check because I can't know when this script # is going to be run and can't fake the current time to git, and hence can't # provide expected output. Instead, I'll just make sure that "relative" # doesn't exit in error -# -#cat >expected <<\EOF -# -#EOF -# test_expect_success 'Check format "relative" date fields output' ' f=relative && (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads && git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual ' -cat >expected <<\EOF -'refs/heads/master' '2006-07-03' '2006-07-03' -'refs/tags/testtag' '2006-07-03' -EOF +# We just check that this is the same as "relative" for now. +test_expect_success 'Check format "relative-local" date fields output' ' + test_date relative-local \ + "$(git for-each-ref --format="%(committerdate:relative)" refs/heads)" \ + "$(git for-each-ref --format="%(authordate:relative)" refs/heads)" \ + "$(git for-each-ref --format="%(taggerdate:relative)" refs/tags)" +' test_expect_success 'Check format "short" date fields output' ' - f=short && - (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads && - git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual && - test_cmp expected actual + test_date short 2006-07-04 2006-07-04 2006-07-04 ' -cat >expected <<\EOF -'refs/heads/master' 'Mon Jul 3 15:18:43 2006' 'Mon Jul 3 15:18:44 2006' -'refs/tags/testtag' 'Mon Jul 3 15:18:45 2006' -EOF +test_expect_success 'Check format "short-local" date fields output' ' + test_date short-local 2006-07-03 2006-07-03 2006-07-03 +' test_expect_success 'Check format "local" date fields output' ' - f=local && - (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads && - git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual && - test_cmp expected actual + test_date local \ + "Mon Jul 3 23:18:43 2006" \ + "Mon Jul 3 23:18:44 2006" \ + "Mon Jul 3 23:18:45 2006" ' -cat >expected <<\EOF -'refs/heads/master' '2006-07-03 17:18:43 +0200' '2006-07-03 17:18:44 +0200' -'refs/tags/testtag' '2006-07-03 17:18:45 +0200' -EOF - test_expect_success 'Check format "iso8601" date fields output' ' - f=iso8601 && - (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads && - git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual && - test_cmp expected actual + test_date iso8601 \ + "2006-07-04 01:18:43 +0200" \ + "2006-07-04 01:18:44 +0200" \ + "2006-07-04 01:18:45 +0200" ' -cat >expected <<\EOF -'refs/heads/master' 'Mon, 3 Jul 2006 17:18:43 +0200' 'Mon, 3 Jul 2006 17:18:44 +0200' -'refs/tags/testtag' 'Mon, 3 Jul 2006 17:18:45 +0200' -EOF +test_expect_success 'Check format "iso8601-local" date fields output' ' + test_date iso8601-local "2006-07-03 23:18:43 +0000" "2006-07-03 23:18:44 +0000" "2006-07-03 23:18:45 +0000" +' test_expect_success 'Check format "rfc2822" date fields output' ' - f=rfc2822 && - (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads && - git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual && + test_date rfc2822 \ + "Tue, 4 Jul 2006 01:18:43 +0200" \ + "Tue, 4 Jul 2006 01:18:44 +0200" \ + "Tue, 4 Jul 2006 01:18:45 +0200" +' + +test_expect_success 'Check format "rfc2822-local" date fields output' ' + test_date rfc2822-local "Mon, 3 Jul 2006 23:18:43 +0000" "Mon, 3 Jul 2006 23:18:44 +0000" "Mon, 3 Jul 2006 23:18:45 +0000" +' + +test_expect_success 'Check format "raw" date fields output' ' + test_date raw "1151968723 +0200" "1151968724 +0200" "1151968725 +0200" +' + +test_expect_success 'Check format "raw-local" date fields output' ' + test_date raw-local "1151968723 +0000" "1151968724 +0000" "1151968725 +0000" +' + +test_expect_success 'Check format of strftime date fields' ' + echo "my date is 2006-07-04" >expected && + git for-each-ref \ + --format="%(authordate:format:my date is %Y-%m-%d)" \ + refs/heads >actual && + test_cmp expected actual +' + +test_expect_success 'Check format of strftime-local date fields' ' + echo "my date is 2006-07-03" >expected && + git for-each-ref \ + --format="%(authordate:format-local:my date is %Y-%m-%d)" \ + refs/heads >actual && + test_cmp expected actual +' + +test_expect_success 'exercise strftime with odd fields' ' + echo >expected && + git for-each-ref --format="%(authordate:format:)" refs/heads >actual && + test_cmp expected actual && + long="long format -- $_z40$_z40$_z40$_z40$_z40$_z40$_z40" && + echo $long >expected && + git for-each-ref --format="%(authordate:format:$long)" refs/heads >actual && test_cmp expected actual ' @@ -287,47 +356,14 @@ for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do " done -cat >expected <<\EOF -master -testtag -EOF - -test_expect_success 'Check short refname format' ' - (git for-each-ref --format="%(refname:short)" refs/heads && - git for-each-ref --format="%(refname:short)" refs/tags) >actual && - test_cmp expected actual -' - -cat >expected <<EOF -origin/master -EOF - -test_expect_success 'Check short upstream format' ' - git for-each-ref --format="%(upstream:short)" refs/heads >actual && - 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_atom head upstream:track '[ahead 1]' +test_atom head upstream:trackshort '>' +test_atom head push:track '[ahead 1]' +test_atom head push:trackshort '>' 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 && @@ -347,15 +383,6 @@ test_expect_success 'Check that :track[short] works when upstream is invalid' ' test_cmp expected actual ' -cat >expected <<EOF -$(git rev-parse --short HEAD) -EOF - -test_expect_success 'Check short objectname format' ' - git for-each-ref --format="%(objectname:short)" refs/heads >actual && - test_cmp expected actual -' - test_expect_success 'Check for invalid refname format' ' test_must_fail git for-each-ref --format="%(refname:INVALID)" ' @@ -517,8 +544,8 @@ body contents $sig" 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 +$(git rev-parse refs/tags/master) <committer@example.com> refs/tags/master EOF test_expect_success 'Verify sort with multiple keys' ' diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh new file mode 100755 index 0000000000..fe4796cc9c --- /dev/null +++ b/t/t6302-for-each-ref-filter.sh @@ -0,0 +1,258 @@ +#!/bin/sh + +test_description='test for-each-refs usage of ref-filter APIs' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-gpg.sh + +if ! test_have_prereq GPG +then + skip_all="skipping for-each-ref tests, GPG not available" + test_done +fi + +test_expect_success 'setup some history and refs' ' + test_commit one && + test_commit two && + test_commit three && + git checkout -b side && + test_commit four && + git tag -s -m "A signed tag message" signed-tag && + git tag -s -m "Annonated doubly" double-tag signed-tag && + git checkout master && + git update-ref refs/odd/spot master +' + +test_expect_success 'filtering with --points-at' ' + cat >expect <<-\EOF && + refs/heads/master + refs/odd/spot + refs/tags/three + EOF + git for-each-ref --format="%(refname)" --points-at=master >actual && + test_cmp expect actual +' + +test_expect_success 'check signed tags with --points-at' ' + sed -e "s/Z$//" >expect <<-\EOF && + refs/heads/side Z + refs/tags/four Z + refs/tags/signed-tag four + EOF + git for-each-ref --format="%(refname) %(*subject)" --points-at=side >actual && + test_cmp expect actual +' + +test_expect_success 'filtering with --merged' ' + cat >expect <<-\EOF && + refs/heads/master + refs/odd/spot + refs/tags/one + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --merged=master >actual && + test_cmp expect actual +' + +test_expect_success 'filtering with --no-merged' ' + cat >expect <<-\EOF && + refs/heads/side + refs/tags/double-tag + refs/tags/four + refs/tags/signed-tag + EOF + git for-each-ref --format="%(refname)" --no-merged=master >actual && + test_cmp expect actual +' + +test_expect_success 'filtering with --contains' ' + cat >expect <<-\EOF && + refs/heads/master + refs/heads/side + refs/odd/spot + refs/tags/double-tag + refs/tags/four + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --contains=two >actual && + test_cmp expect actual +' + +test_expect_success '%(color) must fail' ' + test_must_fail git for-each-ref --format="%(color)%(refname)" +' + +test_expect_success 'left alignment is default' ' + cat >expect <<-\EOF && + refname is refs/heads/master |refs/heads/master + refname is refs/heads/side |refs/heads/side + refname is refs/odd/spot |refs/odd/spot + refname is refs/tags/double-tag|refs/tags/double-tag + refname is refs/tags/four |refs/tags/four + refname is refs/tags/one |refs/tags/one + refname is refs/tags/signed-tag|refs/tags/signed-tag + refname is refs/tags/three |refs/tags/three + refname is refs/tags/two |refs/tags/two + EOF + git for-each-ref --format="%(align:30)refname is %(refname)%(end)|%(refname)" >actual && + test_cmp expect actual +' + +test_expect_success 'middle alignment' ' + cat >expect <<-\EOF && + | refname is refs/heads/master |refs/heads/master + | refname is refs/heads/side |refs/heads/side + | refname is refs/odd/spot |refs/odd/spot + |refname is refs/tags/double-tag|refs/tags/double-tag + | refname is refs/tags/four |refs/tags/four + | refname is refs/tags/one |refs/tags/one + |refname is refs/tags/signed-tag|refs/tags/signed-tag + | refname is refs/tags/three |refs/tags/three + | refname is refs/tags/two |refs/tags/two + EOF + git for-each-ref --format="|%(align:middle,30)refname is %(refname)%(end)|%(refname)" >actual && + test_cmp expect actual +' + +test_expect_success 'right alignment' ' + cat >expect <<-\EOF && + | refname is refs/heads/master|refs/heads/master + | refname is refs/heads/side|refs/heads/side + | refname is refs/odd/spot|refs/odd/spot + |refname is refs/tags/double-tag|refs/tags/double-tag + | refname is refs/tags/four|refs/tags/four + | refname is refs/tags/one|refs/tags/one + |refname is refs/tags/signed-tag|refs/tags/signed-tag + | refname is refs/tags/three|refs/tags/three + | refname is refs/tags/two|refs/tags/two + EOF + git for-each-ref --format="|%(align:30,right)refname is %(refname)%(end)|%(refname)" >actual && + test_cmp expect actual +' + +# Individual atoms inside %(align:...) and %(end) must not be quoted. + +test_expect_success 'alignment with format quote' " + cat >expect <<-\EOF && + |' '\''master| A U Thor'\'' '| + |' '\''side| A U Thor'\'' '| + |' '\''odd/spot| A U Thor'\'' '| + |' '\''double-tag| '\'' '| + |' '\''four| A U Thor'\'' '| + |' '\''one| A U Thor'\'' '| + |' '\''signed-tag| '\'' '| + |' '\''three| A U Thor'\'' '| + |' '\''two| A U Thor'\'' '| + EOF + git for-each-ref --shell --format=\"|%(align:30,middle)'%(refname:short)| %(authorname)'%(end)|\" >actual && + test_cmp expect actual +" + +test_expect_success 'nested alignment with quote formatting' " + cat >expect <<-\EOF && + |' master '| + |' side '| + |' odd/spot '| + |' double-tag '| + |' four '| + |' one '| + |' signed-tag '| + |' three '| + |' two '| + EOF + git for-each-ref --shell --format='|%(align:30,left)%(align:15,right)%(refname:short)%(end)%(end)|' >actual && + test_cmp expect actual +" + +test_expect_success 'check `%(contents:lines=1)`' ' + cat >expect <<-\EOF && + master |three + side |four + odd/spot |three + double-tag |Annonated doubly + four |four + one |one + signed-tag |A signed tag message + three |three + two |two + EOF + git for-each-ref --format="%(refname:short) |%(contents:lines=1)" >actual && + test_cmp expect actual +' + +test_expect_success 'check `%(contents:lines=0)`' ' + cat >expect <<-\EOF && + master | + side | + odd/spot | + double-tag | + four | + one | + signed-tag | + three | + two | + EOF + git for-each-ref --format="%(refname:short) |%(contents:lines=0)" >actual && + test_cmp expect actual +' + +test_expect_success 'check `%(contents:lines=99999)`' ' + cat >expect <<-\EOF && + master |three + side |four + odd/spot |three + double-tag |Annonated doubly + four |four + one |one + signed-tag |A signed tag message + three |three + two |two + EOF + git for-each-ref --format="%(refname:short) |%(contents:lines=99999)" >actual && + test_cmp expect actual +' + +test_expect_success '`%(contents:lines=-1)` should fail' ' + test_must_fail git for-each-ref --format="%(refname:short) |%(contents:lines=-1)" +' + +test_expect_success 'setup for version sort' ' + test_commit foo1.3 && + test_commit foo1.6 && + test_commit foo1.10 +' + +test_expect_success 'version sort' ' + git for-each-ref --sort=version:refname --format="%(refname:short)" refs/tags/ | grep "foo" >actual && + cat >expect <<-\EOF && + foo1.3 + foo1.6 + foo1.10 + EOF + test_cmp expect actual +' + +test_expect_success 'version sort (shortened)' ' + git for-each-ref --sort=v:refname --format="%(refname:short)" refs/tags/ | grep "foo" >actual && + cat >expect <<-\EOF && + foo1.3 + foo1.6 + foo1.10 + EOF + test_cmp expect actual +' + +test_expect_success 'reverse version sort' ' + git for-each-ref --sort=-version:refname --format="%(refname:short)" refs/tags/ | grep "foo" >actual && + cat >expect <<-\EOF && + foo1.10 + foo1.6 + foo1.3 + EOF + test_cmp expect actual +' + +test_done diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index 63194d819e..5d7d414617 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -30,4 +30,17 @@ test_expect_success 'gc -h with invalid configuration' ' test_i18ngrep "[Uu]sage" broken/usage ' +test_expect_success 'gc is not aborted due to a stale symref' ' + git init remote && + ( + cd remote && + test_commit initial && + git clone . ../client && + git branch -m develop && + cd ../client && + git fetch --prune && + git gc + ) +' + test_done diff --git a/t/t6501-freshen-objects.sh b/t/t6501-freshen-objects.sh index 2adf825076..cf076dcd94 100755 --- a/t/t6501-freshen-objects.sh +++ b/t/t6501-freshen-objects.sh @@ -56,7 +56,7 @@ for repack in '' true; do test_expect_success "disable reflogs ($title)" ' git config core.logallrefupdates false && - rm -rf .git/logs + git reflog expire --expire=all --all ' test_expect_success "setup basic history ($title)" ' diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 855afda80a..edb834187a 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -2,6 +2,7 @@ test_description='git filter-branch' . ./test-lib.sh +. "$TEST_DIRECTORY/lib-gpg.sh" test_expect_success 'setup' ' test_commit A && @@ -292,6 +293,19 @@ test_expect_success 'Tag name filtering strips gpg signature' ' test_cmp expect actual ' +test_expect_success GPG 'Filtering retains message of gpg signed commit' ' + mkdir gpg && + touch gpg/foo && + git add gpg && + test_tick && + git commit -S -m "Adding gpg" && + + git log -1 --format="%s" > expect && + git filter-branch -f --msg-filter "cat" && + git log -1 --format="%s" > actual && + test_cmp expect actual +' + test_expect_success 'Tag name filtering allows slashes in tag names' ' git tag -m tag-with-slash X/1 && git cat-file tag X/1 | sed -e s,X/1,X/2, > expect && @@ -319,6 +333,14 @@ test_expect_success 'prune empty collapsed merges' ' test_cmp expect actual ' +test_expect_success 'prune empty works even without index/tree filters' ' + git rev-list HEAD >expect && + git commit --allow-empty -m empty && + git filter-branch -f --prune-empty HEAD && + git rev-list HEAD >actual && + test_cmp expect actual +' + test_expect_success '--remap-to-ancestor with filename filters' ' git checkout master && git reset --hard A && @@ -404,4 +426,11 @@ test_expect_success 'filter commit message without trailing newline' ' test_cmp expect actual ' +test_expect_success 'tree-filter deals with object name vs pathname ambiguity' ' + test_when_finished "git reset --hard original" && + ambiguous=$(git rev-list -1 HEAD) && + git filter-branch --tree-filter "mv file.t $ambiguous" HEAD^.. && + git show HEAD:$ambiguous +' + test_done diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index d1ff5c94f2..c64579fe15 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -51,7 +51,19 @@ test_expect_success 'creating a tag using default HEAD should succeed' ' echo foo >foo && git add foo && git commit -m Foo && - git tag mytag + git tag mytag && + test_must_fail git reflog exists refs/tags/mytag +' + +test_expect_success 'creating a tag with --create-reflog should create reflog' ' + test_when_finished "git tag -d tag_with_reflog" && + git tag --create-reflog tag_with_reflog && + git reflog exists refs/tags/tag_with_reflog +' + +test_expect_success '--create-reflog does not create reflog on failure' ' + test_must_fail git tag --create-reflog mytag && + test_must_fail git reflog exists refs/tags/mytag ' test_expect_success 'listing all tags if one exists should succeed' ' @@ -1450,13 +1462,7 @@ test_expect_success 'invalid sort parameter on command line' ' test_expect_success 'invalid sort parameter in configuratoin' ' git config tag.sort "v:notvalid" && - git tag -l "foo*" >actual && - cat >expect <<-\EOF && - foo1.10 - foo1.3 - foo1.6 - EOF - test_cmp expect actual + test_must_fail git tag -l "foo*" ' test_expect_success 'version sort with prerelease reordering' ' @@ -1513,4 +1519,51 @@ EOF" test_cmp expect actual ' +test_expect_success '--format should list tags as per format given' ' + cat >expect <<-\EOF && + refname : refs/tags/foo1.10 + refname : refs/tags/foo1.3 + refname : refs/tags/foo1.6 + refname : refs/tags/foo1.6-rc1 + refname : refs/tags/foo1.6-rc2 + EOF + git tag -l --format="refname : %(refname)" "foo*" >actual && + test_cmp expect actual +' + +test_expect_success 'setup --merged test tags' ' + git tag mergetest-1 HEAD~2 && + git tag mergetest-2 HEAD~1 && + git tag mergetest-3 HEAD +' + +test_expect_success '--merged cannot be used in non-list mode' ' + test_must_fail git tag --merged=mergetest-2 foo +' + +test_expect_success '--merged shows merged tags' ' + cat >expect <<-\EOF && + mergetest-1 + mergetest-2 + EOF + git tag -l --merged=mergetest-2 mergetest-* >actual && + test_cmp expect actual +' + +test_expect_success '--no-merged show unmerged tags' ' + cat >expect <<-\EOF && + mergetest-3 + EOF + git tag -l --no-merged=mergetest-2 mergetest-* >actual && + test_cmp expect actual +' + +test_expect_success 'ambiguous branch/tags not marked' ' + git tag ambiguous && + git branch ambiguous && + echo ambiguous >expect && + git tag -l ambiguous >actual && + test_cmp expect actual +' + test_done diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh index 947b690fd7..6ea7ac4c41 100755 --- a/t/t7006-pager.sh +++ b/t/t7006-pager.sh @@ -447,4 +447,13 @@ test_expect_success TTY 'external command pagers override sub-commands' ' test_cmp expect actual ' +test_expect_success 'command with underscores does not complain' ' + write_script git-under_score <<-\EOF && + echo ok + EOF + git --exec-path=. under_score >actual 2>&1 && + echo ok >expect && + test_cmp expect actual +' + test_done diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh new file mode 100755 index 0000000000..4608e71343 --- /dev/null +++ b/t/t7030-verify-tag.sh @@ -0,0 +1,115 @@ +#!/bin/sh + +test_description='signed tag tests' +. ./test-lib.sh +. "$TEST_DIRECTORY/lib-gpg.sh" + +test_expect_success GPG 'create signed tags' ' + echo 1 >file && git add file && + test_tick && git commit -m initial && + git tag -s -m initial initial && + git branch side && + + echo 2 >file && test_tick && git commit -a -m second && + git tag -s -m second second && + + git checkout side && + echo 3 >elif && git add elif && + test_tick && git commit -m "third on side" && + + git checkout master && + test_tick && git merge -S side && + git tag -s -m merge merge && + + echo 4 >file && test_tick && git commit -a -S -m "fourth unsigned" && + git tag -a -m fourth-unsigned fourth-unsigned && + + test_tick && git commit --amend -S -m "fourth signed" && + git tag -s -m fourth fourth-signed && + + echo 5 >file && test_tick && git commit -a -m "fifth" && + git tag fifth-unsigned && + + git config commit.gpgsign true && + echo 6 >file && test_tick && git commit -a -m "sixth" && + git tag -a -m sixth sixth-unsigned && + + test_tick && git rebase -f HEAD^^ && git tag -s -m 6th sixth-signed HEAD^ && + git tag -m seventh -s seventh-signed && + + echo 8 >file && test_tick && git commit -a -m eighth && + git tag -uB7227189 -m eighth eighth-signed-alt +' + +test_expect_success GPG 'verify and show signatures' ' + ( + for tag in initial second merge fourth-signed sixth-signed seventh-signed + do + git verify-tag $tag 2>actual && + grep "Good signature from" actual && + ! grep "BAD signature from" actual && + echo $tag OK || exit 1 + done + ) && + ( + for tag in fourth-unsigned fifth-unsigned sixth-unsigned + do + test_must_fail git verify-tag $tag 2>actual && + ! grep "Good signature from" actual && + ! grep "BAD signature from" actual && + echo $tag OK || exit 1 + done + ) && + ( + for tag in eighth-signed-alt + do + git verify-tag $tag 2>actual && + grep "Good signature from" actual && + ! grep "BAD signature from" actual && + grep "not certified" actual && + echo $tag OK || exit 1 + done + ) +' + +test_expect_success GPG 'detect fudged signature' ' + git cat-file tag seventh-signed >raw && + sed -e "s/seventh/7th forged/" raw >forged1 && + git hash-object -w -t tag forged1 >forged1.tag && + test_must_fail git verify-tag $(cat forged1.tag) 2>actual1 && + grep "BAD signature from" actual1 && + ! grep "Good signature from" actual1 +' + +test_expect_success GPG 'verify signatures with --raw' ' + ( + for tag in initial second merge fourth-signed sixth-signed seventh-signed + do + git verify-tag --raw $tag 2>actual && + grep "GOODSIG" actual && + ! grep "BADSIG" actual && + echo $tag OK || exit 1 + done + ) && + ( + for tag in fourth-unsigned fifth-unsigned sixth-unsigned + do + test_must_fail git verify-tag --raw $tag 2>actual && + ! grep "GOODSIG" actual && + ! grep "BADSIG" actual && + echo $tag OK || exit 1 + done + ) && + ( + for tag in eighth-signed-alt + do + git verify-tag --raw $tag 2>actual && + grep "GOODSIG" actual && + ! grep "BADSIG" actual && + grep "TRUST_UNDEFINED" actual && + echo $tag OK || exit 1 + done + ) +' + +test_done diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index 741ec08576..44bf1d84af 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -106,7 +106,7 @@ test_expect_success 'git diff-index --cached -M shows 2 added + 1 unmerged' ' A THREE A TWO EOF - git diff-index --cached --name-status HEAD >actual && + git diff-index --cached -M --name-status HEAD >actual && test_cmp expected actual ' @@ -213,5 +213,19 @@ EOF git checkout master ' +test_expect_success 'status --branch with detached HEAD' ' + git reset --hard && + git checkout master^0 && + git status --branch --porcelain >actual && + cat >expected <<-EOF && + ## HEAD (no branch) + ?? .gitconfig + ?? actual + ?? expect + ?? expected + ?? mdconflict/ + EOF + test_i18ncmp expected actual +' test_done diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh new file mode 100755 index 0000000000..0e8d0d42f2 --- /dev/null +++ b/t/t7063-status-untracked-cache.sh @@ -0,0 +1,574 @@ +#!/bin/sh + +test_description='test untracked cache' + +. ./test-lib.sh + +avoid_racy() { + sleep 1 +} + +# It's fine if git update-index returns an error code other than one, +# it'll be caught in the first test. +test_lazy_prereq UNTRACKED_CACHE ' + { git update-index --untracked-cache; ret=$?; } && + test $ret -ne 1 +' + +if ! test_have_prereq UNTRACKED_CACHE; then + skip_all='This system does not support untracked cache' + test_done +fi + +test_expect_success 'setup' ' + git init worktree && + cd worktree && + mkdir done dtwo dthree && + touch one two three done/one dtwo/two dthree/three && + git add one two done/one && + : >.git/info/exclude && + git update-index --untracked-cache +' + +test_expect_success 'untracked cache is empty' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 0000000000000000000000000000000000000000 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +EOF + test_cmp ../expect ../actual +' + +cat >../status.expect <<EOF && +A done/one +A one +A two +?? dthree/ +?? dtwo/ +?? three +EOF + +cat >../dump.expect <<EOF && +info/exclude e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ 0000000000000000000000000000000000000000 recurse valid +dthree/ +dtwo/ +three +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +three +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + +test_expect_success 'status first time (empty cache)' ' + avoid_racy && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 3 +gitignore invalidation: 1 +directory invalidation: 0 +opendir: 4 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'untracked cache after first status' ' + test-dump-untracked-cache >../actual && + test_cmp ../dump.expect ../actual +' + +test_expect_success 'status second time (fully populated cache)' ' + avoid_racy && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 0 +opendir: 0 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'untracked cache after second status' ' + test-dump-untracked-cache >../actual && + test_cmp ../dump.expect ../actual +' + +test_expect_success 'modify in root directory, one dir invalidation' ' + avoid_racy && + : >four && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + cat >../status.expect <<EOF && +A done/one +A one +A two +?? dthree/ +?? dtwo/ +?? four +?? three +EOF + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 1 +opendir: 1 +EOF + test_cmp ../trace.expect ../trace + +' + +test_expect_success 'verify untracked cache dump' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ 0000000000000000000000000000000000000000 recurse valid +dthree/ +dtwo/ +four +three +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +three +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'new .gitignore invalidates recursively' ' + avoid_racy && + echo four >.gitignore && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + cat >../status.expect <<EOF && +A done/one +A one +A two +?? .gitignore +?? dthree/ +?? dtwo/ +?? three +EOF + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 1 +directory invalidation: 1 +opendir: 4 +EOF + test_cmp ../trace.expect ../trace + +' + +test_expect_success 'verify untracked cache dump' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dthree/ +dtwo/ +three +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +three +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'new info/exclude invalidates everything' ' + avoid_racy && + echo three >>.git/info/exclude && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + cat >../status.expect <<EOF && +A done/one +A one +A two +?? .gitignore +?? dtwo/ +EOF + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 1 +directory invalidation: 0 +opendir: 4 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'verify untracked cache dump' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dtwo/ +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'move two from tracked to untracked' ' + git rm --cached two && + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'status after the move' ' + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + cat >../status.expect <<EOF && +A done/one +A one +?? .gitignore +?? dtwo/ +?? two +EOF + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 0 +opendir: 1 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'verify untracked cache dump' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dtwo/ +two +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'move two from untracked to tracked' ' + git add two && + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'status after the move' ' + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + cat >../status.expect <<EOF && +A done/one +A one +A two +?? .gitignore +?? dtwo/ +EOF + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 0 +opendir: 1 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'verify untracked cache dump' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dtwo/ +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'set up for sparse checkout testing' ' + echo two >done/.gitignore && + echo three >>done/.gitignore && + echo two >done/two && + git add -f done/two done/.gitignore && + git commit -m "first commit" +' + +test_expect_success 'status after commit' ' + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + cat >../status.expect <<EOF && +?? .gitignore +?? dtwo/ +EOF + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 0 +opendir: 2 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'untracked cache correct after commit' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dtwo/ +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'set up sparse checkout' ' + echo "done/[a-z]*" >.git/info/sparse-checkout && + test_config core.sparsecheckout true && + git checkout master && + git update-index --force-untracked-cache && + git status --porcelain >/dev/null && # prime the cache + test_path_is_missing done/.gitignore && + test_path_is_file done/one +' + +test_expect_success 'create/modify files, some of which are gitignored' ' + echo two bis >done/two && + echo three >done/three && # three is gitignored + echo four >done/four && # four is gitignored at a higher level + echo five >done/five && # five is not gitignored + echo test >base && #we need to ensure that the root dir is touched + rm base +' + +test_expect_success 'test sparse status with untracked cache' ' + : >../trace && + avoid_racy && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../status.actual && + cat >../status.expect <<EOF && + M done/two +?? .gitignore +?? done/five +?? dtwo/ +EOF + test_cmp ../status.expect ../status.actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 1 +directory invalidation: 2 +opendir: 2 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'untracked cache correct after status' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dtwo/ +/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid +five +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'test sparse status again with untracked cache' ' + avoid_racy && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../status.actual && + cat >../status.expect <<EOF && + M done/two +?? .gitignore +?? done/five +?? dtwo/ +EOF + test_cmp ../status.expect ../status.actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 0 +opendir: 0 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'set up for test of subdir and sparse checkouts' ' + mkdir done/sub && + mkdir done/sub/sub && + echo "sub" > done/sub/sub/file +' + +test_expect_success 'test sparse status with untracked cache and subdir' ' + avoid_racy && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../status.actual && + cat >../status.expect <<EOF && + M done/two +?? .gitignore +?? done/five +?? done/sub/ +?? dtwo/ +EOF + test_cmp ../status.expect ../status.actual && + cat >../trace.expect <<EOF && +node creation: 2 +gitignore invalidation: 0 +directory invalidation: 1 +opendir: 3 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'verify untracked cache dump (sparse/subdirs)' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dtwo/ +/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid +five +sub/ +/done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid +sub/ +/done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid +file +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'test sparse status again with untracked cache and subdir' ' + avoid_racy && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../status.actual && + test_cmp ../status.expect ../status.actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 0 +opendir: 0 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'move entry in subdir from untracked to cached' ' + git add dtwo/two && + git status --porcelain >../status.actual && + cat >../status.expect <<EOF && + M done/two +A dtwo/two +?? .gitignore +?? done/five +?? done/sub/ +EOF + test_cmp ../status.expect ../status.actual +' + +test_expect_success 'move entry in subdir from cached to untracked' ' + git rm --cached dtwo/two && + git status --porcelain >../status.actual && + cat >../status.expect <<EOF && + M done/two +?? .gitignore +?? done/five +?? done/sub/ +?? dtwo/ +EOF + test_cmp ../status.expect ../status.actual +' + +test_done diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 99be5d95d0..86ceb38b01 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -432,9 +432,7 @@ test_expect_success 'nested git work tree' ' ( cd foo && git init && - >hello.world - git add . && - git commit -a -m nested + test_commit nested hello.world ) && ( cd bar && @@ -443,9 +441,7 @@ test_expect_success 'nested git work tree' ' ( cd baz/boo && git init && - >deeper.world - git add . && - git commit -a -m deeply.nested + test_commit deeply.nested deeper.world ) && git clean -f -d && test -f foo/.git/index && @@ -455,15 +451,153 @@ test_expect_success 'nested git work tree' ' ! test -d bar ' +test_expect_success 'should clean things that almost look like git but are not' ' + rm -fr almost_git almost_bare_git almost_submodule && + mkdir -p almost_git/.git/objects && + mkdir -p almost_git/.git/refs && + cat >almost_git/.git/HEAD <<-\EOF && + garbage + EOF + cp -r almost_git/.git/ almost_bare_git && + mkdir almost_submodule/ && + cat >almost_submodule/.git <<-\EOF && + garbage + EOF + test_when_finished "rm -rf almost_*" && + git clean -f -d && + test_path_is_missing almost_git && + test_path_is_missing almost_bare_git && + test_path_is_missing almost_submodule +' + +test_expect_success 'should not clean submodules' ' + rm -fr repo to_clean sub1 sub2 && + mkdir repo to_clean && + ( + cd repo && + git init && + test_commit msg hello.world + ) && + git submodule add ./repo/.git sub1 && + git commit -m "sub1" && + git branch before_sub2 && + git submodule add ./repo/.git sub2 && + git commit -m "sub2" && + git checkout before_sub2 && + >to_clean/should_clean.this && + git clean -f -d && + test_path_is_file repo/.git/index && + test_path_is_file repo/hello.world && + test_path_is_file sub1/.git && + test_path_is_file sub1/hello.world && + test_path_is_file sub2/.git && + test_path_is_file sub2/hello.world && + test_path_is_missing to_clean +' + +test_expect_success POSIXPERM 'should avoid cleaning possible submodules' ' + rm -fr to_clean possible_sub1 && + mkdir to_clean possible_sub1 && + test_when_finished "rm -rf possible_sub*" && + echo "gitdir: foo" >possible_sub1/.git && + >possible_sub1/hello.world && + chmod 0 possible_sub1/.git && + >to_clean/should_clean.this && + git clean -f -d && + test_path_is_file possible_sub1/.git && + test_path_is_file possible_sub1/hello.world && + test_path_is_missing to_clean +' + +test_expect_success 'nested (empty) git should be kept' ' + rm -fr empty_repo to_clean && + git init empty_repo && + mkdir to_clean && + >to_clean/should_clean.this && + git clean -f -d && + test_path_is_file empty_repo/.git/HEAD && + test_path_is_missing to_clean +' + +test_expect_success 'nested bare repositories should be cleaned' ' + rm -fr bare1 bare2 subdir && + git init --bare bare1 && + git clone --local --bare . bare2 && + mkdir subdir && + cp -r bare2 subdir/bare3 && + git clean -f -d && + test_path_is_missing bare1 && + test_path_is_missing bare2 && + test_path_is_missing subdir +' + +test_expect_failure 'nested (empty) bare repositories should be cleaned even when in .git' ' + rm -fr strange_bare && + mkdir strange_bare && + git init --bare strange_bare/.git && + git clean -f -d && + test_path_is_missing strange_bare +' + +test_expect_failure 'nested (non-empty) bare repositories should be cleaned even when in .git' ' + rm -fr strange_bare && + mkdir strange_bare && + git clone --local --bare . strange_bare/.git && + git clean -f -d && + test_path_is_missing strange_bare +' + +test_expect_success 'giving path in nested git work tree will remove it' ' + rm -fr repo && + mkdir repo && + ( + cd repo && + git init && + mkdir -p bar/baz && + test_commit msg bar/baz/hello.world + ) && + git clean -f -d repo/bar/baz && + test_path_is_file repo/.git/HEAD && + test_path_is_dir repo/bar/ && + test_path_is_missing repo/bar/baz +' + +test_expect_success 'giving path to nested .git will not remove it' ' + rm -fr repo && + mkdir repo untracked && + ( + cd repo && + git init && + test_commit msg hello.world + ) && + git clean -f -d repo/.git && + test_path_is_file repo/.git/HEAD && + test_path_is_dir repo/.git/refs && + test_path_is_dir repo/.git/objects && + test_path_is_dir untracked/ +' + +test_expect_success 'giving path to nested .git/ will remove contents' ' + rm -fr repo untracked && + mkdir repo untracked && + ( + cd repo && + git init && + test_commit msg hello.world + ) && + git clean -f -d repo/.git/ && + test_path_is_dir repo/.git && + test_dir_is_empty repo/.git && + test_path_is_dir untracked/ +' + test_expect_success 'force removal of nested git work tree' ' rm -fr foo bar baz && mkdir -p foo bar baz/boo && ( cd foo && git init && - >hello.world - git add . && - git commit -a -m nested + test_commit nested hello.world ) && ( cd bar && @@ -472,9 +606,7 @@ test_expect_success 'force removal of nested git work tree' ' ( cd baz/boo && git init && - >deeper.world - git add . && - git commit -a -m deeply.nested + test_commit deeply.nested deeper.world ) && git clean -f -f -d && ! test -d foo && diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 540771ca41..be82a75e54 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -999,5 +999,30 @@ test_expect_success 'submodule add clone shallow submodule' ' ) ' +test_expect_success 'submodule helper list is not confused by common prefixes' ' + mkdir -p dir1/b && + ( + cd dir1/b && + git init && + echo hi >testfile2 && + git add . && + git commit -m "test1" + ) && + mkdir -p dir2/b && + ( + cd dir2/b && + git init && + echo hello >testfile1 && + git add . && + git commit -m "test2" + ) && + git submodule add /dir1/b dir1/b && + git submodule add /dir2/b dir2/b && + git commit -m "first submodule commit" && + git submodule--helper list dir1/b |cut -c51- >actual && + echo "dir1/b" >expect && + test_cmp expect actual +' + test_done diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-work-tree.sh index c20717181e..c20717181e 100755 --- a/t/t7409-submodule-detached-worktree.sh +++ b/t/t7409-submodule-detached-work-tree.sh diff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh new file mode 100755 index 0000000000..1acef32647 --- /dev/null +++ b/t/t7410-submodule-checkout-to.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +test_description='Combination of submodules and multiple workdirs' + +. ./test-lib.sh + +base_path=$(pwd -P) + +test_expect_success 'setup: make origin' \ + 'mkdir -p origin/sub && ( cd origin/sub && git init && + echo file1 >file1 && + git add file1 && + git commit -m file1 ) && + mkdir -p origin/main && ( cd origin/main && git init && + git submodule add ../sub && + git commit -m "add sub" ) && + ( cd origin/sub && + echo file1updated >file1 && + git add file1 && + git commit -m "file1 updated" ) && + ( cd origin/main/sub && git pull ) && + ( cd origin/main && + git add sub && + git commit -m "sub updated" )' + +test_expect_success 'setup: clone' \ + 'mkdir clone && ( cd clone && + git clone --recursive "$base_path/origin/main")' + +rev1_hash_main=$(git --git-dir=origin/main/.git show --pretty=format:%h -q "HEAD~1") +rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q "HEAD~1") + +test_expect_success 'checkout main' \ + 'mkdir default_checkout && + (cd clone/main && + git worktree add "$base_path/default_checkout/main" "$rev1_hash_main")' + +test_expect_failure 'can see submodule diffs just after checkout' \ + '(cd default_checkout/main && git diff --submodule master"^!" | grep "file1 updated")' + +test_expect_success 'checkout main and initialize independed clones' \ + 'mkdir fully_cloned_submodule && + (cd clone/main && + git worktree add "$base_path/fully_cloned_submodule/main" "$rev1_hash_main") && + (cd fully_cloned_submodule/main && git submodule update)' + +test_expect_success 'can see submodule diffs after independed cloning' \ + '(cd fully_cloned_submodule/main && git diff --submodule master"^!" | grep "file1 updated")' + +test_expect_success 'checkout sub manually' \ + 'mkdir linked_submodule && + (cd clone/main && + git worktree add "$base_path/linked_submodule/main" "$rev1_hash_main") && + (cd clone/main/sub && + git worktree add "$base_path/linked_submodule/main/sub" "$rev1_hash_sub")' + +test_expect_success 'can see submodule diffs after manual checkout of linked submodule' \ + '(cd linked_submodule/main && git diff --submodule master"^!" | grep "file1 updated")' + +test_done diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh new file mode 100755 index 0000000000..fc97c3314e --- /dev/null +++ b/t/t7411-submodule-config.sh @@ -0,0 +1,153 @@ +#!/bin/sh +# +# Copyright (c) 2014 Heiko Voigt +# + +test_description='Test submodules config cache infrastructure + +This test verifies that parsing .gitmodules configurations directly +from the database and from the worktree works. +' + +TEST_NO_CREATE_REPO=1 +. ./test-lib.sh + +test_expect_success 'submodule config cache setup' ' + mkdir submodule && + (cd submodule && + git init && + echo a >a && + git add . && + git commit -ma + ) && + mkdir super && + (cd super && + git init && + git submodule add ../submodule && + git submodule add ../submodule a && + git commit -m "add as submodule and as a" && + git mv a b && + git commit -m "move a to b" + ) +' + +cat >super/expect <<EOF +Submodule name: 'a' for path 'a' +Submodule name: 'a' for path 'b' +Submodule name: 'submodule' for path 'submodule' +Submodule name: 'submodule' for path 'submodule' +EOF + +test_expect_success 'test parsing and lookup of submodule config by path' ' + (cd super && + test-submodule-config \ + HEAD^ a \ + HEAD b \ + HEAD^ submodule \ + HEAD submodule \ + >actual && + test_cmp expect actual + ) +' + +test_expect_success 'test parsing and lookup of submodule config by name' ' + (cd super && + test-submodule-config --name \ + HEAD^ a \ + HEAD a \ + HEAD^ submodule \ + HEAD submodule \ + >actual && + test_cmp expect actual + ) +' + +cat >super/expect_error <<EOF +Submodule name: 'a' for path 'b' +Submodule name: 'submodule' for path 'submodule' +EOF + +test_expect_success 'error in one submodule config lets continue' ' + (cd super && + cp .gitmodules .gitmodules.bak && + echo " value = \"" >>.gitmodules && + git add .gitmodules && + mv .gitmodules.bak .gitmodules && + git commit -m "add error" && + test-submodule-config \ + HEAD b \ + HEAD submodule \ + >actual && + test_cmp expect_error actual + ) +' + +cat >super/expect_url <<EOF +Submodule url: 'git@somewhere.else.net:a.git' for path 'b' +Submodule url: 'git@somewhere.else.net:submodule.git' for path 'submodule' +EOF + +cat >super/expect_local_path <<EOF +Submodule name: 'a' for path 'c' +Submodule name: 'submodule' for path 'submodule' +EOF + +test_expect_success 'reading of local configuration' ' + (cd super && + old_a=$(git config submodule.a.url) && + old_submodule=$(git config submodule.submodule.url) && + git config submodule.a.url git@somewhere.else.net:a.git && + git config submodule.submodule.url git@somewhere.else.net:submodule.git && + test-submodule-config --url \ + "" b \ + "" submodule \ + >actual && + test_cmp expect_url actual && + git config submodule.a.path c && + test-submodule-config \ + "" c \ + "" submodule \ + >actual && + test_cmp expect_local_path actual && + git config submodule.a.url $old_a && + git config submodule.submodule.url $old_submodule && + git config --unset submodule.a.path c + ) +' + +cat >super/expect_fetchrecurse_die.err <<EOF +fatal: bad submodule.submodule.fetchrecursesubmodules argument: blabla +EOF + +test_expect_success 'local error in fetchrecursesubmodule dies early' ' + (cd super && + git config submodule.submodule.fetchrecursesubmodules blabla && + test_must_fail test-submodule-config \ + "" b \ + "" submodule \ + >actual.out 2>actual.err && + touch expect_fetchrecurse_die.out && + test_cmp expect_fetchrecurse_die.out actual.out && + test_cmp expect_fetchrecurse_die.err actual.err && + git config --unset submodule.submodule.fetchrecursesubmodules + ) +' + +test_expect_success 'error in history in fetchrecursesubmodule lets continue' ' + (cd super && + git config -f .gitmodules \ + submodule.submodule.fetchrecursesubmodules blabla && + git add .gitmodules && + git config --unset -f .gitmodules \ + submodule.submodule.fetchrecursesubmodules && + git commit -m "add error in fetchrecursesubmodules" && + test-submodule-config \ + HEAD b \ + HEAD submodule \ + >actual && + test_cmp expect_error actual && + git reset --hard HEAD^ + ) +' + +test_done diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index 31924b21a6..b39e313ac2 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -392,7 +392,7 @@ exit 0 EOF test_expect_success !AUTOIDENT 'do not fire editor when committer is bogus' ' - >.git/result + >.git/result && >expect && echo >>negative && diff --git a/t/t7509-commit.sh b/t/t7509-commit.sh index 9ac794052d..db9774e345 100755 --- a/t/t7509-commit.sh +++ b/t/t7509-commit.sh @@ -90,22 +90,10 @@ sha1_file() { remove_object() { rm -f $(sha1_file "$*") } -no_reflog() { - cp .git/config .git/config.saved && - echo "[core] logallrefupdates = false" >>.git/config && - test_when_finished "mv -f .git/config.saved .git/config" && - - if test -e .git/logs - then - mv .git/logs . && - test_when_finished "mv logs .git/" - fi -} test_expect_success '--amend option with empty author' ' git cat-file commit Initial >tmp && sed "s/author [^<]* </author </" tmp >empty-author && - no_reflog && sha=$(git hash-object -t commit -w empty-author) && test_when_finished "remove_object $sha" && git checkout $sha && @@ -119,7 +107,6 @@ test_expect_success '--amend option with empty author' ' test_expect_success '--amend option with missing author' ' git cat-file commit Initial >tmp && sed "s/author [^<]* </author </" tmp >malformed && - no_reflog && sha=$(git hash-object -t commit -w malformed) && test_when_finished "remove_object $sha" && git checkout $sha && diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh index 13331e533b..18e5cf0663 100755 --- a/t/t7510-signed-commit.sh +++ b/t/t7510-signed-commit.sh @@ -81,6 +81,44 @@ test_expect_success GPG 'verify and show signatures' ' ) ' +test_expect_success GPG 'verify-commit exits success on untrusted signature' ' + git verify-commit eighth-signed-alt 2>actual && + grep "Good signature from" actual && + ! grep "BAD signature from" actual && + grep "not certified" actual +' + +test_expect_success GPG 'verify signatures with --raw' ' + ( + for commit in initial second merge fourth-signed fifth-signed sixth-signed seventh-signed + do + git verify-commit --raw $commit 2>actual && + grep "GOODSIG" actual && + ! grep "BADSIG" actual && + echo $commit OK || exit 1 + done + ) && + ( + for commit in merge^2 fourth-unsigned sixth-unsigned seventh-unsigned + do + test_must_fail git verify-commit --raw $commit 2>actual && + ! grep "GOODSIG" actual && + ! grep "BADSIG" actual && + echo $commit OK || exit 1 + done + ) && + ( + for commit in eighth-signed-alt + do + git verify-commit --raw $commit 2>actual && + grep "GOODSIG" actual && + ! grep "BADSIG" actual && + grep "TRUST_UNDEFINED" actual && + echo $commit OK || exit 1 + done + ) +' + test_expect_success GPG 'show signed commit with signature' ' git show -s initial >commit && git show -s --show-signature initial >show && diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh index 68ad2d7454..49d19a3b36 100755 --- a/t/t7512-status-help.sh +++ b/t/t7512-status-help.sh @@ -134,9 +134,13 @@ 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) && + LAST_COMMIT=$(git rev-parse --short rebase_i_conflicts_second) && test_must_fail git rebase -i rebase_i_conflicts && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last command done (1 command done): + pick $LAST_COMMIT one_second +No commands remaining. 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) @@ -159,10 +163,14 @@ 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) && + LAST_COMMIT=$(git rev-parse --short rebase_i_conflicts_second) && test_must_fail git rebase -i rebase_i_conflicts && git add main.txt && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last command done (1 command done): + pick $LAST_COMMIT one_second +No commands remaining. You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''. (all conflicts fixed: run "git rebase --continue") @@ -183,14 +191,20 @@ test_expect_success 'status when rebasing -i in edit mode' ' git checkout -b rebase_i_edit && test_commit one_rebase_i main.txt one && test_commit two_rebase_i main.txt two && + COMMIT2=$(git rev-parse --short rebase_i_edit) && test_commit three_rebase_i main.txt three && + COMMIT3=$(git rev-parse --short rebase_i_edit) && 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 && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + pick $COMMIT2 two_rebase_i + edit $COMMIT3 three_rebase_i +No commands remaining. 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) @@ -207,8 +221,11 @@ test_expect_success 'status when splitting a commit' ' git checkout -b split_commit && test_commit one_split main.txt one && test_commit two_split main.txt two && + COMMIT2=$(git rev-parse --short split_commit) && test_commit three_split main.txt three && + COMMIT3=$(git rev-parse --short split_commit) && test_commit four_split main.txt four && + COMMIT4=$(git rev-parse --short split_commit) && FAKE_LINES="1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && @@ -216,7 +233,13 @@ test_expect_success 'status when splitting a commit' ' git rebase -i HEAD~3 && git reset HEAD^ && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + pick $COMMIT2 two_split + edit $COMMIT3 three_split +Next command to do (1 remaining command): + pick $COMMIT4 four_split + (use "git rebase --edit-todo" to view and edit) You are currently splitting a commit while rebasing branch '\''split_commit'\'' on '\''$ONTO'\''. (Once your working directory is clean, run "git rebase --continue") @@ -239,7 +262,9 @@ test_expect_success 'status after editing the last commit with --amend during a test_commit one_amend main.txt one && test_commit two_amend main.txt two && test_commit three_amend main.txt three && + COMMIT3=$(git rev-parse --short amend_last) && test_commit four_amend main.txt four && + COMMIT4=$(git rev-parse --short amend_last) && FAKE_LINES="1 2 edit 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && @@ -247,7 +272,12 @@ test_expect_success 'status after editing the last commit with --amend during a git rebase -i HEAD~3 && git commit --amend -m "foo" && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (3 commands done): + pick $COMMIT3 three_amend + edit $COMMIT4 four_amend + (see more in file .git/rebase-merge/done) +No commands remaining. 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) @@ -273,11 +303,20 @@ 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" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git rebase --continue && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) 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) @@ -294,12 +333,21 @@ 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" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git rebase --continue && git reset HEAD^ && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. (Once your working directory is clean, run "git rebase --continue") @@ -321,12 +369,21 @@ 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" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git rebase --continue && git commit --amend -m "foo" && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) 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) @@ -343,12 +400,21 @@ 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" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git commit --amend -m "a" && git rebase --continue && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) 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) @@ -366,12 +432,21 @@ test_expect_success 'status: (amend first edit) second edit and split' ' export FAKE_LINES && test_when_finished "git rebase --abort" && ONTO=$(git rev-parse --short HEAD~3) && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && git rebase -i HEAD~3 && git commit --amend -m "b" && git rebase --continue && git reset HEAD^ && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. (Once your working directory is clean, run "git rebase --continue") @@ -393,13 +468,22 @@ 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" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && 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 && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) 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) @@ -416,6 +500,9 @@ 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" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git reset HEAD^ && @@ -423,7 +510,13 @@ test_expect_success 'status: (split first edit) second edit' ' git commit -m "e" && git rebase --continue && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) 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) @@ -440,6 +533,9 @@ 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" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git reset HEAD^ && @@ -448,7 +544,13 @@ test_expect_success 'status: (split first edit) second edit and split' ' git rebase --continue && git reset HEAD^ && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. (Once your working directory is clean, run "git rebase --continue") @@ -470,6 +572,9 @@ 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" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git reset HEAD^ && @@ -478,7 +583,13 @@ test_expect_success 'status: (split first edit) second edit and amend' ' git rebase --continue && git commit --amend -m "h" && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) 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) @@ -745,4 +856,91 @@ EOF test_i18ncmp expected actual ' +test_expect_success 'prepare for different number of commits rebased' ' + git reset --hard master && + git checkout -b several_commits && + test_commit one_commit main.txt one && + test_commit two_commit main.txt two && + test_commit three_commit main.txt three && + test_commit four_commit main.txt four +' + +test_expect_success 'status: one command done nothing remaining' ' + FAKE_LINES="exec_exit_15" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && + test_must_fail git rebase -i HEAD~3 && + cat >expected <<EOF && +interactive rebase in progress; onto $ONTO +Last command done (1 command done): + exec exit 15 +No commands remaining. +You are currently editing a commit while rebasing branch '\''several_commits'\'' 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 +' + +test_expect_success 'status: two commands done with some white lines in done file' ' + FAKE_LINES="1 > exec_exit_15 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && + COMMIT4=$(git rev-parse --short HEAD) && + COMMIT3=$(git rev-parse --short HEAD^) && + COMMIT2=$(git rev-parse --short HEAD^^) && + test_must_fail git rebase -i HEAD~3 && + cat >expected <<EOF && +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + pick $COMMIT2 two_commit + exec exit 15 +Next commands to do (2 remaining commands): + pick $COMMIT3 three_commit + pick $COMMIT4 four_commit + (use "git rebase --edit-todo" to view and edit) +You are currently editing a commit while rebasing branch '\''several_commits'\'' 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 +' + +test_expect_success 'status: two remaining commands with some white lines in todo file' ' + FAKE_LINES="1 2 exec_exit_15 3 > 4" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~4) && + COMMIT4=$(git rev-parse --short HEAD) && + COMMIT3=$(git rev-parse --short HEAD^) && + COMMIT2=$(git rev-parse --short HEAD^^) && + test_must_fail git rebase -i HEAD~4 && + cat >expected <<EOF && +interactive rebase in progress; onto $ONTO +Last commands done (3 commands done): + pick $COMMIT2 two_commit + exec exit 15 + (see more in file .git/rebase-merge/done) +Next commands to do (2 remaining commands): + pick $COMMIT3 three_commit + pick $COMMIT4 four_commit + (use "git rebase --edit-todo" to view and edit) +You are currently editing a commit while rebasing branch '\''several_commits'\'' 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 +' + test_done diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh index bd0ab46750..322c436a49 100755 --- a/t/t7513-interpret-trailers.sh +++ b/t/t7513-interpret-trailers.sh @@ -93,12 +93,39 @@ test_expect_success 'with config option on the command line' ' Acked-by: Johan Reviewed-by: Peff EOF - echo "Acked-by: Johan" | + { echo; echo "Acked-by: Johan"; } | git -c "trailer.Acked-by.ifexists=addifdifferent" interpret-trailers \ --trailer "Reviewed-by: Peff" --trailer "Acked-by: Johan" >actual && test_cmp expected actual ' +test_expect_success 'with only a title in the message' ' + cat >expected <<-\EOF && + area: change + + Reviewed-by: Peff + Acked-by: Johan + EOF + echo "area: change" | + git interpret-trailers --trailer "Reviewed-by: Peff" \ + --trailer "Acked-by: Johan" >actual && + test_cmp expected actual +' + +test_expect_success 'with multiline title in the message' ' + cat >expected <<-\EOF && + place of + code: change + + Reviewed-by: Peff + Acked-by: Johan + EOF + printf "%s\n" "place of" "code: change" | + git interpret-trailers --trailer "Reviewed-by: Peff" \ + --trailer "Acked-by: Johan" >actual && + test_cmp expected actual +' + test_expect_success 'with config setup' ' git config trailer.ack.key "Acked-by: " && cat >expected <<-\EOF && diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index 75c50eea15..302e238263 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -692,4 +692,37 @@ test_expect_success GPG 'merge --no-edit tag should skip editor' ' test_cmp actual expect ' +test_expect_success 'set up mod-256 conflict scenario' ' + # 256 near-identical stanzas... + for i in $(test_seq 1 256); do + for j in 1 2 3 4 5; do + echo $i-$j + done + done >file && + git add file && + git commit -m base && + + # one side changes the first line of each to "master" + sed s/-1/-master/ <file >tmp && + mv tmp file && + git commit -am master && + + # and the other to "side"; merging the two will + # yield 256 separate conflicts + git checkout -b side HEAD^ && + sed s/-1/-side/ <file >tmp && + mv tmp file && + git commit -am side +' + +test_expect_success 'merge detects mod-256 conflicts (recursive)' ' + git reset --hard && + test_must_fail git merge -s recursive master +' + +test_expect_success 'merge detects mod-256 conflicts (resolve)' ' + git reset --hard && + test_must_fail git merge -s resolve master +' + test_done diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index 7eeb207b32..6f12b235b3 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -174,9 +174,9 @@ test_expect_success 'mergetool skips autoresolved' ' ' test_expect_success 'mergetool merges all from subdir' ' + test_config rerere.enabled false && ( cd subdir && - test_config rerere.enabled false && test_must_fail git merge master && ( yes "r" | git mergetool ../submod ) && ( yes "d" "d" | git mergetool --no-prompt ) && diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index ea35a0241c..ec8bc8c765 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -492,12 +492,31 @@ test_expect_success PERL 'difftool --no-symlinks detects conflict ' ' test_expect_success PERL 'difftool properly honors gitlink and core.worktree' ' git submodule add ./. submod/ule && + test_config -C submod/ule diff.tool checktrees && + test_config -C submod/ule difftool.checktrees.cmd '\'' + test -d "$LOCAL" && test -d "$REMOTE" && echo good + '\'' && ( 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 + ) +' + +test_expect_success PERL,SYMLINKS 'difftool --dir-diff symlinked directories' ' + git init dirlinks && + ( + cd dirlinks && + git config diff.tool checktrees && + git config difftool.checktrees.cmd "echo good" && + mkdir foo && + : >foo/bar && + git add foo/bar && + test_commit symlink-one && + ln -s foo link && + git add link && + test_commit symlink-two && echo good >expect && git difftool --tool=checktrees --dir-diff HEAD~ >actual && test_cmp expect actual diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh index 5cdf3f178e..ff09aced68 100755 --- a/t/t8002-blame.sh +++ b/t/t8002-blame.sh @@ -19,4 +19,66 @@ test_expect_success 'blame --show-email' ' "<E at test dot git>" 1 ' +test_expect_success 'setup showEmail tests' ' + echo "bin: test number 1" >one && + git add one && + GIT_AUTHOR_NAME=name1 \ + GIT_AUTHOR_EMAIL=email1@test.git \ + git commit -m First --date="2010-01-01 01:00:00" && + cat >expected_n <<-\EOF && + (name1 2010-01-01 01:00:00 +0000 1) bin: test number 1 + EOF + cat >expected_e <<-\EOF + (<email1@test.git> 2010-01-01 01:00:00 +0000 1) bin: test number 1 + EOF +' + +find_blame () { + sed -e 's/^[^(]*//' +} + +test_expect_success 'blame with no options and no config' ' + git blame one >blame && + find_blame <blame >result && + test_cmp expected_n result +' + +test_expect_success 'blame with showemail options' ' + git blame --show-email one >blame1 && + find_blame <blame1 >result && + test_cmp expected_e result && + git blame -e one >blame2 && + find_blame <blame2 >result && + test_cmp expected_e result && + git blame --no-show-email one >blame3 && + find_blame <blame3 >result && + test_cmp expected_n result +' + +test_expect_success 'blame with showEmail config false' ' + git config blame.showEmail false && + git blame one >blame1 && + find_blame <blame1 >result && + test_cmp expected_n result && + git blame --show-email one >blame2 && + find_blame <blame2 >result && + test_cmp expected_e result && + git blame -e one >blame3 && + find_blame <blame3 >result && + test_cmp expected_e result && + git blame --no-show-email one >blame4 && + find_blame <blame4 >result && + test_cmp expected_n result +' + +test_expect_success 'blame with showEmail config true' ' + git config blame.showEmail true && + git blame one >blame1 && + find_blame <blame1 >result && + test_cmp expected_e result && + git blame --no-show-email one >blame2 && + find_blame <blame2 >result && + test_cmp expected_n result +' + test_done diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh index 847d098c09..75da219ed1 100755 --- a/t/t8005-blame-i18n.sh +++ b/t/t8005-blame-i18n.sh @@ -33,11 +33,15 @@ author $SJIS_NAME summary $SJIS_MSG EOF +filter_author_summary () { + sed -n -e '/^author /p' -e '/^summary /p' "$@" +} + test_expect_success !MINGW \ 'blame respects i18n.commitencoding' ' - git blame --incremental file | \ - egrep "^(author|summary) " > actual && - test_cmp actual expected + git blame --incremental file >output && + filter_author_summary output >actual && + test_cmp expected actual ' cat >expected <<EOF @@ -52,9 +56,9 @@ EOF test_expect_success !MINGW \ 'blame respects i18n.logoutputencoding' ' git config i18n.logoutputencoding eucJP && - git blame --incremental file | \ - egrep "^(author|summary) " > actual && - test_cmp actual expected + git blame --incremental file >output && + filter_author_summary output >actual && + test_cmp expected actual ' cat >expected <<EOF @@ -68,9 +72,9 @@ EOF test_expect_success !MINGW \ 'blame respects --encoding=UTF-8' ' - git blame --incremental --encoding=UTF-8 file | \ - egrep "^(author|summary) " > actual && - test_cmp actual expected + git blame --incremental --encoding=UTF-8 file >output && + filter_author_summary output >actual && + test_cmp expected actual ' cat >expected <<EOF @@ -84,9 +88,9 @@ EOF test_expect_success !MINGW \ 'blame respects --encoding=none' ' - git blame --incremental --encoding=none file | \ - egrep "^(author|summary) " > actual && - test_cmp actual expected + git blame --incremental --encoding=none file >output && + filter_author_summary output >actual && + test_cmp expected actual ' test_done diff --git a/t/t8009-blame-vs-topicbranches.sh b/t/t8009-blame-vs-topicbranches.sh new file mode 100755 index 0000000000..72596e38b2 --- /dev/null +++ b/t/t8009-blame-vs-topicbranches.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +test_description='blaming trough history with topic branches' +. ./test-lib.sh + +# Creates the history shown below. '*'s mark the first parent in the merges. +# The only line of file.t is changed in commit B2 +# +# +---C1 +# / \ +# A0--A1--*A2--*A3 +# \ / +# B1-B2 +# +test_expect_success setup ' + test_commit A0 file.t line0 && + test_commit A1 && + git reset --hard A0 && + test_commit B1 && + test_commit B2 file.t line0changed && + git reset --hard A1 && + test_merge A2 B2 && + git reset --hard A1 && + test_commit C1 && + git reset --hard A2 && + test_merge A3 C1 + ' + +test_expect_success 'blame --reverse --first-parent finds A1' ' + git blame --porcelain --reverse --first-parent A0..A3 -- file.t >actual_full && + head -n 1 <actual_full | sed -e "s/ .*//" >actual && + git rev-parse A1 >expect && + test_cmp expect actual + ' + +test_done diff --git a/t/t9000-addresses.sh b/t/t9000-addresses.sh new file mode 100755 index 0000000000..a1ebef6de2 --- /dev/null +++ b/t/t9000-addresses.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +test_description='compare address parsing with and without Mail::Address' +. ./test-lib.sh + +if ! test_have_prereq PERL; then + skip_all='skipping perl interface tests, perl not available' + test_done +fi + +perl -MTest::More -e 0 2>/dev/null || { + skip_all="Perl Test::More unavailable, skipping test" + test_done +} + +perl -MMail::Address -e 0 2>/dev/null || { + skip_all="Perl Mail::Address unavailable, skipping test" + test_done +} + +test_external_has_tap=1 + +test_external_without_stderr \ + 'Perl address parsing function' \ + perl "$TEST_DIRECTORY"/t9000/test.pl + +test_done diff --git a/t/t9000/test.pl b/t/t9000/test.pl new file mode 100755 index 0000000000..2d05d3eeab --- /dev/null +++ b/t/t9000/test.pl @@ -0,0 +1,67 @@ +#!/usr/bin/perl +use lib (split(/:/, $ENV{GITPERLLIB})); + +use 5.008; +use warnings; +use strict; + +use Test::More qw(no_plan); +use Mail::Address; + +BEGIN { use_ok('Git') } + +my @success_list = (q[Jane], + q[jdoe@example.com], + q[<jdoe@example.com>], + q[Jane <jdoe@example.com>], + q[Jane Doe <jdoe@example.com>], + q["Jane" <jdoe@example.com>], + q["Doe, Jane" <jdoe@example.com>], + q["Jane@:;\>.,()<Doe" <jdoe@example.com>], + q[Jane!#$%&'*+-/=?^_{|}~Doe' <jdoe@example.com>], + q["<jdoe@example.com>"], + q["Jane jdoe@example.com"], + q[Jane Doe <jdoe @ example.com >], + q[Jane Doe < jdoe@example.com >], + q[Jane @ Doe @ Jane @ Doe], + q["Jane, 'Doe'" <jdoe@example.com>], + q['Doe, "Jane' <jdoe@example.com>], + q["Jane" "Do"e <jdoe@example.com>], + q["Jane' Doe" <jdoe@example.com>], + q["Jane Doe <jdoe@example.com>" <jdoe@example.com>], + q["Jane\" Doe" <jdoe@example.com>], + q[Doe, jane <jdoe@example.com>], + q["Jane Doe <jdoe@example.com>], + q['Jane 'Doe' <jdoe@example.com>]); + +my @known_failure_list = (q[Jane\ Doe <jdoe@example.com>], + q["Doe, Ja"ne <jdoe@example.com>], + q["Doe, Katarina" Jane <jdoe@example.com>], + q[Jane@:;\.,()<>Doe <jdoe@example.com>], + q[Jane jdoe@example.com], + q[<jdoe@example.com> Jane Doe], + q[Jane <jdoe@example.com> Doe], + q["Jane "Kat"a" ri"na" ",Doe" <jdoe@example.com>], + q[Jane Doe], + q[Jane "Doe <jdoe@example.com>"], + q[\"Jane Doe <jdoe@example.com>], + q[Jane\"\" Doe <jdoe@example.com>], + q['Jane "Katarina\" \' Doe' <jdoe@example.com>]); + +foreach my $str (@success_list) { + my @expected = map { $_->format } Mail::Address->parse("$str"); + my @actual = Git::parse_mailboxes("$str"); + is_deeply(\@expected, \@actual, qq[same output : $str]); +} + +TODO: { + local $TODO = "known breakage"; + foreach my $str (@known_failure_list) { + my @expected = map { $_->format } Mail::Address->parse("$str"); + my @actual = Git::parse_mailboxes("$str"); + is_deeply(\@expected, \@actual, qq[same output : $str]); + } +} + +my $is_passing = eval { Test::More->is_passing }; +exit($is_passing ? 0 : 1) unless $@ =~ /Can't locate object method/; diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 7be14a4e37..834d91a691 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -312,13 +312,19 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email' ) ' +test_expect_success $PREREQ 'setup tocmd and cccmd scripts' ' + write_script tocmd-sed <<-\EOF && + sed -n -e "s/^tocmd--//p" "$1" + EOF + write_script cccmd-sed <<-\EOF + sed -n -e "s/^cccmd--//p" "$1" + EOF +' + test_expect_success $PREREQ 'tocmd works' ' clean_fake_sendmail && cp $patches tocmd.patch && echo tocmd--tocmd@example.com >>tocmd.patch && - write_script tocmd-sed <<-\EOF && - sed -n -e "s/^tocmd--//p" "$1" - EOF git send-email \ --from="Example <nobody@example.com>" \ --to-cmd=./tocmd-sed \ @@ -332,9 +338,6 @@ test_expect_success $PREREQ 'cccmd works' ' clean_fake_sendmail && cp $patches cccmd.patch && echo "cccmd-- cccmd@example.com" >>cccmd.patch && - write_script cccmd-sed <<-\EOF && - sed -n -e "s/^cccmd--//p" "$1" - EOF git send-email \ --from="Example <nobody@example.com>" \ --to=nobody@example.com \ @@ -519,6 +522,12 @@ Result: OK EOF " +replace_variable_fields () { + sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \ + -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \ + -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" +} + test_suppression () { git send-email \ --dry-run \ @@ -526,10 +535,7 @@ test_suppression () { --from="Example <from@example.com>" \ --to=to@example.com \ --smtp-server relay.example.com \ - $patches | - sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \ - -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \ - -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \ + $patches | replace_variable_fields \ >actual-suppress-$1${2+"-$2"} && test_cmp expected-suppress-$1${2+"-$2"} actual-suppress-$1${2+"-$2"} } @@ -1521,6 +1527,21 @@ test_expect_success $PREREQ 'cccover adds Cc to all mail' ' test_cover_addresses "Cc" ' +test_expect_success $PREREQ 'escaped quotes in sendemail.aliasfiletype=mutt' ' + clean_fake_sendmail && + echo "alias sbd \\\"Dot U. Sir\\\" <somebody@example.org>" >.mutt && + git config --replace-all sendemail.aliasesfile "$(pwd)/.mutt" && + git config sendemail.aliasfiletype mutt && + git send-email \ + --from="Example <nobody@example.com>" \ + --to=sbd \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0001-*.patch \ + 2>errors >out && + grep "^!somebody@example\.org!$" commandline1 && + grep -F "To: \"Dot U. Sir\" <somebody@example.org>" out +' + test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' ' clean_fake_sendmail && echo "alias sbd somebody@example.org" >.mailrc && @@ -1537,7 +1558,7 @@ test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' ' test_expect_success $PREREQ 'sendemail.aliasfile=~/.mailrc' ' clean_fake_sendmail && - echo "alias sbd someone@example.org" >~/.mailrc && + echo "alias sbd someone@example.org" >"$HOME/.mailrc" && git config --replace-all sendemail.aliasesfile "~/.mailrc" && git config sendemail.aliasfiletype mailrc && git send-email \ @@ -1549,6 +1570,220 @@ test_expect_success $PREREQ 'sendemail.aliasfile=~/.mailrc' ' grep "^!someone@example\.org!$" commandline1 ' +test_dump_aliases () { + msg="$1" && shift && + filetype="$1" && shift && + printf '%s\n' "$@" >expect && + cat >.tmp-email-aliases && + + test_expect_success $PREREQ "$msg" ' + clean_fake_sendmail && rm -fr outdir && + git config --replace-all sendemail.aliasesfile \ + "$(pwd)/.tmp-email-aliases" && + git config sendemail.aliasfiletype "$filetype" && + git send-email --dump-aliases 2>errors >actual && + test_cmp expect actual + ' +} + +test_dump_aliases '--dump-aliases sendmail format' \ + 'sendmail' \ + 'abgroup' \ + 'alice' \ + 'bcgrp' \ + 'bob' \ + 'chloe' <<-\EOF + alice: Alice W Land <awol@example.com> + bob: Robert Bobbyton <bob@example.com> + chloe: chloe@example.com + abgroup: alice, bob + bcgrp: bob, chloe, Other <o@example.com> + EOF + +test_dump_aliases '--dump-aliases mutt format' \ + 'mutt' \ + 'alice' \ + 'bob' \ + 'chloe' \ + 'donald' <<-\EOF + alias alice Alice W Land <awol@example.com> + alias donald Donald C Carlton <donc@example.com> + alias bob Robert Bobbyton <bob@example.com> + alias chloe chloe@example.com + EOF + +test_dump_aliases '--dump-aliases mailrc format' \ + 'mailrc' \ + 'alice' \ + 'bob' \ + 'chloe' \ + 'eve' <<-\EOF + alias alice Alice W Land <awol@example.com> + alias eve Eve <eve@example.com> + alias bob Robert Bobbyton <bob@example.com> + alias chloe chloe@example.com + EOF + +test_dump_aliases '--dump-aliases pine format' \ + 'pine' \ + 'alice' \ + 'bob' \ + 'chloe' \ + 'eve' <<-\EOF + alice Alice W Land <awol@example.com> + eve Eve <eve@example.com> + bob Robert Bobbyton <bob@example.com> + chloe chloe@example.com + EOF + +test_dump_aliases '--dump-aliases gnus format' \ + 'gnus' \ + 'alice' \ + 'bob' \ + 'chloe' \ + 'eve' <<-\EOF + (define-mail-alias "alice" "awol@example.com") + (define-mail-alias "eve" "eve@example.com") + (define-mail-alias "bob" "bob@example.com") + (define-mail-alias "chloe" "chloe@example.com") + EOF + +test_expect_success '--dump-aliases must be used alone' ' + test_must_fail git send-email --dump-aliases --to=janice@example.com -1 refs/heads/accounting +' + +test_sendmail_aliases () { + msg="$1" && shift && + expect="$@" && + cat >.tmp-email-aliases && + + test_expect_success $PREREQ "$msg" ' + clean_fake_sendmail && rm -fr outdir && + git format-patch -1 -o outdir && + git config --replace-all sendemail.aliasesfile \ + "$(pwd)/.tmp-email-aliases" && + git config sendemail.aliasfiletype sendmail && + git send-email \ + --from="Example <nobody@example.com>" \ + --to=alice --to=bcgrp \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0001-*.patch \ + 2>errors >out && + for i in $expect + do + grep "^!$i!$" commandline1 || return 1 + done + ' +} + +test_sendmail_aliases 'sendemail.aliasfiletype=sendmail' \ + 'awol@example\.com' \ + 'bob@example\.com' \ + 'chloe@example\.com' \ + 'o@example\.com' <<-\EOF + alice: Alice W Land <awol@example.com> + bob: Robert Bobbyton <bob@example.com> + # this is a comment + # this is also a comment + chloe: chloe@example.com + abgroup: alice, bob + bcgrp: bob, chloe, Other <o@example.com> + EOF + +test_sendmail_aliases 'sendmail aliases line folding' \ + alice1 \ + bob1 bob2 \ + chuck1 chuck2 \ + darla1 darla2 darla3 \ + elton1 elton2 elton3 \ + fred1 fred2 \ + greg1 <<-\EOF + alice: alice1 + bob: bob1,\ + bob2 + chuck: chuck1, + chuck2 + darla: darla1,\ + darla2, + darla3 + elton: elton1, + elton2,\ + elton3 + fred: fred1,\ + fred2 + greg: greg1 + bcgrp: bob, chuck, darla, elton, fred, greg + EOF + +test_sendmail_aliases 'sendmail aliases tolerate bogus line folding' \ + alice1 bob1 <<-\EOF + alice: alice1 + bcgrp: bob1\ + EOF + +test_sendmail_aliases 'sendmail aliases empty' alice bcgrp <<-\EOF + EOF + +test_expect_success $PREREQ 'alias support in To header' ' + clean_fake_sendmail && + echo "alias sbd someone@example.org" >.mailrc && + test_config sendemail.aliasesfile ".mailrc" && + test_config sendemail.aliasfiletype mailrc && + git format-patch --stdout -1 --to=sbd >aliased.patch && + git send-email \ + --from="Example <nobody@example.com>" \ + --smtp-server="$(pwd)/fake.sendmail" \ + aliased.patch \ + 2>errors >out && + grep "^!someone@example\.org!$" commandline1 +' + +test_expect_success $PREREQ 'alias support in Cc header' ' + clean_fake_sendmail && + echo "alias sbd someone@example.org" >.mailrc && + test_config sendemail.aliasesfile ".mailrc" && + test_config sendemail.aliasfiletype mailrc && + git format-patch --stdout -1 --cc=sbd >aliased.patch && + git send-email \ + --from="Example <nobody@example.com>" \ + --smtp-server="$(pwd)/fake.sendmail" \ + aliased.patch \ + 2>errors >out && + grep "^!someone@example\.org!$" commandline1 +' + +test_expect_success $PREREQ 'tocmd works with aliases' ' + clean_fake_sendmail && + echo "alias sbd someone@example.org" >.mailrc && + test_config sendemail.aliasesfile ".mailrc" && + test_config sendemail.aliasfiletype mailrc && + git format-patch --stdout -1 >tocmd.patch && + echo tocmd--sbd >>tocmd.patch && + git send-email \ + --from="Example <nobody@example.com>" \ + --to-cmd=./tocmd-sed \ + --smtp-server="$(pwd)/fake.sendmail" \ + tocmd.patch \ + 2>errors >out && + grep "^!someone@example\.org!$" commandline1 +' + +test_expect_success $PREREQ 'cccmd works with aliases' ' + clean_fake_sendmail && + echo "alias sbd someone@example.org" >.mailrc && + test_config sendemail.aliasesfile ".mailrc" && + test_config sendemail.aliasfiletype mailrc && + git format-patch --stdout -1 >cccmd.patch && + echo cccmd--sbd >>cccmd.patch && + git send-email \ + --from="Example <nobody@example.com>" \ + --cc-cmd=./cccmd-sed \ + --smtp-server="$(pwd)/fake.sendmail" \ + cccmd.patch \ + 2>errors >out && + grep "^!someone@example\.org!$" commandline1 +' + do_xmailer_test () { expected=$1 params=$2 && git format-patch -1 && @@ -1582,4 +1817,72 @@ test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=false' ' do_xmailer_test 1 "--xmailer" ' +test_expect_success $PREREQ 'setup expected-list' ' + git send-email \ + --dry-run \ + --from="Example <from@example.com>" \ + --to="To 1 <to1@example.com>" \ + --to="to2@example.com" \ + --to="to3@example.com" \ + --cc="Cc 1 <cc1@example.com>" \ + --cc="Cc2 <cc2@example.com>" \ + --bcc="bcc1@example.com" \ + --bcc="bcc2@example.com" \ + 0001-add-master.patch | replace_variable_fields \ + >expected-list +' + +test_expect_success $PREREQ 'use email list in --cc --to and --bcc' ' + git send-email \ + --dry-run \ + --from="Example <from@example.com>" \ + --to="To 1 <to1@example.com>, to2@example.com" \ + --to="to3@example.com" \ + --cc="Cc 1 <cc1@example.com>, Cc2 <cc2@example.com>" \ + --bcc="bcc1@example.com, bcc2@example.com" \ + 0001-add-master.patch | replace_variable_fields \ + >actual-list && + test_cmp expected-list actual-list +' + +test_expect_success $PREREQ 'aliases work with email list' ' + echo "alias to2 to2@example.com" >.mutt && + echo "alias cc1 Cc 1 <cc1@example.com>" >>.mutt && + test_config sendemail.aliasesfile ".mutt" && + test_config sendemail.aliasfiletype mutt && + git send-email \ + --dry-run \ + --from="Example <from@example.com>" \ + --to="To 1 <to1@example.com>, to2, to3@example.com" \ + --cc="cc1, Cc2 <cc2@example.com>" \ + --bcc="bcc1@example.com, bcc2@example.com" \ + 0001-add-master.patch | replace_variable_fields \ + >actual-list && + test_cmp expected-list actual-list +' + +test_expect_success $PREREQ 'leading and trailing whitespaces are removed' ' + echo "alias to2 to2@example.com" >.mutt && + echo "alias cc1 Cc 1 <cc1@example.com>" >>.mutt && + test_config sendemail.aliasesfile ".mutt" && + test_config sendemail.aliasfiletype mutt && + TO1=$(echo "QTo 1 <to1@example.com>" | q_to_tab) && + TO2=$(echo "QZto2" | qz_to_tab_space) && + CC1=$(echo "cc1" | append_cr) && + BCC1=$(echo "Q bcc1@example.com Q" | q_to_nul) && + git send-email \ + --dry-run \ + --from=" Example <from@example.com>" \ + --to="$TO1" \ + --to="$TO2" \ + --to=" to3@example.com " \ + --cc="$CC1" \ + --cc="Cc2 <cc2@example.com>" \ + --bcc="$BCC1" \ + --bcc="bcc2@example.com" \ + 0001-add-master.patch | replace_variable_fields \ + >actual-list && + test_cmp expected-list actual-list +' + test_done diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 812c9cd462..7117719830 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -35,7 +35,7 @@ exit 1 check_entries () { # $1 == directory, $2 == expected - grep '^/' "$1/CVS/Entries" | sort | cut -d/ -f2,3,5 >actual + sed -ne '/^\//p' "$1/CVS/Entries" | sort | cut -d/ -f2,3,5 >actual if test -z "$2" then >expected diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index aac126fd57..14a938402e 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -47,1077 +47,1075 @@ file5_data='an inline file. file6_data='#!/bin/sh echo "$@"' ->empty - ### ### series A ### -test_tick - test_expect_success 'empty stream succeeds' ' git fast-import </dev/null ' -cat >input <<INPUT_END -blob -mark :2 -data <<EOF -$file2_data -EOF - -blob -mark :3 -data <<END -$file3_data -END - -blob -mark :4 -data $file4_len -$file4_data -commit refs/heads/master -mark :5 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -initial -COMMIT - -M 644 :2 file2 -M 644 :3 file3 -M 755 :4 file4 - -tag series-A -from :5 -data <<EOF -An annotated tag without a tagger -EOF - -tag series-A-blob -from :3 -data <<EOF -An annotated tag that annotates a blob. -EOF - -INPUT_END -test_expect_success \ - 'A: create pack from stdin' \ - 'git fast-import --export-marks=marks.out <input && - git whatchanged master' +test_expect_success 'A: create pack from stdin' ' + test_tick && + cat >input <<-INPUT_END && + blob + mark :2 + data <<EOF + $file2_data + EOF + + blob + mark :3 + data <<END + $file3_data + END + + blob + mark :4 + data $file4_len + $file4_data + commit refs/heads/master + mark :5 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + initial + COMMIT + + M 644 :2 file2 + M 644 :3 file3 + M 755 :4 file4 + + tag series-A + from :5 + data <<EOF + An annotated tag without a tagger + EOF + + tag series-A-blob + from :3 + data <<EOF + An annotated tag that annotates a blob. + EOF + + INPUT_END + git fast-import --export-marks=marks.out <input && + git whatchanged master +' test_expect_success 'A: verify pack' ' verify_packs ' -cat >expect <<EOF -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -initial -EOF -test_expect_success \ - 'A: verify commit' \ - 'git cat-file commit master | sed 1d >actual && - test_cmp expect actual' - -cat >expect <<EOF -100644 blob file2 -100644 blob file3 -100755 blob file4 -EOF -test_expect_success \ - 'A: verify tree' \ - 'git cat-file -p master^{tree} | sed "s/ [0-9a-f]* / /" >actual && - test_cmp expect actual' - -echo "$file2_data" >expect -test_expect_success \ - 'A: verify file2' \ - 'git cat-file blob master:file2 >actual && test_cmp expect actual' - -echo "$file3_data" >expect -test_expect_success \ - 'A: verify file3' \ - 'git cat-file blob master:file3 >actual && test_cmp expect actual' - -printf "$file4_data" >expect -test_expect_success \ - 'A: verify file4' \ - 'git cat-file blob master:file4 >actual && test_cmp expect actual' - -cat >expect <<EOF -object $(git rev-parse refs/heads/master) -type commit -tag series-A - -An annotated tag without a tagger -EOF +test_expect_success 'A: verify commit' ' + cat >expect <<-EOF && + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + initial + EOF + git cat-file commit master | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'A: verify tree' ' + cat >expect <<-EOF && + 100644 blob file2 + 100644 blob file3 + 100755 blob file4 + EOF + git cat-file -p master^{tree} | sed "s/ [0-9a-f]* / /" >actual && + test_cmp expect actual +' + +test_expect_success 'A: verify file2' ' + echo "$file2_data" >expect && + git cat-file blob master:file2 >actual && + test_cmp expect actual +' + +test_expect_success 'A: verify file3' ' + echo "$file3_data" >expect && + git cat-file blob master:file3 >actual && + test_cmp expect actual +' + +test_expect_success 'A: verify file4' ' + printf "$file4_data" >expect && + git cat-file blob master:file4 >actual && + test_cmp expect actual +' + test_expect_success 'A: verify tag/series-A' ' + cat >expect <<-EOF && + object $(git rev-parse refs/heads/master) + type commit + tag series-A + + An annotated tag without a tagger + EOF git cat-file tag tags/series-A >actual && test_cmp expect actual ' -cat >expect <<EOF -object $(git rev-parse refs/heads/master:file3) -type blob -tag series-A-blob - -An annotated tag that annotates a blob. -EOF test_expect_success 'A: verify tag/series-A-blob' ' + cat >expect <<-EOF && + object $(git rev-parse refs/heads/master:file3) + type blob + tag series-A-blob + + An annotated tag that annotates a blob. + EOF git cat-file tag tags/series-A-blob >actual && test_cmp expect actual ' -cat >expect <<EOF -:2 `git rev-parse --verify master:file2` -:3 `git rev-parse --verify master:file3` -:4 `git rev-parse --verify master:file4` -:5 `git rev-parse --verify master^0` -EOF -test_expect_success \ - 'A: verify marks output' \ - 'test_cmp expect marks.out' +test_expect_success 'A: verify marks output' ' + cat >expect <<-EOF && + :2 `git rev-parse --verify master:file2` + :3 `git rev-parse --verify master:file3` + :4 `git rev-parse --verify master:file4` + :5 `git rev-parse --verify master^0` + EOF + test_cmp expect marks.out +' -test_expect_success \ - 'A: verify marks import' \ - 'git fast-import \ +test_expect_success 'A: verify marks import' ' + git fast-import \ --import-marks=marks.out \ --export-marks=marks.new \ </dev/null && - test_cmp expect marks.new' - -test_tick -new_blob=$(echo testing | git hash-object --stdin) -cat >input <<INPUT_END -tag series-A-blob-2 -from $(git rev-parse refs/heads/master:file3) -data <<EOF -Tag blob by sha1. -EOF - -blob -mark :6 -data <<EOF -testing -EOF - -commit refs/heads/new_blob -committer <> 0 +0000 -data 0 -M 644 :6 new_blob -#pretend we got sha1 from fast-import -ls "new_blob" - -tag series-A-blob-3 -from $new_blob -data <<EOF -Tag new_blob. -EOF -INPUT_END - -cat >expect <<EOF -object $(git rev-parse refs/heads/master:file3) -type blob -tag series-A-blob-2 - -Tag blob by sha1. -object $new_blob -type blob -tag series-A-blob-3 - -Tag new_blob. -EOF - -test_expect_success \ - 'A: tag blob by sha1' \ - 'git fast-import <input && + test_cmp expect marks.new +' + +test_expect_success 'A: tag blob by sha1' ' + test_tick && + new_blob=$(echo testing | git hash-object --stdin) && + cat >input <<-INPUT_END && + tag series-A-blob-2 + from $(git rev-parse refs/heads/master:file3) + data <<EOF + Tag blob by sha1. + EOF + + blob + mark :6 + data <<EOF + testing + EOF + + commit refs/heads/new_blob + committer <> 0 +0000 + data 0 + M 644 :6 new_blob + #pretend we got sha1 from fast-import + ls "new_blob" + + tag series-A-blob-3 + from $new_blob + data <<EOF + Tag new_blob. + EOF + INPUT_END + + cat >expect <<-EOF && + object $(git rev-parse refs/heads/master:file3) + type blob + tag series-A-blob-2 + + Tag blob by sha1. + object $new_blob + type blob + tag series-A-blob-3 + + Tag new_blob. + EOF + + git fast-import <input && git cat-file tag tags/series-A-blob-2 >actual && git cat-file tag tags/series-A-blob-3 >>actual && - test_cmp expect actual' + test_cmp expect actual +' + +test_expect_success 'A: verify marks import does not crash' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/verify--import-marks + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + recreate from :5 + COMMIT -test_tick -cat >input <<INPUT_END -commit refs/heads/verify--import-marks -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -recreate from :5 -COMMIT + from :5 + M 755 :2 copy-of-file2 -from :5 -M 755 :2 copy-of-file2 + INPUT_END -INPUT_END -test_expect_success \ - 'A: verify marks import does not crash' \ - 'git fast-import --import-marks=marks.out <input && - git whatchanged verify--import-marks' + git fast-import --import-marks=marks.out <input && + git whatchanged verify--import-marks +' test_expect_success 'A: verify pack' ' verify_packs ' -cat >expect <<EOF -:000000 100755 0000000000000000000000000000000000000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 A copy-of-file2 -EOF -git diff-tree -M -r master verify--import-marks >actual -test_expect_success \ - 'A: verify diff' \ - 'compare_diff_raw expect actual && - test `git rev-parse --verify master:file2` \ - = `git rev-parse --verify verify--import-marks:copy-of-file2`' - -test_tick -mt=$(git hash-object --stdin < /dev/null) -: >input.blob -: >marks.exp -: >tree.exp - -cat >input.commit <<EOF -commit refs/heads/verify--dump-marks -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -test the sparse array dumping routines with exponentially growing marks -COMMIT -EOF - -i=0 -l=4 -m=6 -n=7 -while test "$i" -lt 27; do - cat >>input.blob <<EOF -blob -mark :$l -data 0 -blob -mark :$m -data 0 -blob -mark :$n -data 0 -EOF - echo "M 100644 :$l l$i" >>input.commit - echo "M 100644 :$m m$i" >>input.commit - echo "M 100644 :$n n$i" >>input.commit - - echo ":$l $mt" >>marks.exp - echo ":$m $mt" >>marks.exp - echo ":$n $mt" >>marks.exp - - printf "100644 blob $mt\tl$i\n" >>tree.exp - printf "100644 blob $mt\tm$i\n" >>tree.exp - printf "100644 blob $mt\tn$i\n" >>tree.exp - - l=$(($l + $l)) - m=$(($m + $m)) - n=$(($l + $n)) - - i=$((1 + $i)) -done - -sort tree.exp > tree.exp_s +test_expect_success 'A: verify diff' ' + cat >expect <<-EOF && + :000000 100755 0000000000000000000000000000000000000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 A copy-of-file2 + EOF + git diff-tree -M -r master verify--import-marks >actual && + compare_diff_raw expect actual && + test `git rev-parse --verify master:file2` \ + = `git rev-parse --verify verify--import-marks:copy-of-file2` +' test_expect_success 'A: export marks with large values' ' + test_tick && + mt=$(git hash-object --stdin < /dev/null) && + >input.blob && + >marks.exp && + >tree.exp && + + cat >input.commit <<-EOF && + commit refs/heads/verify--dump-marks + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + test the sparse array dumping routines with exponentially growing marks + COMMIT + EOF + + i=0 l=4 m=6 n=7 && + while test "$i" -lt 27 + do + cat >>input.blob <<-EOF && + blob + mark :$l + data 0 + blob + mark :$m + data 0 + blob + mark :$n + data 0 + EOF + echo "M 100644 :$l l$i" >>input.commit && + echo "M 100644 :$m m$i" >>input.commit && + echo "M 100644 :$n n$i" >>input.commit && + + echo ":$l $mt" >>marks.exp && + echo ":$m $mt" >>marks.exp && + echo ":$n $mt" >>marks.exp && + + printf "100644 blob $mt\tl$i\n" >>tree.exp && + printf "100644 blob $mt\tm$i\n" >>tree.exp && + printf "100644 blob $mt\tn$i\n" >>tree.exp && + + l=$(($l + $l)) && + m=$(($m + $m)) && + n=$(($l + $n)) && + + i=$((1 + $i)) || return 1 + done && + + sort tree.exp > tree.exp_s && + cat input.blob input.commit | git fast-import --export-marks=marks.large && git ls-tree refs/heads/verify--dump-marks >tree.out && test_cmp tree.exp_s tree.out && - test_cmp marks.exp marks.large' + test_cmp marks.exp marks.large +' ### ### series B ### -test_tick -cat >input <<INPUT_END -commit refs/heads/branch -mark :1 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -corrupt -COMMIT +test_expect_success 'B: fail on invalid blob sha1' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/branch + mark :1 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + corrupt + COMMIT + + from refs/heads/master + M 755 0000000000000000000000000000000000000001 zero1 -from refs/heads/master -M 755 0000000000000000000000000000000000000001 zero1 + INPUT_END + + test_when_finished "rm -f .git/objects/pack_* .git/objects/index_*" && + test_must_fail git fast-import <input +' + +test_expect_success 'B: accept branch name "TEMP_TAG"' ' + cat >input <<-INPUT_END && + commit TEMP_TAG + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + tag base + COMMIT + + from refs/heads/master + + INPUT_END + + test_when_finished "rm -f .git/TEMP_TAG + git gc + git prune" && + git fast-import <input && + test -f .git/TEMP_TAG && + test `git rev-parse master` = `git rev-parse TEMP_TAG^` +' -INPUT_END -test_expect_success 'B: fail on invalid blob sha1' ' - test_must_fail git fast-import <input -' -rm -f .git/objects/pack_* .git/objects/index_* - -cat >input <<INPUT_END -commit TEMP_TAG -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -tag base -COMMIT - -from refs/heads/master - -INPUT_END -test_expect_success \ - 'B: accept branch name "TEMP_TAG"' \ - 'git fast-import <input && - test -f .git/TEMP_TAG && - test `git rev-parse master` = `git rev-parse TEMP_TAG^`' -rm -f .git/TEMP_TAG - -git gc 2>/dev/null >/dev/null -git prune 2>/dev/null >/dev/null - -cat >input <<INPUT_END -commit refs/heads/empty-committer-1 -committer <> $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: accept empty committer' ' + cat >input <<-INPUT_END && + commit refs/heads/empty-committer-1 + committer <> $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/empty-committer-1 + git gc + git prune" && git fast-import <input && out=$(git fsck) && echo "$out" && test -z "$out" ' -git update-ref -d refs/heads/empty-committer-1 || true - -git gc 2>/dev/null >/dev/null -git prune 2>/dev/null >/dev/null -cat >input <<INPUT_END -commit refs/heads/empty-committer-2 -committer <a@b.com> $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: accept and fixup committer with no name' ' + cat >input <<-INPUT_END && + commit refs/heads/empty-committer-2 + committer <a@b.com> $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/empty-committer-2 + git gc + git prune" && git fast-import <input && out=$(git fsck) && echo "$out" && test -z "$out" ' -git update-ref -d refs/heads/empty-committer-2 || true - -git gc 2>/dev/null >/dev/null -git prune 2>/dev/null >/dev/null -cat >input <<INPUT_END -commit refs/heads/invalid-committer -committer Name email> $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: fail on invalid committer (1)' ' + cat >input <<-INPUT_END && + commit refs/heads/invalid-committer + committer Name email> $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/invalid-committer" && test_must_fail git fast-import <input ' -git update-ref -d refs/heads/invalid-committer || true -cat >input <<INPUT_END -commit refs/heads/invalid-committer -committer Name <e<mail> $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: fail on invalid committer (2)' ' + cat >input <<-INPUT_END && + commit refs/heads/invalid-committer + committer Name <e<mail> $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/invalid-committer" && test_must_fail git fast-import <input ' -git update-ref -d refs/heads/invalid-committer || true -cat >input <<INPUT_END -commit refs/heads/invalid-committer -committer Name <email>> $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: fail on invalid committer (3)' ' + cat >input <<-INPUT_END && + commit refs/heads/invalid-committer + committer Name <email>> $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/invalid-committer" && test_must_fail git fast-import <input ' -git update-ref -d refs/heads/invalid-committer || true -cat >input <<INPUT_END -commit refs/heads/invalid-committer -committer Name <email $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: fail on invalid committer (4)' ' + cat >input <<-INPUT_END && + commit refs/heads/invalid-committer + committer Name <email $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/invalid-committer" && test_must_fail git fast-import <input ' -git update-ref -d refs/heads/invalid-committer || true -cat >input <<INPUT_END -commit refs/heads/invalid-committer -committer Name<email> $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: fail on invalid committer (5)' ' + cat >input <<-INPUT_END && + commit refs/heads/invalid-committer + committer Name<email> $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/invalid-committer" && test_must_fail git fast-import <input ' -git update-ref -d refs/heads/invalid-committer || true ### ### series C ### -newf=`echo hi newf | git hash-object -w --stdin` -oldf=`git rev-parse --verify master:file2` -test_tick -cat >input <<INPUT_END -commit refs/heads/branch -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -second -COMMIT - -from refs/heads/master -M 644 $oldf file2/oldf -M 755 $newf file2/newf -D file3 - -INPUT_END -test_expect_success \ - 'C: incremental import create pack from stdin' \ - 'git fast-import <input && - git whatchanged branch' +test_expect_success 'C: incremental import create pack from stdin' ' + newf=`echo hi newf | git hash-object -w --stdin` && + oldf=`git rev-parse --verify master:file2` && + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/branch + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + second + COMMIT + + from refs/heads/master + M 644 $oldf file2/oldf + M 755 $newf file2/newf + D file3 + + INPUT_END + + git fast-import <input && + git whatchanged branch +' test_expect_success 'C: verify pack' ' verify_packs ' -test_expect_success \ - 'C: validate reuse existing blob' \ - 'test $newf = `git rev-parse --verify branch:file2/newf` && - test $oldf = `git rev-parse --verify branch:file2/oldf`' - -cat >expect <<EOF -parent `git rev-parse --verify master^0` -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -second -EOF -test_expect_success \ - 'C: verify commit' \ - 'git cat-file commit branch | sed 1d >actual && - test_cmp expect actual' - -cat >expect <<EOF -:000000 100755 0000000000000000000000000000000000000000 f1fb5da718392694d0076d677d6d0e364c79b0bc A file2/newf -:100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100 file2 file2/oldf -:100644 000000 0d92e9f3374ae2947c23aa477cbc68ce598135f1 0000000000000000000000000000000000000000 D file3 -EOF -git diff-tree -M -r master branch >actual -test_expect_success \ - 'C: validate rename result' \ - 'compare_diff_raw expect actual' +test_expect_success 'C: validate reuse existing blob' ' + test $newf = `git rev-parse --verify branch:file2/newf` && + test $oldf = `git rev-parse --verify branch:file2/oldf` +' + +test_expect_success 'C: verify commit' ' + cat >expect <<-EOF && + parent `git rev-parse --verify master^0` + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + second + EOF + + git cat-file commit branch | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'C: validate rename result' ' + cat >expect <<-EOF && + :000000 100755 0000000000000000000000000000000000000000 f1fb5da718392694d0076d677d6d0e364c79b0bc A file2/newf + :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100 file2 file2/oldf + :100644 000000 0d92e9f3374ae2947c23aa477cbc68ce598135f1 0000000000000000000000000000000000000000 D file3 + EOF + git diff-tree -M -r master branch >actual && + compare_diff_raw expect actual +' ### ### series D ### -test_tick -cat >input <<INPUT_END -commit refs/heads/branch -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -third -COMMIT - -from refs/heads/branch^0 -M 644 inline newdir/interesting -data <<EOF -$file5_data -EOF - -M 755 inline newdir/exec.sh -data <<EOF -$file6_data -EOF - -INPUT_END -test_expect_success \ - 'D: inline data in commit' \ - 'git fast-import <input && - git whatchanged branch' +test_expect_success 'D: inline data in commit' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/branch + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + third + COMMIT + + from refs/heads/branch^0 + M 644 inline newdir/interesting + data <<EOF + $file5_data + EOF + + M 755 inline newdir/exec.sh + data <<EOF + $file6_data + EOF + + INPUT_END + + git fast-import <input && + git whatchanged branch +' test_expect_success 'D: verify pack' ' verify_packs ' -cat >expect <<EOF -:000000 100755 0000000000000000000000000000000000000000 e74b7d465e52746be2b4bae983670711e6e66657 A newdir/exec.sh -:000000 100644 0000000000000000000000000000000000000000 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 A newdir/interesting -EOF -git diff-tree -M -r branch^ branch >actual -test_expect_success \ - 'D: validate new files added' \ - 'compare_diff_raw expect actual' +test_expect_success 'D: validate new files added' ' + cat >expect <<-EOF && + :000000 100755 0000000000000000000000000000000000000000 e74b7d465e52746be2b4bae983670711e6e66657 A newdir/exec.sh + :000000 100644 0000000000000000000000000000000000000000 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 A newdir/interesting + EOF + git diff-tree -M -r branch^ branch >actual && + compare_diff_raw expect actual +' -echo "$file5_data" >expect -test_expect_success \ - 'D: verify file5' \ - 'git cat-file blob branch:newdir/interesting >actual && - test_cmp expect actual' +test_expect_success 'D: verify file5' ' + echo "$file5_data" >expect && + git cat-file blob branch:newdir/interesting >actual && + test_cmp expect actual +' -echo "$file6_data" >expect -test_expect_success \ - 'D: verify file6' \ - 'git cat-file blob branch:newdir/exec.sh >actual && - test_cmp expect actual' +test_expect_success 'D: verify file6' ' + echo "$file6_data" >expect && + git cat-file blob branch:newdir/exec.sh >actual && + test_cmp expect actual +' ### ### series E ### -cat >input <<INPUT_END -commit refs/heads/branch -author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> Tue Feb 6 11:22:18 2007 -0500 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> Tue Feb 6 12:35:02 2007 -0500 -data <<COMMIT -RFC 2822 type date -COMMIT +test_expect_success 'E: rfc2822 date, --date-format=raw' ' + cat >input <<-INPUT_END && + commit refs/heads/branch + author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> Tue Feb 6 11:22:18 2007 -0500 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> Tue Feb 6 12:35:02 2007 -0500 + data <<COMMIT + RFC 2822 type date + COMMIT -from refs/heads/branch^0 + from refs/heads/branch^0 -INPUT_END -test_expect_success 'E: rfc2822 date, --date-format=raw' ' - test_must_fail git fast-import --date-format=raw <input + INPUT_END + + test_must_fail git fast-import --date-format=raw <input +' +test_expect_success 'E: rfc2822 date, --date-format=rfc2822' ' + git fast-import --date-format=rfc2822 <input ' -test_expect_success \ - 'E: rfc2822 date, --date-format=rfc2822' \ - 'git fast-import --date-format=rfc2822 <input' test_expect_success 'E: verify pack' ' verify_packs ' -cat >expect <<EOF -author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 1170778938 -0500 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1170783302 -0500 +test_expect_success 'E: verify commit' ' + cat >expect <<-EOF && + author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 1170778938 -0500 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1170783302 -0500 -RFC 2822 type date -EOF -test_expect_success \ - 'E: verify commit' \ - 'git cat-file commit branch | sed 1,2d >actual && - test_cmp expect actual' + RFC 2822 type date + EOF + git cat-file commit branch | sed 1,2d >actual && + test_cmp expect actual +' ### ### series F ### -old_branch=`git rev-parse --verify branch^0` -test_tick -cat >input <<INPUT_END -commit refs/heads/branch -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -losing things already? -COMMIT - -from refs/heads/branch~1 - -reset refs/heads/other -from refs/heads/branch - -INPUT_END -test_expect_success \ - 'F: non-fast-forward update skips' \ - 'if git fast-import <input - then - echo BAD gfi did not fail - return 1 - else - if test $old_branch = `git rev-parse --verify branch^0` - then - : branch unaffected and failure returned - return 0 - else - echo BAD gfi changed branch $old_branch - return 1 - fi - fi - ' +test_expect_success 'F: non-fast-forward update skips' ' + old_branch=`git rev-parse --verify branch^0` && + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/branch + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + losing things already? + COMMIT + + from refs/heads/branch~1 + + reset refs/heads/other + from refs/heads/branch + + INPUT_END + + test_must_fail git fast-import <input && + # branch must remain unaffected + test $old_branch = `git rev-parse --verify branch^0` +' test_expect_success 'F: verify pack' ' verify_packs ' -cat >expect <<EOF -tree `git rev-parse branch~1^{tree}` -parent `git rev-parse branch~1` -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +test_expect_success 'F: verify other commit' ' + cat >expect <<-EOF && + tree `git rev-parse branch~1^{tree}` + parent `git rev-parse branch~1` + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -losing things already? -EOF -test_expect_success \ - 'F: verify other commit' \ - 'git cat-file commit other >actual && - test_cmp expect actual' + losing things already? + EOF + git cat-file commit other >actual && + test_cmp expect actual +' ### ### series G ### -old_branch=`git rev-parse --verify branch^0` -test_tick -cat >input <<INPUT_END -commit refs/heads/branch -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -losing things already? -COMMIT +test_expect_success 'G: non-fast-forward update forced' ' + old_branch=`git rev-parse --verify branch^0` && + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/branch + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + losing things already? + COMMIT -from refs/heads/branch~1 + from refs/heads/branch~1 -INPUT_END -test_expect_success \ - 'G: non-fast-forward update forced' \ - 'git fast-import --force <input' + INPUT_END + git fast-import --force <input +' test_expect_success 'G: verify pack' ' verify_packs ' -test_expect_success \ - 'G: branch changed, but logged' \ - 'test $old_branch != `git rev-parse --verify branch^0` && - test $old_branch = `git rev-parse --verify branch@{1}`' +test_expect_success 'G: branch changed, but logged' ' + test $old_branch != `git rev-parse --verify branch^0` && + test $old_branch = `git rev-parse --verify branch@{1}` +' ### ### series H ### -test_tick -cat >input <<INPUT_END -commit refs/heads/H -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -third -COMMIT - -from refs/heads/branch^0 -M 644 inline i-will-die -data <<EOF -this file will never exist. -EOF - -deleteall -M 644 inline h/e/l/lo -data <<EOF -$file5_data -EOF - -INPUT_END -test_expect_success \ - 'H: deletall, add 1' \ - 'git fast-import <input && - git whatchanged H' +test_expect_success 'H: deletall, add 1' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/H + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + third + COMMIT + + from refs/heads/branch^0 + M 644 inline i-will-die + data <<EOF + this file will never exist. + EOF + + deleteall + M 644 inline h/e/l/lo + data <<EOF + $file5_data + EOF + + INPUT_END + git fast-import <input && + git whatchanged H +' test_expect_success 'H: verify pack' ' verify_packs ' -cat >expect <<EOF -:100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D file2/newf -:100644 000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 0000000000000000000000000000000000000000 D file2/oldf -:100755 000000 85df50785d62d3b05ab03d9cbf7e4a0b49449730 0000000000000000000000000000000000000000 D file4 -:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100 newdir/interesting h/e/l/lo -:100755 000000 e74b7d465e52746be2b4bae983670711e6e66657 0000000000000000000000000000000000000000 D newdir/exec.sh -EOF -git diff-tree -M -r H^ H >actual -test_expect_success \ - 'H: validate old files removed, new files added' \ - 'compare_diff_raw expect actual' - -echo "$file5_data" >expect -test_expect_success \ - 'H: verify file' \ - 'git cat-file blob H:h/e/l/lo >actual && - test_cmp expect actual' +test_expect_success 'H: validate old files removed, new files added' ' + cat >expect <<-EOF && + :100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D file2/newf + :100644 000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 0000000000000000000000000000000000000000 D file2/oldf + :100755 000000 85df50785d62d3b05ab03d9cbf7e4a0b49449730 0000000000000000000000000000000000000000 D file4 + :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100 newdir/interesting h/e/l/lo + :100755 000000 e74b7d465e52746be2b4bae983670711e6e66657 0000000000000000000000000000000000000000 D newdir/exec.sh + EOF + git diff-tree -M -r H^ H >actual && + compare_diff_raw expect actual +' + +test_expect_success 'H: verify file' ' + echo "$file5_data" >expect && + git cat-file blob H:h/e/l/lo >actual && + test_cmp expect actual +' ### ### series I ### -cat >input <<INPUT_END -commit refs/heads/export-boundary -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -we have a border. its only 40 characters wide. -COMMIT +test_expect_success 'I: export-pack-edges' ' + cat >input <<-INPUT_END && + commit refs/heads/export-boundary + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + we have a border. its only 40 characters wide. + COMMIT -from refs/heads/branch + from refs/heads/branch -INPUT_END -test_expect_success \ - 'I: export-pack-edges' \ - 'git fast-import --export-pack-edges=edges.list <input' + INPUT_END + git fast-import --export-pack-edges=edges.list <input +' -cat >expect <<EOF -.git/objects/pack/pack-.pack: `git rev-parse --verify export-boundary` -EOF -test_expect_success \ - 'I: verify edge list' \ - 'sed -e s/pack-.*pack/pack-.pack/ edges.list >actual && - test_cmp expect actual' +test_expect_success 'I: verify edge list' ' + cat >expect <<-EOF && + .git/objects/pack/pack-.pack: `git rev-parse --verify export-boundary` + EOF + sed -e s/pack-.*pack/pack-.pack/ edges.list >actual && + test_cmp expect actual +' ### ### series J ### -cat >input <<INPUT_END -commit refs/heads/J -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -create J -COMMIT - -from refs/heads/branch - -reset refs/heads/J - -commit refs/heads/J -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -initialize J -COMMIT - -INPUT_END -test_expect_success \ - 'J: reset existing branch creates empty commit' \ - 'git fast-import <input' -test_expect_success \ - 'J: branch has 1 commit, empty tree' \ - 'test 1 = `git rev-list J | wc -l` && - test 0 = `git ls-tree J | wc -l`' - -cat >input <<INPUT_END -reset refs/heads/J2 - -tag wrong_tag -from refs/heads/J2 -data <<EOF -Tag branch that was reset. -EOF -INPUT_END -test_expect_success \ - 'J: tag must fail on empty branch' \ - 'test_must_fail git fast-import <input' +test_expect_success 'J: reset existing branch creates empty commit' ' + cat >input <<-INPUT_END && + commit refs/heads/J + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + create J + COMMIT + + from refs/heads/branch + + reset refs/heads/J + + commit refs/heads/J + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + initialize J + COMMIT + + INPUT_END + git fast-import <input +' +test_expect_success 'J: branch has 1 commit, empty tree' ' + test 1 = `git rev-list J | wc -l` && + test 0 = `git ls-tree J | wc -l` +' + +test_expect_success 'J: tag must fail on empty branch' ' + cat >input <<-INPUT_END && + reset refs/heads/J2 + + tag wrong_tag + from refs/heads/J2 + data <<EOF + Tag branch that was reset. + EOF + INPUT_END + test_must_fail git fast-import <input +' + ### ### series K ### -cat >input <<INPUT_END -commit refs/heads/K -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -create K -COMMIT +test_expect_success 'K: reinit branch with from' ' + cat >input <<-INPUT_END && + commit refs/heads/K + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + create K + COMMIT -from refs/heads/branch + from refs/heads/branch -commit refs/heads/K -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -redo K -COMMIT + commit refs/heads/K + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + redo K + COMMIT -from refs/heads/branch^1 + from refs/heads/branch^1 -INPUT_END -test_expect_success \ - 'K: reinit branch with from' \ - 'git fast-import <input' -test_expect_success \ - 'K: verify K^1 = branch^1' \ - 'test `git rev-parse --verify branch^1` \ - = `git rev-parse --verify K^1`' + INPUT_END + git fast-import <input +' +test_expect_success 'K: verify K^1 = branch^1' ' + test `git rev-parse --verify branch^1` \ + = `git rev-parse --verify K^1` +' ### ### series L ### -cat >input <<INPUT_END -blob -mark :1 -data <<EOF -some data -EOF - -blob -mark :2 -data <<EOF -other data -EOF - -commit refs/heads/L -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -create L -COMMIT - -M 644 :1 b. -M 644 :1 b/other -M 644 :1 ba - -commit refs/heads/L -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -update L -COMMIT - -M 644 :2 b. -M 644 :2 b/other -M 644 :2 ba -INPUT_END - -cat >expect <<EXPECT_END -:100644 100644 4268632... 55d3a52... M b. -:040000 040000 0ae5cac... 443c768... M b -:100644 100644 4268632... 55d3a52... M ba -EXPECT_END - -test_expect_success \ - 'L: verify internal tree sorting' \ - 'git fast-import <input && - git diff-tree --abbrev --raw L^ L >output && - test_cmp expect output' - -cat >input <<INPUT_END -blob -mark :1 -data <<EOF -the data -EOF - -commit refs/heads/L2 -committer C O Mitter <committer@example.com> 1112912473 -0700 -data <<COMMIT -init L2 -COMMIT -M 644 :1 a/b/c -M 644 :1 a/b/d -M 644 :1 a/e/f - -commit refs/heads/L2 -committer C O Mitter <committer@example.com> 1112912473 -0700 -data <<COMMIT -update L2 -COMMIT -C a g -C a/e g/b -M 644 :1 g/b/h -INPUT_END - -cat <<EOF >expect -g/b/f -g/b/h -EOF - -test_expect_success \ - 'L: nested tree copy does not corrupt deltas' \ - 'git fast-import <input && +test_expect_success 'L: verify internal tree sorting' ' + cat >input <<-INPUT_END && + blob + mark :1 + data <<EOF + some data + EOF + + blob + mark :2 + data <<EOF + other data + EOF + + commit refs/heads/L + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + create L + COMMIT + + M 644 :1 b. + M 644 :1 b/other + M 644 :1 ba + + commit refs/heads/L + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + update L + COMMIT + + M 644 :2 b. + M 644 :2 b/other + M 644 :2 ba + INPUT_END + + cat >expect <<-EXPECT_END && + :100644 100644 4268632... 55d3a52... M b. + :040000 040000 0ae5cac... 443c768... M b + :100644 100644 4268632... 55d3a52... M ba + EXPECT_END + + git fast-import <input && + git diff-tree --abbrev --raw L^ L >output && + test_cmp expect output +' + +test_expect_success 'L: nested tree copy does not corrupt deltas' ' + cat >input <<-INPUT_END && + blob + mark :1 + data <<EOF + the data + EOF + + commit refs/heads/L2 + committer C O Mitter <committer@example.com> 1112912473 -0700 + data <<COMMIT + init L2 + COMMIT + M 644 :1 a/b/c + M 644 :1 a/b/d + M 644 :1 a/e/f + + commit refs/heads/L2 + committer C O Mitter <committer@example.com> 1112912473 -0700 + data <<COMMIT + update L2 + COMMIT + C a g + C a/e g/b + M 644 :1 g/b/h + INPUT_END + + cat >expect <<-\EOF && + g/b/f + g/b/h + EOF + + test_when_finished "git update-ref -d refs/heads/L2" && + git fast-import <input && git ls-tree L2 g/b/ >tmp && cat tmp | cut -f 2 >actual && test_cmp expect actual && - git fsck `git rev-parse L2`' - -git update-ref -d refs/heads/L2 + git fsck `git rev-parse L2` +' ### ### series M ### -test_tick -cat >input <<INPUT_END -commit refs/heads/M1 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -file rename -COMMIT - -from refs/heads/branch^0 -R file2/newf file2/n.e.w.f - -INPUT_END - -cat >expect <<EOF -:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 file2/newf file2/n.e.w.f -EOF -test_expect_success \ - 'M: rename file in same subdirectory' \ - 'git fast-import <input && - git diff-tree -M -r M1^ M1 >actual && - compare_diff_raw expect actual' - -cat >input <<INPUT_END -commit refs/heads/M2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -file rename -COMMIT - -from refs/heads/branch^0 -R file2/newf i/am/new/to/you - -INPUT_END - -cat >expect <<EOF -:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 file2/newf i/am/new/to/you -EOF -test_expect_success \ - 'M: rename file to new subdirectory' \ - 'git fast-import <input && - git diff-tree -M -r M2^ M2 >actual && - compare_diff_raw expect actual' - -cat >input <<INPUT_END -commit refs/heads/M3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -file rename -COMMIT - -from refs/heads/M2^0 -R i other/sub - -INPUT_END - -cat >expect <<EOF -:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 i/am/new/to/you other/sub/am/new/to/you -EOF -test_expect_success \ - 'M: rename subdirectory to new subdirectory' \ - 'git fast-import <input && - 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' +test_expect_success 'M: rename file in same subdirectory' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/M1 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + file rename + COMMIT + + from refs/heads/branch^0 + R file2/newf file2/n.e.w.f + + INPUT_END + + cat >expect <<-EOF && + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 file2/newf file2/n.e.w.f + EOF + git fast-import <input && + git diff-tree -M -r M1^ M1 >actual && + compare_diff_raw expect actual +' + +test_expect_success 'M: rename file to new subdirectory' ' + cat >input <<-INPUT_END && + commit refs/heads/M2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + file rename + COMMIT + + from refs/heads/branch^0 + R file2/newf i/am/new/to/you + + INPUT_END + + cat >expect <<-EOF && + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 file2/newf i/am/new/to/you + EOF + git fast-import <input && + git diff-tree -M -r M2^ M2 >actual && + compare_diff_raw expect actual +' + +test_expect_success 'M: rename subdirectory to new subdirectory' ' + cat >input <<-INPUT_END && + commit refs/heads/M3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + file rename + COMMIT + + from refs/heads/M2^0 + R i other/sub + + INPUT_END + + cat >expect <<-EOF && + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 i/am/new/to/you other/sub/am/new/to/you + EOF + git fast-import <input && + git diff-tree -M -r M3^ M3 >actual && + compare_diff_raw expect actual +' + +test_expect_success 'M: rename root to subdirectory' ' + 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 + git fast-import <input && + git diff-tree -M -r M4^ M4 >actual && + cat actual && + compare_diff_raw expect actual +' ### ### series N ### -test_tick -cat >input <<INPUT_END -commit refs/heads/N1 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -file copy -COMMIT - -from refs/heads/branch^0 -C file2/newf file2/n.e.w.f - -INPUT_END - -cat >expect <<EOF -:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file2/n.e.w.f -EOF -test_expect_success \ - 'N: copy file in same subdirectory' \ - 'git fast-import <input && - git diff-tree -C --find-copies-harder -r N1^ N1 >actual && - compare_diff_raw expect actual' - -cat >input <<INPUT_END -commit refs/heads/N2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -clean directory copy -COMMIT - -from refs/heads/branch^0 -C file2 file3 - -commit refs/heads/N2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -modify directory copy -COMMIT - -M 644 inline file3/file5 -data <<EOF -$file5_data -EOF - -INPUT_END - -cat >expect <<EOF -:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting file3/file5 -:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf -:100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf -EOF -test_expect_success \ - 'N: copy then modify subdirectory' \ - 'git fast-import <input && - git diff-tree -C --find-copies-harder -r N2^^ N2 >actual && - compare_diff_raw expect actual' - -cat >input <<INPUT_END -commit refs/heads/N3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -dirty directory copy -COMMIT - -from refs/heads/branch^0 -M 644 inline file2/file5 -data <<EOF -$file5_data -EOF - -C file2 file3 -D file2/file5 - -INPUT_END - -test_expect_success \ - 'N: copy dirty subdirectory' \ - 'git fast-import <input && - test `git rev-parse N2^{tree}` = `git rev-parse N3^{tree}`' - -test_expect_success \ - 'N: copy directory by id' \ - 'cat >expect <<-\EOF && +test_expect_success 'N: copy file in same subdirectory' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/N1 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + file copy + COMMIT + + from refs/heads/branch^0 + C file2/newf file2/n.e.w.f + + INPUT_END + + cat >expect <<-EOF && + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file2/n.e.w.f + EOF + git fast-import <input && + git diff-tree -C --find-copies-harder -r N1^ N1 >actual && + compare_diff_raw expect actual +' + +test_expect_success 'N: copy then modify subdirectory' ' + cat >input <<-INPUT_END && + commit refs/heads/N2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + clean directory copy + COMMIT + + from refs/heads/branch^0 + C file2 file3 + + commit refs/heads/N2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + modify directory copy + COMMIT + + M 644 inline file3/file5 + data <<EOF + $file5_data + EOF + + INPUT_END + + cat >expect <<-EOF && + :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting file3/file5 :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf EOF - subdir=$(git rev-parse refs/heads/branch^0:file2) && - cat >input <<-INPUT_END && + git fast-import <input && + git diff-tree -C --find-copies-harder -r N2^^ N2 >actual && + compare_diff_raw expect actual +' + +test_expect_success 'N: copy dirty subdirectory' ' + cat >input <<-INPUT_END && + commit refs/heads/N3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + dirty directory copy + COMMIT + + from refs/heads/branch^0 + M 644 inline file2/file5 + data <<EOF + $file5_data + EOF + + C file2 file3 + D file2/file5 + + INPUT_END + + git fast-import <input && + test `git rev-parse N2^{tree}` = `git rev-parse N3^{tree}` +' + +test_expect_success 'N: copy directory by id' ' + cat >expect <<-\EOF && + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf + :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf + EOF + subdir=$(git rev-parse refs/heads/branch^0:file2) && + cat >input <<-INPUT_END && commit refs/heads/N4 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1127,9 +1125,10 @@ test_expect_success \ from refs/heads/branch^0 M 040000 $subdir file3 INPUT_END - git fast-import <input && - git diff-tree -C --find-copies-harder -r N4^ N4 >actual && - compare_diff_raw expect actual' + git fast-import <input && + git diff-tree -C --find-copies-harder -r N4^ N4 >actual && + compare_diff_raw expect actual +' test_expect_success PIPE 'N: read and copy directory' ' cat >expect <<-\EOF && @@ -1202,14 +1201,13 @@ test_expect_success PIPE 'N: empty directory reads as missing' ' test_cmp expect actual ' -test_expect_success \ - 'N: copy root directory by tree hash' \ - 'cat >expect <<-\EOF && +test_expect_success 'N: copy root directory by tree hash' ' + cat >expect <<-\EOF && :100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D file3/newf :100644 000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 0000000000000000000000000000000000000000 D file3/oldf EOF - root=$(git rev-parse refs/heads/branch^0^{tree}) && - cat >input <<-INPUT_END && + root=$(git rev-parse refs/heads/branch^0^{tree}) && + cat >input <<-INPUT_END && commit refs/heads/N6 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1219,20 +1217,20 @@ test_expect_success \ from refs/heads/branch^0 M 040000 $root "" INPUT_END - git fast-import <input && - git diff-tree -C --find-copies-harder -r N4 N6 >actual && - compare_diff_raw expect actual' + git fast-import <input && + git diff-tree -C --find-copies-harder -r N4 N6 >actual && + compare_diff_raw expect actual +' -test_expect_success \ - 'N: copy root by path' \ - 'cat >expect <<-\EOF && +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 && + cat >input <<-INPUT_END && commit refs/heads/N-copy-root-path committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1242,21 +1240,21 @@ test_expect_success \ 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' + 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 && +test_expect_success 'N: delete directory by copying' ' + cat >expect <<-\EOF && OBJID :100644 000000 OBJID OBJID D foo/bar/qux OBJID :000000 100644 OBJID OBJID A foo/bar/baz :000000 100644 OBJID OBJID A foo/bar/qux EOF - empty_tree=$(git mktree </dev/null) && - cat >input <<-INPUT_END && + empty_tree=$(git mktree </dev/null) && + cat >input <<-INPUT_END && commit refs/heads/N-delete committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1282,21 +1280,21 @@ test_expect_success \ M 040000 $empty_tree foo/bar/qux INPUT_END - git fast-import <input && - git rev-list N-delete | + git fast-import <input && + git rev-list N-delete | git diff-tree -r --stdin --root --always | sed -e "s/$_x40/OBJID/g" >actual && - test_cmp expect actual' + test_cmp expect actual +' -test_expect_success \ - 'N: modify copied tree' \ - 'cat >expect <<-\EOF && +test_expect_success 'N: modify copied tree' ' + cat >expect <<-\EOF && :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting file3/file5 :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf EOF - subdir=$(git rev-parse refs/heads/branch^0:file2) && - cat >input <<-INPUT_END && + subdir=$(git rev-parse refs/heads/branch^0:file2) && + cat >input <<-INPUT_END && commit refs/heads/N5 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1317,14 +1315,14 @@ test_expect_success \ $file5_data EOF INPUT_END - git fast-import <input && - git diff-tree -C --find-copies-harder -r N5^^ N5 >actual && - compare_diff_raw expect actual' - -test_expect_success \ - 'N: reject foo/ syntax' \ - 'subdir=$(git rev-parse refs/heads/branch^0:file2) && - test_must_fail git fast-import <<-INPUT_END + git fast-import <input && + git diff-tree -C --find-copies-harder -r N5^^ N5 >actual && + compare_diff_raw expect actual +' + +test_expect_success 'N: reject foo/ syntax' ' + subdir=$(git rev-parse refs/heads/branch^0:file2) && + test_must_fail git fast-import <<-INPUT_END commit refs/heads/N5B committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1333,11 +1331,11 @@ test_expect_success \ from refs/heads/branch^0 M 040000 $subdir file3/ - INPUT_END' + INPUT_END +' -test_expect_success \ - 'N: reject foo/ syntax in copy source' \ - 'test_must_fail git fast-import <<-INPUT_END +test_expect_success 'N: reject foo/ syntax in copy source' ' + test_must_fail git fast-import <<-INPUT_END commit refs/heads/N5C committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1346,11 +1344,11 @@ test_expect_success \ from refs/heads/branch^0 C file2/ file3 - INPUT_END' + INPUT_END +' -test_expect_success \ - 'N: reject foo/ syntax in rename source' \ - 'test_must_fail git fast-import <<-INPUT_END +test_expect_success 'N: reject foo/ syntax in rename source' ' + test_must_fail git fast-import <<-INPUT_END commit refs/heads/N5D committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1359,11 +1357,11 @@ test_expect_success \ from refs/heads/branch^0 R file2/ file3 - INPUT_END' + INPUT_END +' -test_expect_success \ - 'N: reject foo/ syntax in ls argument' \ - 'test_must_fail git fast-import <<-INPUT_END +test_expect_success 'N: reject foo/ syntax in ls argument' ' + test_must_fail git fast-import <<-INPUT_END commit refs/heads/N5E committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1372,13 +1370,13 @@ test_expect_success \ from refs/heads/branch^0 ls "file2/" - INPUT_END' + INPUT_END +' -test_expect_success \ - 'N: copy to root by id and modify' \ - 'echo "hello, world" >expect.foo && - echo hello >expect.bar && - git fast-import <<-SETUP_END && +test_expect_success 'N: copy to root by id and modify' ' + echo "hello, world" >expect.foo && + echo hello >expect.bar && + git fast-import <<-SETUP_END && commit refs/heads/N7 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1392,8 +1390,8 @@ test_expect_success \ EOF SETUP_END - tree=$(git rev-parse --verify N7:) && - git fast-import <<-INPUT_END && + tree=$(git rev-parse --verify N7:) && + git fast-import <<-INPUT_END && commit refs/heads/N8 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1406,15 +1404,15 @@ test_expect_success \ hello, world EOF INPUT_END - git show N8:foo/foo >actual.foo && - git show N8:foo/bar >actual.bar && - test_cmp expect.foo actual.foo && - test_cmp expect.bar actual.bar' - -test_expect_success \ - 'N: extract subtree' \ - 'branch=$(git rev-parse --verify refs/heads/branch^{tree}) && - cat >input <<-INPUT_END && + git show N8:foo/foo >actual.foo && + git show N8:foo/bar >actual.bar && + test_cmp expect.foo actual.foo && + test_cmp expect.bar actual.bar +' + +test_expect_success 'N: extract subtree' ' + branch=$(git rev-parse --verify refs/heads/branch^{tree}) && + cat >input <<-INPUT_END && commit refs/heads/N9 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1424,14 +1422,14 @@ test_expect_success \ M 040000 $branch "" C "newdir" "" INPUT_END - git fast-import <input && - git diff --exit-code branch:newdir N9' - -test_expect_success \ - 'N: modify subtree, extract it, and modify again' \ - 'echo hello >expect.baz && - echo hello, world >expect.qux && - git fast-import <<-SETUP_END && + git fast-import <input && + git diff --exit-code branch:newdir N9 +' + +test_expect_success 'N: modify subtree, extract it, and modify again' ' + echo hello >expect.baz && + echo hello, world >expect.qux && + git fast-import <<-SETUP_END && commit refs/heads/N10 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1445,8 +1443,8 @@ test_expect_success \ EOF SETUP_END - tree=$(git rev-parse --verify N10:) && - git fast-import <<-INPUT_END && + tree=$(git rev-parse --verify N10:) && + git fast-import <<-INPUT_END && commit refs/heads/N11 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1461,676 +1459,692 @@ test_expect_success \ R "foo" "" C "bar/qux" "bar/quux" INPUT_END - git show N11:bar/baz >actual.baz && - git show N11:bar/qux >actual.qux && - git show N11:bar/quux >actual.quux && - test_cmp expect.baz actual.baz && - test_cmp expect.qux actual.qux && - test_cmp expect.qux actual.quux' + git show N11:bar/baz >actual.baz && + git show N11:bar/qux >actual.qux && + git show N11:bar/quux >actual.quux && + test_cmp expect.baz actual.baz && + test_cmp expect.qux actual.qux && + test_cmp expect.qux actual.quux' ### ### series O ### -cat >input <<INPUT_END -#we will -commit refs/heads/O1 -# -- ignore all of this text -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -# $GIT_COMMITTER_NAME has inserted here for his benefit. -data <<COMMIT -dirty directory copy -COMMIT - -# don't forget the import blank line! -# -# yes, we started from our usual base of branch^0. -# i like branch^0. -from refs/heads/branch^0 -# and we need to reuse file2/file5 from N3 above. -M 644 inline file2/file5 -# otherwise the tree will be different -data <<EOF -$file5_data -EOF - -# don't forget to copy file2 to file3 -C file2 file3 -# -# or to delete file5 from file2. -D file2/file5 -# are we done yet? - -INPUT_END - -test_expect_success \ - 'O: comments are all skipped' \ - 'git fast-import <input && - test `git rev-parse N3` = `git rev-parse O1`' - -cat >input <<INPUT_END -commit refs/heads/O2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -dirty directory copy -COMMIT -from refs/heads/branch^0 -M 644 inline file2/file5 -data <<EOF -$file5_data -EOF -C file2 file3 -D file2/file5 - -INPUT_END - -test_expect_success \ - 'O: blank lines not necessary after data commands' \ - 'git fast-import <input && - test `git rev-parse N3` = `git rev-parse O2`' - -test_expect_success \ - 'O: repack before next test' \ - 'git repack -a -d' - -cat >input <<INPUT_END -commit refs/heads/O3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zstring -COMMIT -commit refs/heads/O3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zof -COMMIT -checkpoint -commit refs/heads/O3 -mark :5 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zempty -COMMIT -checkpoint -commit refs/heads/O3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zcommits -COMMIT -reset refs/tags/O3-2nd -from :5 -reset refs/tags/O3-3rd -from :5 -INPUT_END - -cat >expect <<INPUT_END -string -of -empty -commits -INPUT_END -test_expect_success \ - 'O: blank lines not necessary after other commands' \ - 'git fast-import <input && - test 8 = `find .git/objects/pack -type f | wc -l` && - test `git rev-parse refs/tags/O3-2nd` = `git rev-parse O3^` && - git log --reverse --pretty=oneline O3 | sed s/^.*z// >actual && - test_cmp expect actual' - -cat >input <<INPUT_END -commit refs/heads/O4 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zstring -COMMIT -commit refs/heads/O4 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zof -COMMIT -progress Two commits down, 2 to go! -commit refs/heads/O4 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zempty -COMMIT -progress Three commits down, 1 to go! -commit refs/heads/O4 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zcommits -COMMIT -progress I'm done! -INPUT_END -test_expect_success \ - 'O: progress outputs as requested by input' \ - 'git fast-import <input >actual && - grep "progress " <input >expect && - test_cmp expect actual' +test_expect_success 'O: comments are all skipped' ' + cat >input <<-INPUT_END && + #we will + commit refs/heads/O1 + # -- ignore all of this text + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + # $GIT_COMMITTER_NAME has inserted here for his benefit. + data <<COMMIT + dirty directory copy + COMMIT + + # do not forget the import blank line! + # + # yes, we started from our usual base of branch^0. + # i like branch^0. + from refs/heads/branch^0 + # and we need to reuse file2/file5 from N3 above. + M 644 inline file2/file5 + # otherwise the tree will be different + data <<EOF + $file5_data + EOF + + # do not forget to copy file2 to file3 + C file2 file3 + # + # or to delete file5 from file2. + D file2/file5 + # are we done yet? + + INPUT_END + + git fast-import <input && + test `git rev-parse N3` = `git rev-parse O1` +' + +test_expect_success 'O: blank lines not necessary after data commands' ' + cat >input <<-INPUT_END && + commit refs/heads/O2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + dirty directory copy + COMMIT + from refs/heads/branch^0 + M 644 inline file2/file5 + data <<EOF + $file5_data + EOF + C file2 file3 + D file2/file5 + + INPUT_END + + git fast-import <input && + test `git rev-parse N3` = `git rev-parse O2` +' + +test_expect_success 'O: repack before next test' ' + git repack -a -d +' + +test_expect_success 'O: blank lines not necessary after other commands' ' + cat >input <<-INPUT_END && + commit refs/heads/O3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zstring + COMMIT + commit refs/heads/O3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zof + COMMIT + checkpoint + commit refs/heads/O3 + mark :5 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zempty + COMMIT + checkpoint + commit refs/heads/O3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zcommits + COMMIT + reset refs/tags/O3-2nd + from :5 + reset refs/tags/O3-3rd + from :5 + INPUT_END + + cat >expect <<-INPUT_END && + string + of + empty + commits + INPUT_END + + git fast-import <input && + test 8 = `find .git/objects/pack -type f | wc -l` && + test `git rev-parse refs/tags/O3-2nd` = `git rev-parse O3^` && + git log --reverse --pretty=oneline O3 | sed s/^.*z// >actual && + test_cmp expect actual +' + +test_expect_success 'O: progress outputs as requested by input' ' + cat >input <<-INPUT_END && + commit refs/heads/O4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zstring + COMMIT + commit refs/heads/O4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zof + COMMIT + progress Two commits down, 2 to go! + commit refs/heads/O4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zempty + COMMIT + progress Three commits down, 1 to go! + commit refs/heads/O4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zcommits + COMMIT + progress done! + INPUT_END + git fast-import <input >actual && + grep "progress " <input >expect && + test_cmp expect actual +' ### ### series P (gitlinks) ### -cat >input <<INPUT_END -blob -mark :1 -data 10 -test file - -reset refs/heads/sub -commit refs/heads/sub -mark :2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data 12 -sub_initial -M 100644 :1 file - -blob -mark :3 -data <<DATAEND -[submodule "sub"] - path = sub - url = "`pwd`/sub" -DATAEND - -commit refs/heads/subuse1 -mark :4 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data 8 -initial -from refs/heads/master -M 100644 :3 .gitmodules -M 160000 :2 sub - -blob -mark :5 -data 20 -test file -more data - -commit refs/heads/sub -mark :6 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data 11 -sub_second -from :2 -M 100644 :5 file - -commit refs/heads/subuse1 -mark :7 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data 7 -second -from :4 -M 160000 :6 sub - -INPUT_END - -test_expect_success \ - 'P: superproject & submodule mix' \ - 'git fast-import <input && - git checkout subuse1 && - rm -rf sub && mkdir sub && (cd sub && - git init && - git fetch --update-head-ok .. refs/heads/sub:refs/heads/master && - git checkout master) && - git submodule init && - git submodule update' - -SUBLAST=$(git rev-parse --verify sub) -SUBPREV=$(git rev-parse --verify sub^) - -cat >input <<INPUT_END -blob -mark :1 -data <<DATAEND -[submodule "sub"] - path = sub - url = "`pwd`/sub" -DATAEND - -commit refs/heads/subuse2 -mark :2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data 8 -initial -from refs/heads/master -M 100644 :1 .gitmodules -M 160000 $SUBPREV sub - -commit refs/heads/subuse2 -mark :3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data 7 -second -from :2 -M 160000 $SUBLAST sub - -INPUT_END - -test_expect_success \ - 'P: verbatim SHA gitlinks' \ - 'git branch -D sub && - git gc && git prune && - git fast-import <input && - test $(git rev-parse --verify subuse2) = $(git rev-parse --verify subuse1)' - -test_tick -cat >input <<INPUT_END -commit refs/heads/subuse3 -mark :1 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -corrupt -COMMIT - -from refs/heads/subuse2 -M 160000 inline sub -data <<DATA -$SUBPREV -DATA - -INPUT_END +test_expect_success 'P: superproject & submodule mix' ' + cat >input <<-INPUT_END && + blob + mark :1 + data 10 + test file -test_expect_success 'P: fail on inline gitlink' ' - test_must_fail git fast-import <input' + reset refs/heads/sub + commit refs/heads/sub + mark :2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 12 + sub_initial + M 100644 :1 file + + blob + mark :3 + data <<DATAEND + [submodule "sub"] + path = sub + url = "`pwd`/sub" + DATAEND + + commit refs/heads/subuse1 + mark :4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 8 + initial + from refs/heads/master + M 100644 :3 .gitmodules + M 160000 :2 sub + + blob + mark :5 + data 20 + test file + more data + + commit refs/heads/sub + mark :6 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 11 + sub_second + from :2 + M 100644 :5 file + + commit refs/heads/subuse1 + mark :7 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 7 + second + from :4 + M 160000 :6 sub + + INPUT_END + + git fast-import <input && + git checkout subuse1 && + rm -rf sub && + mkdir sub && + ( + cd sub && + git init && + git fetch --update-head-ok .. refs/heads/sub:refs/heads/master && + git checkout master + ) && + git submodule init && + git submodule update +' + +test_expect_success 'P: verbatim SHA gitlinks' ' + SUBLAST=$(git rev-parse --verify sub) && + SUBPREV=$(git rev-parse --verify sub^) && + + cat >input <<-INPUT_END && + blob + mark :1 + data <<DATAEND + [submodule "sub"] + path = sub + url = "`pwd`/sub" + DATAEND + + commit refs/heads/subuse2 + mark :2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 8 + initial + from refs/heads/master + M 100644 :1 .gitmodules + M 160000 $SUBPREV sub -test_tick -cat >input <<INPUT_END -blob -mark :1 -data <<DATA -$SUBPREV -DATA + commit refs/heads/subuse2 + mark :3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 7 + second + from :2 + M 160000 $SUBLAST sub -commit refs/heads/subuse3 -mark :2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -corrupt -COMMIT + INPUT_END -from refs/heads/subuse2 -M 160000 :1 sub + git branch -D sub && + git gc && + git prune && + git fast-import <input && + test $(git rev-parse --verify subuse2) = $(git rev-parse --verify subuse1) +' + +test_expect_success 'P: fail on inline gitlink' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/subuse3 + mark :1 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + corrupt + COMMIT -INPUT_END + from refs/heads/subuse2 + M 160000 inline sub + data <<DATA + $SUBPREV + DATA + + INPUT_END + + test_must_fail git fast-import <input +' test_expect_success 'P: fail on blob mark in gitlink' ' - test_must_fail git fast-import <input' + test_tick && + cat >input <<-INPUT_END && + blob + mark :1 + data <<DATA + $SUBPREV + DATA + + commit refs/heads/subuse3 + mark :2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + corrupt + COMMIT + + from refs/heads/subuse2 + M 160000 :1 sub + + INPUT_END + + test_must_fail git fast-import <input +' ### ### series Q (notes) ### -note1_data="The first note for the first commit" -note2_data="The first note for the second commit" -note3_data="The first note for the third commit" -note1b_data="The second note for the first commit" -note1c_data="The third note for the first commit" -note2b_data="The second note for the second commit" - -test_tick -cat >input <<INPUT_END -blob -mark :2 -data <<EOF -$file2_data -EOF - -commit refs/heads/notes-test -mark :3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -first (:3) -COMMIT - -M 644 :2 file2 - -blob -mark :4 -data $file4_len -$file4_data -commit refs/heads/notes-test -mark :5 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -second (:5) -COMMIT - -M 644 :4 file4 - -commit refs/heads/notes-test -mark :6 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -third (:6) -COMMIT - -M 644 inline file5 -data <<EOF -$file5_data -EOF - -M 755 inline file6 -data <<EOF -$file6_data -EOF - -blob -mark :7 -data <<EOF -$note1_data -EOF - -blob -mark :8 -data <<EOF -$note2_data -EOF - -commit refs/notes/foobar -mark :9 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -notes (:9) -COMMIT - -N :7 :3 -N :8 :5 -N inline :6 -data <<EOF -$note3_data -EOF - -commit refs/notes/foobar -mark :10 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -notes (:10) -COMMIT - -N inline :3 -data <<EOF -$note1b_data -EOF - -commit refs/notes/foobar2 -mark :11 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -notes (:11) -COMMIT - -N inline :3 -data <<EOF -$note1c_data -EOF - -commit refs/notes/foobar -mark :12 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -notes (:12) -COMMIT - -deleteall -N inline :5 -data <<EOF -$note2b_data -EOF - -INPUT_END - -test_expect_success \ - 'Q: commit notes' \ - 'git fast-import <input && - git whatchanged notes-test' +test_expect_success 'Q: commit notes' ' + note1_data="The first note for the first commit" && + note2_data="The first note for the second commit" && + note3_data="The first note for the third commit" && + note1b_data="The second note for the first commit" && + note1c_data="The third note for the first commit" && + note2b_data="The second note for the second commit" && + + test_tick && + cat >input <<-INPUT_END && + blob + mark :2 + data <<EOF + $file2_data + EOF + + commit refs/heads/notes-test + mark :3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + first (:3) + COMMIT + + M 644 :2 file2 + + blob + mark :4 + data $file4_len + $file4_data + commit refs/heads/notes-test + mark :5 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + second (:5) + COMMIT + + M 644 :4 file4 + + commit refs/heads/notes-test + mark :6 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + third (:6) + COMMIT + + M 644 inline file5 + data <<EOF + $file5_data + EOF + + M 755 inline file6 + data <<EOF + $file6_data + EOF + + blob + mark :7 + data <<EOF + $note1_data + EOF + + blob + mark :8 + data <<EOF + $note2_data + EOF + + commit refs/notes/foobar + mark :9 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + notes (:9) + COMMIT + + N :7 :3 + N :8 :5 + N inline :6 + data <<EOF + $note3_data + EOF + + commit refs/notes/foobar + mark :10 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + notes (:10) + COMMIT + + N inline :3 + data <<EOF + $note1b_data + EOF + + commit refs/notes/foobar2 + mark :11 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + notes (:11) + COMMIT + + N inline :3 + data <<EOF + $note1c_data + EOF + + commit refs/notes/foobar + mark :12 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + notes (:12) + COMMIT + + deleteall + N inline :5 + data <<EOF + $note2b_data + EOF + + INPUT_END + + git fast-import <input && + git whatchanged notes-test +' test_expect_success 'Q: verify pack' ' verify_packs ' -commit1=$(git rev-parse notes-test~2) -commit2=$(git rev-parse notes-test^) -commit3=$(git rev-parse notes-test) - -cat >expect <<EOF -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -first (:3) -EOF -test_expect_success \ - 'Q: verify first commit' \ - 'git cat-file commit notes-test~2 | sed 1d >actual && - test_cmp expect actual' - -cat >expect <<EOF -parent $commit1 -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -second (:5) -EOF -test_expect_success \ - 'Q: verify second commit' \ - 'git cat-file commit notes-test^ | sed 1d >actual && - test_cmp expect actual' - -cat >expect <<EOF -parent $commit2 -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -third (:6) -EOF -test_expect_success \ - 'Q: verify third commit' \ - 'git cat-file commit notes-test | sed 1d >actual && - test_cmp expect actual' - -cat >expect <<EOF -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -notes (:9) -EOF -test_expect_success \ - 'Q: verify first notes commit' \ - 'git cat-file commit refs/notes/foobar~2 | sed 1d >actual && - test_cmp expect actual' - -cat >expect.unsorted <<EOF -100644 blob $commit1 -100644 blob $commit2 -100644 blob $commit3 -EOF -cat expect.unsorted | sort >expect -test_expect_success \ - 'Q: verify first notes tree' \ - 'git cat-file -p refs/notes/foobar~2^{tree} | sed "s/ [0-9a-f]* / /" >actual && - test_cmp expect actual' - -echo "$note1_data" >expect -test_expect_success \ - 'Q: verify first note for first commit' \ - 'git cat-file blob refs/notes/foobar~2:$commit1 >actual && test_cmp expect actual' - -echo "$note2_data" >expect -test_expect_success \ - 'Q: verify first note for second commit' \ - 'git cat-file blob refs/notes/foobar~2:$commit2 >actual && test_cmp expect actual' - -echo "$note3_data" >expect -test_expect_success \ - 'Q: verify first note for third commit' \ - 'git cat-file blob refs/notes/foobar~2:$commit3 >actual && test_cmp expect actual' - -cat >expect <<EOF -parent `git rev-parse --verify refs/notes/foobar~2` -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -notes (:10) -EOF -test_expect_success \ - 'Q: verify second notes commit' \ - 'git cat-file commit refs/notes/foobar^ | sed 1d >actual && - test_cmp expect actual' - -cat >expect.unsorted <<EOF -100644 blob $commit1 -100644 blob $commit2 -100644 blob $commit3 -EOF -cat expect.unsorted | sort >expect -test_expect_success \ - 'Q: verify second notes tree' \ - 'git cat-file -p refs/notes/foobar^^{tree} | sed "s/ [0-9a-f]* / /" >actual && - test_cmp expect actual' - -echo "$note1b_data" >expect -test_expect_success \ - 'Q: verify second note for first commit' \ - 'git cat-file blob refs/notes/foobar^:$commit1 >actual && test_cmp expect actual' - -echo "$note2_data" >expect -test_expect_success \ - 'Q: verify first note for second commit' \ - 'git cat-file blob refs/notes/foobar^:$commit2 >actual && test_cmp expect actual' - -echo "$note3_data" >expect -test_expect_success \ - 'Q: verify first note for third commit' \ - 'git cat-file blob refs/notes/foobar^:$commit3 >actual && test_cmp expect actual' - -cat >expect <<EOF -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -notes (:11) -EOF -test_expect_success \ - 'Q: verify third notes commit' \ - 'git cat-file commit refs/notes/foobar2 | sed 1d >actual && - test_cmp expect actual' - -cat >expect.unsorted <<EOF -100644 blob $commit1 -EOF -cat expect.unsorted | sort >expect -test_expect_success \ - 'Q: verify third notes tree' \ - 'git cat-file -p refs/notes/foobar2^{tree} | sed "s/ [0-9a-f]* / /" >actual && - test_cmp expect actual' - -echo "$note1c_data" >expect -test_expect_success \ - 'Q: verify third note for first commit' \ - 'git cat-file blob refs/notes/foobar2:$commit1 >actual && test_cmp expect actual' - -cat >expect <<EOF -parent `git rev-parse --verify refs/notes/foobar^` -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -notes (:12) -EOF -test_expect_success \ - 'Q: verify fourth notes commit' \ - 'git cat-file commit refs/notes/foobar | sed 1d >actual && - test_cmp expect actual' - -cat >expect.unsorted <<EOF -100644 blob $commit2 -EOF -cat expect.unsorted | sort >expect -test_expect_success \ - 'Q: verify fourth notes tree' \ - 'git cat-file -p refs/notes/foobar^{tree} | sed "s/ [0-9a-f]* / /" >actual && - test_cmp expect actual' - -echo "$note2b_data" >expect -test_expect_success \ - 'Q: verify second note for second commit' \ - 'git cat-file blob refs/notes/foobar:$commit2 >actual && test_cmp expect actual' - -cat >input <<EOF -reset refs/heads/Q0 - -commit refs/heads/note-Q0 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -Note for an empty branch. -COMMIT - -N inline refs/heads/Q0 -data <<NOTE -some note -NOTE -EOF -test_expect_success \ - 'Q: deny note on empty branch' \ - 'test_must_fail git fast-import <input' +test_expect_success 'Q: verify first commit' ' + commit1=$(git rev-parse notes-test~2) && + commit2=$(git rev-parse notes-test^) && + commit3=$(git rev-parse notes-test) && + + cat >expect <<-EOF && + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + first (:3) + EOF + git cat-file commit notes-test~2 | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify second commit' ' + cat >expect <<-EOF && + parent $commit1 + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + second (:5) + EOF + git cat-file commit notes-test^ | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify third commit' ' + cat >expect <<-EOF && + parent $commit2 + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + third (:6) + EOF + git cat-file commit notes-test | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first notes commit' ' + cat >expect <<-EOF && + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + notes (:9) + EOF + git cat-file commit refs/notes/foobar~2 | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first notes tree' ' + cat >expect.unsorted <<-EOF && + 100644 blob $commit1 + 100644 blob $commit2 + 100644 blob $commit3 + EOF + cat expect.unsorted | sort >expect && + git cat-file -p refs/notes/foobar~2^{tree} | sed "s/ [0-9a-f]* / /" >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first note for first commit' ' + echo "$note1_data" >expect && + git cat-file blob refs/notes/foobar~2:$commit1 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first note for second commit' ' + echo "$note2_data" >expect && + git cat-file blob refs/notes/foobar~2:$commit2 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first note for third commit' ' + echo "$note3_data" >expect && + git cat-file blob refs/notes/foobar~2:$commit3 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify second notes commit' ' + cat >expect <<-EOF && + parent `git rev-parse --verify refs/notes/foobar~2` + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + notes (:10) + EOF + git cat-file commit refs/notes/foobar^ | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify second notes tree' ' + cat >expect.unsorted <<-EOF && + 100644 blob $commit1 + 100644 blob $commit2 + 100644 blob $commit3 + EOF + cat expect.unsorted | sort >expect && + git cat-file -p refs/notes/foobar^^{tree} | sed "s/ [0-9a-f]* / /" >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify second note for first commit' ' + echo "$note1b_data" >expect && + git cat-file blob refs/notes/foobar^:$commit1 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first note for second commit' ' + echo "$note2_data" >expect && + git cat-file blob refs/notes/foobar^:$commit2 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first note for third commit' ' + echo "$note3_data" >expect && + git cat-file blob refs/notes/foobar^:$commit3 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify third notes commit' ' + cat >expect <<-EOF && + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + notes (:11) + EOF + git cat-file commit refs/notes/foobar2 | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify third notes tree' ' + cat >expect.unsorted <<-EOF && + 100644 blob $commit1 + EOF + cat expect.unsorted | sort >expect && + git cat-file -p refs/notes/foobar2^{tree} | sed "s/ [0-9a-f]* / /" >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify third note for first commit' ' + echo "$note1c_data" >expect && + git cat-file blob refs/notes/foobar2:$commit1 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify fourth notes commit' ' + cat >expect <<-EOF && + parent `git rev-parse --verify refs/notes/foobar^` + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + notes (:12) + EOF + git cat-file commit refs/notes/foobar | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify fourth notes tree' ' + cat >expect.unsorted <<-EOF && + 100644 blob $commit2 + EOF + cat expect.unsorted | sort >expect && + git cat-file -p refs/notes/foobar^{tree} | sed "s/ [0-9a-f]* / /" >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify second note for second commit' ' + echo "$note2b_data" >expect && + git cat-file blob refs/notes/foobar:$commit2 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: deny note on empty branch' ' + cat >input <<-EOF && + reset refs/heads/Q0 + + commit refs/heads/note-Q0 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + Note for an empty branch. + COMMIT + + N inline refs/heads/Q0 + data <<NOTE + some note + NOTE + EOF + test_must_fail git fast-import <input +' ### ### series R (feature and option) ### -cat >input <<EOF -feature no-such-feature-exists -EOF - test_expect_success 'R: abort on unsupported feature' ' + cat >input <<-EOF && + feature no-such-feature-exists + EOF + test_must_fail git fast-import <input ' -cat >input <<EOF -feature date-format=now -EOF - test_expect_success 'R: supported feature is accepted' ' + cat >input <<-EOF && + feature date-format=now + EOF + git fast-import <input ' -cat >input << EOF -blob -data 3 -hi -feature date-format=now -EOF - test_expect_success 'R: abort on receiving feature after data command' ' + cat >input <<-EOF && + blob + data 3 + hi + feature date-format=now + EOF + test_must_fail git fast-import <input ' -cat >input << EOF -feature import-marks=git.marks -feature import-marks=git2.marks -EOF - test_expect_success 'R: only one import-marks feature allowed per stream' ' + cat >input <<-EOF && + feature import-marks=git.marks + feature import-marks=git2.marks + EOF + test_must_fail git fast-import <input ' -cat >input << EOF -feature export-marks=git.marks -blob -mark :1 -data 3 -hi +test_expect_success 'R: export-marks feature results in a marks file being created' ' + cat >input <<-EOF && + feature export-marks=git.marks + blob + mark :1 + data 3 + hi -EOF + EOF -test_expect_success \ - 'R: export-marks feature results in a marks file being created' \ - 'cat input | git fast-import && - grep :1 git.marks' + cat input | git fast-import && + grep :1 git.marks +' -test_expect_success \ - 'R: export-marks options can be overridden by commandline options' \ - 'cat input | git fast-import --export-marks=other.marks && - grep :1 other.marks' +test_expect_success 'R: export-marks options can be overridden by commandline options' ' + cat input | git fast-import --export-marks=other.marks && + grep :1 other.marks +' test_expect_success 'R: catch typo in marks file name' ' test_must_fail git fast-import --import-marks=nonexistent.marks </dev/null && @@ -2234,62 +2248,62 @@ test_expect_success 'R: feature import-marks-if-exists' ' test_cmp expect io.marks ' -cat >input << EOF -feature import-marks=marks.out -feature export-marks=marks.new -EOF - -test_expect_success \ - 'R: import to output marks works without any content' \ - 'cat input | git fast-import && - test_cmp marks.out marks.new' +test_expect_success 'R: import to output marks works without any content' ' + cat >input <<-EOF && + feature import-marks=marks.out + feature export-marks=marks.new + EOF -cat >input <<EOF -feature import-marks=nonexistent.marks -feature export-marks=marks.new -EOF + cat input | git fast-import && + test_cmp marks.out marks.new +' -test_expect_success \ - 'R: import marks prefers commandline marks file over the stream' \ - 'cat input | git fast-import --import-marks=marks.out && - test_cmp marks.out marks.new' +test_expect_success 'R: import marks prefers commandline marks file over the stream' ' + cat >input <<-EOF && + feature import-marks=nonexistent.marks + feature export-marks=marks.new + EOF + cat input | git fast-import --import-marks=marks.out && + test_cmp marks.out marks.new +' -cat >input <<EOF -feature import-marks=nonexistent.marks -feature export-marks=combined.marks -EOF test_expect_success 'R: multiple --import-marks= should be honoured' ' - head -n2 marks.out > one.marks && - tail -n +3 marks.out > two.marks && - git fast-import --import-marks=one.marks --import-marks=two.marks <input && - test_cmp marks.out combined.marks -' + cat >input <<-EOF && + feature import-marks=nonexistent.marks + feature export-marks=combined.marks + EOF -cat >input <<EOF -feature relative-marks -feature import-marks=relative.in -feature export-marks=relative.out -EOF + head -n2 marks.out > one.marks && + tail -n +3 marks.out > two.marks && + git fast-import --import-marks=one.marks --import-marks=two.marks <input && + test_cmp marks.out combined.marks +' test_expect_success 'R: feature relative-marks should be honoured' ' - mkdir -p .git/info/fast-import/ && - cp marks.new .git/info/fast-import/relative.in && - git fast-import <input && - test_cmp marks.new .git/info/fast-import/relative.out -' + cat >input <<-EOF && + feature relative-marks + feature import-marks=relative.in + feature export-marks=relative.out + EOF -cat >input <<EOF -feature relative-marks -feature import-marks=relative.in -feature no-relative-marks -feature export-marks=non-relative.out -EOF + mkdir -p .git/info/fast-import/ && + cp marks.new .git/info/fast-import/relative.in && + git fast-import <input && + test_cmp marks.new .git/info/fast-import/relative.out +' test_expect_success 'R: feature no-relative-marks should be honoured' ' - git fast-import <input && - test_cmp marks.new non-relative.out + cat >input <<-EOF && + feature relative-marks + feature import-marks=relative.in + feature no-relative-marks + feature export-marks=non-relative.out + EOF + + git fast-import <input && + test_cmp marks.new non-relative.out ' test_expect_success 'R: feature ls supported' ' @@ -2330,15 +2344,28 @@ test_expect_success !MINGW 'R: in-stream cat-blob-fd not respected' ' cat-blob $blob EOF test_cmp expect actual.3 && - test_cmp empty actual.1 && + test_must_be_empty actual.1 && git fast-import 3>actual.3 >actual.1 <<-EOF && option cat-blob-fd=3 cat-blob $blob EOF - test_cmp empty actual.3 && + test_must_be_empty actual.3 && test_cmp expect actual.1 ' +test_expect_success !MINGW 'R: print mark for new blob' ' + echo "effluentish" | git hash-object --stdin >expect && + git fast-import --cat-blob-fd=6 6>actual <<-\EOF && + blob + mark :1 + data <<BLOB_END + effluentish + BLOB_END + get-mark :1 + EOF + test_cmp expect actual +' + test_expect_success !MINGW 'R: print new blob' ' blob=$(echo "yep yep yep" | git hash-object --stdin) && cat >expect <<-EOF && @@ -2536,17 +2563,17 @@ test_expect_success PIPE 'R: print staged blob within commit' ' test_cmp expect actual ' -cat >input << EOF -option git quiet -blob -data 3 -hi +test_expect_success 'R: quiet option results in no stats being output' ' + cat >input <<-EOF && + option git quiet + blob + data 3 + hi -EOF + EOF -test_expect_success 'R: quiet option results in no stats being output' ' - cat input | git fast-import 2> output && - test_cmp empty output + cat input | git fast-import 2> output && + test_must_be_empty output ' test_expect_success 'R: feature done means terminating "done" is mandatory' ' @@ -2591,16 +2618,16 @@ test_expect_success 'R: terminating "done" within commit' ' test_cmp expect actual ' -cat >input <<EOF -option git non-existing-option -EOF - test_expect_success 'R: die on unknown option' ' - test_must_fail git fast-import <input + cat >input <<-EOF && + option git non-existing-option + EOF + + test_must_fail git fast-import <input ' test_expect_success 'R: unknown commandline options are rejected' '\ - test_must_fail git fast-import --non-existing-option < /dev/null + test_must_fail git fast-import --non-existing-option < /dev/null ' test_expect_success 'R: die on invalid option argument' ' @@ -2611,41 +2638,41 @@ test_expect_success 'R: die on invalid option argument' ' test_must_fail git fast-import --depth="5 elephants" </dev/null ' -cat >input <<EOF -option non-existing-vcs non-existing-option -EOF - test_expect_success 'R: ignore non-git options' ' - git fast-import <input + cat >input <<-EOF && + option non-existing-vcs non-existing-option + EOF + + git fast-import <input ' ## ## R: very large blobs ## -blobsize=$((2*1024*1024 + 53)) -test-genrandom bar $blobsize >expect -cat >input <<INPUT_END -commit refs/heads/big-file -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -R - big file -COMMIT - -M 644 inline big1 -data $blobsize -INPUT_END -cat expect >>input -cat >>input <<INPUT_END -M 644 inline big2 -data $blobsize -INPUT_END -cat expect >>input -echo >>input - -test_expect_success \ - 'R: blob bigger than threshold' \ - 'test_create_repo R && - git --git-dir=R/.git fast-import --big-file-threshold=1 <input' +test_expect_success 'R: blob bigger than threshold' ' + blobsize=$((2*1024*1024 + 53)) && + test-genrandom bar $blobsize >expect && + cat >input <<-INPUT_END && + commit refs/heads/big-file + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + R - big file + COMMIT + + M 644 inline big1 + data $blobsize + INPUT_END + cat expect >>input && + cat >>input <<-INPUT_END && + M 644 inline big2 + data $blobsize + INPUT_END + cat expect >>input && + echo >>input && + + test_create_repo R && + git --git-dir=R/.git fast-import --big-file-threshold=1 <input +' test_expect_success 'R: verify created pack' ' ( @@ -2654,17 +2681,18 @@ test_expect_success 'R: verify created pack' ' ) ' -test_expect_success \ - 'R: verify written objects' \ - 'git --git-dir=R/.git cat-file blob big-file:big1 >actual && - test_cmp_bin expect actual && - a=$(git --git-dir=R/.git rev-parse big-file:big1) && - b=$(git --git-dir=R/.git rev-parse big-file:big2) && - test $a = $b' -test_expect_success \ - 'R: blob appears only once' \ - 'n=$(grep $a verify | wc -l) && - test 1 = $n' +test_expect_success 'R: verify written objects' ' + git --git-dir=R/.git cat-file blob big-file:big1 >actual && + test_cmp_bin expect actual && + a=$(git --git-dir=R/.git rev-parse big-file:big1) && + b=$(git --git-dir=R/.git rev-parse big-file:big2) && + test $a = $b +' + +test_expect_success 'R: blob appears only once' ' + n=$(grep $a verify | wc -l) && + test 1 = $n +' ### ### series S @@ -2697,46 +2725,46 @@ test_expect_success \ # # Invalid dataref .. # -test_tick - -cat >input <<INPUT_END -commit refs/heads/S -mark :301 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -commit 1 -COMMIT -M 100644 inline hello.c -data <<BLOB -blob 1 -BLOB - -commit refs/heads/S -mark :302 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -commit 2 -COMMIT -from :301 -M 100644 inline hello.c -data <<BLOB -blob 2 -BLOB - -blob -mark :403 -data <<BLOB -blob 3 -BLOB - -blob -mark :202 -data <<BLOB -note 2 -BLOB -INPUT_END - test_expect_success 'S: initialize for S tests' ' + test_tick && + + cat >input <<-INPUT_END && + commit refs/heads/S + mark :301 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit 1 + COMMIT + M 100644 inline hello.c + data <<BLOB + blob 1 + BLOB + + commit refs/heads/S + mark :302 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit 2 + COMMIT + from :301 + M 100644 inline hello.c + data <<BLOB + blob 2 + BLOB + + blob + mark :403 + data <<BLOB + blob 3 + BLOB + + blob + mark :202 + data <<BLOB + note 2 + BLOB + INPUT_END + git fast-import --export-marks=marks <input ' @@ -2988,103 +3016,103 @@ test_expect_success 'T: empty reset doesnt delete branch' ' ### series U (filedelete) ### -cat >input <<INPUT_END -commit refs/heads/U -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -test setup -COMMIT -M 100644 inline hello.c -data <<BLOB -blob 1 -BLOB -M 100644 inline good/night.txt -data <<BLOB -sleep well -BLOB -M 100644 inline good/bye.txt -data <<BLOB -au revoir -BLOB - -INPUT_END - test_expect_success 'U: initialize for U tests' ' + cat >input <<-INPUT_END && + commit refs/heads/U + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + test setup + COMMIT + M 100644 inline hello.c + data <<BLOB + blob 1 + BLOB + M 100644 inline good/night.txt + data <<BLOB + sleep well + BLOB + M 100644 inline good/bye.txt + data <<BLOB + au revoir + BLOB + + INPUT_END + git fast-import <input ' -cat >input <<INPUT_END -commit refs/heads/U -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -delete good/night.txt -COMMIT -from refs/heads/U^0 -D good/night.txt +test_expect_success 'U: filedelete file succeeds' ' + cat >input <<-INPUT_END && + commit refs/heads/U + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + delete good/night.txt + COMMIT + from refs/heads/U^0 + D good/night.txt -INPUT_END + INPUT_END -test_expect_success 'U: filedelete file succeeds' ' git fast-import <input ' -cat >expect <<EOF -:100644 000000 2907ebb4bf85d91bf0716bb3bd8a68ef48d6da76 0000000000000000000000000000000000000000 D good/night.txt -EOF +test_expect_success 'U: validate file delete result' ' + cat >expect <<-EOF && + :100644 000000 2907ebb4bf85d91bf0716bb3bd8a68ef48d6da76 0000000000000000000000000000000000000000 D good/night.txt + EOF -git diff-tree -M -r U^1 U >actual + git diff-tree -M -r U^1 U >actual && -test_expect_success 'U: validate file delete result' ' compare_diff_raw expect actual ' -cat >input <<INPUT_END -commit refs/heads/U -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -delete good dir -COMMIT -from refs/heads/U^0 -D good +test_expect_success 'U: filedelete directory succeeds' ' + cat >input <<-INPUT_END && + commit refs/heads/U + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + delete good dir + COMMIT + from refs/heads/U^0 + D good -INPUT_END + INPUT_END -test_expect_success 'U: filedelete directory succeeds' ' git fast-import <input ' -cat >expect <<EOF -:100644 000000 69cb75792f55123d8389c156b0b41c2ff00ed507 0000000000000000000000000000000000000000 D good/bye.txt -EOF +test_expect_success 'U: validate directory delete result' ' + cat >expect <<-EOF && + :100644 000000 69cb75792f55123d8389c156b0b41c2ff00ed507 0000000000000000000000000000000000000000 D good/bye.txt + EOF -git diff-tree -M -r U^1 U >actual + git diff-tree -M -r U^1 U >actual && -test_expect_success 'U: validate directory delete result' ' compare_diff_raw expect actual ' -cat >input <<INPUT_END -commit refs/heads/U -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -must succeed -COMMIT -from refs/heads/U^0 -D "" +test_expect_success 'U: filedelete root succeeds' ' + cat >input <<-INPUT_END && + commit refs/heads/U + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + must succeed + COMMIT + from refs/heads/U^0 + D "" -INPUT_END + INPUT_END -test_expect_success 'U: filedelete root succeeds' ' - git fast-import <input + git fast-import <input ' -cat >expect <<EOF -:100644 000000 c18147dc648481eeb65dc5e66628429a64843327 0000000000000000000000000000000000000000 D hello.c -EOF +test_expect_success 'U: validate root delete result' ' + cat >expect <<-EOF && + :100644 000000 c18147dc648481eeb65dc5e66628429a64843327 0000000000000000000000000000000000000000 D hello.c + EOF -git diff-tree -M -r U^1 U >actual + git diff-tree -M -r U^1 U >actual && -test_expect_success 'U: validate root delete result' ' compare_diff_raw expect actual ' diff --git a/t/t9402-git-cvsserver-refs.sh b/t/t9402-git-cvsserver-refs.sh index 1e266effff..d00df08731 100755 --- a/t/t9402-git-cvsserver-refs.sh +++ b/t/t9402-git-cvsserver-refs.sh @@ -496,7 +496,7 @@ test_expect_success 'check [cvswork3] diff' ' ' test_expect_success 'merge early [cvswork3] b3 with b1' ' - ( cd gitwork3 && git merge "message" HEAD b1 ) && + ( cd gitwork3 && git merge -m "message" b1 ) && git fetch gitwork3 b3:b3 && git tag v3merged b3 && git push --tags gitcvs.git b3:b3 diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh index 5b562122a1..0730f18d0f 100755 --- a/t/t9800-git-p4-basic.sh +++ b/t/t9800-git-p4-basic.sh @@ -131,6 +131,44 @@ test_expect_success 'clone two dirs, @all, conflicting files' ' ) ' +revision_ranges="2000/01/01,#head \ + 1,2080/01/01 \ + 2000/01/01,2080/01/01 \ + 2000/01/01,1000 \ + 1,1000" + +test_expect_success 'clone using non-numeric revision ranges' ' + test_when_finished cleanup_git && + for r in $revision_ranges + do + rm -fr "$git" && + test ! -d "$git" && + git p4 clone --dest="$git" //depot@$r && + ( + cd "$git" && + git ls-files >lines && + test_line_count = 6 lines + ) + done +' + +test_expect_success 'clone with date range, excluding some changes' ' + test_when_finished cleanup_git && + before=$(date +%Y/%m/%d:%H:%M:%S) && + sleep 2 && + ( + cd "$cli" && + :>date_range_test && + p4 add date_range_test && + p4 submit -d "Adding file" + ) && + git p4 clone --dest="$git" //depot@1,$before && + ( + cd "$git" && + test_path_is_missing date_range_test + ) +' + test_expect_success 'exit when p4 fails to produce marshaled output' ' mkdir badp4dir && test_when_finished "rm badp4dir/p4 && rmdir badp4dir" && @@ -203,6 +241,22 @@ test_expect_success 'unresolvable host in P4PORT should display error' ' ) ' +test_expect_success 'submit from detached head' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git checkout p4/master && + >detached_head_test && + git add detached_head_test && + git commit -m "add detached_head" && + git config git-p4.skipSubmitEdit true && + git p4 submit && + git p4 rebase && + git log p4/master | grep detached_head + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh index 2bf142d09c..0aafd03334 100755 --- a/t/t9801-git-p4-branch.sh +++ b/t/t9801-git-p4-branch.sh @@ -504,6 +504,112 @@ test_expect_success 'use-client-spec detect-branches skips files in branches' ' ) ' +test_expect_success 'restart p4d' ' + kill_p4d && + start_p4d +' + +# +# 1: //depot/branch1/base/file1 +# //depot/branch1/base/file2 +# //depot/branch1/base/dir/sub_file1 +# 2: integrate //depot/branch1/base/... -> //depot/branch2/base/... +# 3: //depot/branch1/base/file3 +# 4: //depot/branch1/base/file2 (edit) +# 5: integrate //depot/branch1/base/... -> //depot/branch3/base/... +# +# Note: the client view removes the "base" folder from the workspace +# and moves sub_file1 one level up. +test_expect_success 'add simple p4 branches with common base folder on each branch' ' + ( + cd "$cli" && + client_view "//depot/branch1/base/... //client/branch1/..." \ + "//depot/branch1/base/dir/sub_file1 //client/branch1/sub_file1" \ + "//depot/branch2/base/... //client/branch2/..." \ + "//depot/branch3/base/... //client/branch3/..." && + mkdir -p branch1 && + cd branch1 && + echo file1 >file1 && + echo file2 >file2 && + mkdir dir && + echo sub_file1 >sub_file1 && + p4 add file1 file2 sub_file1 && + p4 submit -d "Create branch1" && + p4 integrate //depot/branch1/base/... //depot/branch2/base/... && + p4 submit -d "Integrate branch2 from branch1" && + echo file3 >file3 && + p4 add file3 && + p4 submit -d "add file3 in branch1" && + p4 open file2 && + echo update >>file2 && + p4 submit -d "update file2 in branch1" && + p4 integrate //depot/branch1/base/... //depot/branch3/base/... && + p4 submit -d "Integrate branch3 from branch1" + ) +' + +# Configure branches through git-config and clone them. +# All files are tested to make sure branches were cloned correctly. +# Finally, make an update to branch1 on P4 side to check if it is imported +# correctly by git p4. +# git p4 is expected to use the client view to also not include the common +# "base" folder in the imported directory structure. +test_expect_success 'git p4 clone simple branches with base folder on server side' ' + test_create_repo "$git" && + ( + cd "$git" && + git config git-p4.branchList branch1:branch2 && + git config --add git-p4.branchList branch1:branch3 && + git p4 clone --dest=. --use-client-spec --detect-branches //depot@all && + git log --all --graph --decorate --stat && + git reset --hard p4/depot/branch1 && + test -f file1 && + test -f file2 && + test -f file3 && + test -f sub_file1 && + grep update file2 && + git reset --hard p4/depot/branch2 && + test -f file1 && + test -f file2 && + test ! -f file3 && + test -f sub_file1 && + ! grep update file2 && + git reset --hard p4/depot/branch3 && + test -f file1 && + test -f file2 && + test -f file3 && + test -f sub_file1 && + grep update file2 && + cd "$cli" && + cd branch1 && + p4 edit file2 && + echo file2_ >>file2 && + p4 submit -d "update file2 in branch1" && + cd "$git" && + git reset --hard p4/depot/branch1 && + git p4 rebase && + grep file2_ file2 + ) +' + +# Now update a file in one of the branches in git and submit to P4 +test_expect_success 'Update a file in git side and submit to P4 using client view' ' + test_when_finished cleanup_git && + ( + cd "$git" && + git reset --hard p4/depot/branch1 && + echo "client spec" >> file1 && + git add -u . && + git commit -m "update file1 in branch1" && + git config git-p4.skipSubmitEdit true && + git p4 submit --verbose && + cd "$cli" && + p4 sync ... && + cd branch1 && + grep "client spec" file1 + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9803-git-p4-shell-metachars.sh b/t/t9803-git-p4-shell-metachars.sh index fbacff34fe..d950c7d665 100755 --- a/t/t9803-git-p4-shell-metachars.sh +++ b/t/t9803-git-p4-shell-metachars.sh @@ -28,7 +28,7 @@ test_expect_success 'shell metachars in filenames' ' echo f2 >"file with spaces" && git add "file with spaces" && git commit -m "add files" && - P4EDITOR=touch git p4 submit + P4EDITOR="test-chmtime +5" git p4 submit ) && ( cd "$cli" && @@ -47,7 +47,7 @@ test_expect_success 'deleting with shell metachars' ' git rm foo\$bar && git rm file\ with\ spaces && git commit -m "remove files" && - P4EDITOR=touch git p4 submit + P4EDITOR="test-chmtime +5" git p4 submit ) && ( cd "$cli" && diff --git a/t/t9805-git-p4-skip-submit-edit.sh b/t/t9805-git-p4-skip-submit-edit.sh index 89311886db..5fbf904dc8 100755 --- a/t/t9805-git-p4-skip-submit-edit.sh +++ b/t/t9805-git-p4-skip-submit-edit.sh @@ -90,7 +90,7 @@ test_expect_success 'no config, edited' ' cd "$git" && echo line >>file1 && git commit -a -m "change 5" && - P4EDITOR="$TRASH_DIRECTORY/ed.sh" && + P4EDITOR="\"$TRASH_DIRECTORY/ed.sh\"" && export P4EDITOR && git p4 submit && p4 changes //depot/... >wc && diff --git a/t/t9807-git-p4-submit.sh b/t/t9807-git-p4-submit.sh index 1f74a88385..593152817d 100755 --- a/t/t9807-git-p4-submit.sh +++ b/t/t9807-git-p4-submit.sh @@ -389,7 +389,7 @@ test_expect_success 'description with Jobs section and bogus following text' ' ( cd "$cli" && p4 revert desc6 && - rm desc6 + rm -f desc6 ) ' diff --git a/t/t9811-git-p4-label-import.sh b/t/t9811-git-p4-label-import.sh index 095238fffe..decb66ba30 100755 --- a/t/t9811-git-p4-label-import.sh +++ b/t/t9811-git-p4-label-import.sh @@ -214,6 +214,51 @@ test_expect_success 'use git config to enable import/export of tags' ' ) ' +p4_head_revision() { + p4 changes -m 1 "$@" | awk '{print $2}' +} + +# Importing a label that references a P4 commit that +# has not been seen. The presence of a label on a commit +# we haven't seen should not cause git-p4 to fail. It should +# merely skip that label, and still import other labels. +test_expect_success 'importing labels with missing revisions' ' + test_when_finished cleanup_git && + ( + rm -fr "$cli" "$git" && + mkdir "$cli" && + P4CLIENT=missing-revision && + client_view "//depot/missing-revision/... //missing-revision/..." && + cd "$cli" && + >f1 && p4 add f1 && p4 submit -d "start" && + + p4 tag -l TAG_S0 ... && + + >f2 && p4 add f2 && p4 submit -d "second" && + + startrev=$(p4_head_revision //depot/missing-revision/...) && + + >f3 && p4 add f3 && p4 submit -d "third" && + + p4 edit f2 && date >f2 && p4 submit -d "change" f2 && + + endrev=$(p4_head_revision //depot/missing-revision/...) && + + p4 tag -l TAG_S1 ... && + + # we should skip TAG_S0 since it is before our startpoint, + # but pick up TAG_S1. + + git p4 clone --dest="$git" --import-labels -v \ + //depot/missing-revision/...@$startrev,$endrev && + ( + cd "$git" && + git rev-parse TAG_S1 && + ! git rev-parse TAG_S0 + ) + ) +' + 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 166b840bfa..0fe2312807 100755 --- a/t/t9813-git-p4-preserve-users.sh +++ b/t/t9813-git-p4-preserve-users.sh @@ -53,7 +53,9 @@ test_expect_success 'preserve users' ' 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 && + P4EDITOR="test-chmtime +5" P4USER=alice P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + git p4 commit --preserve-user && p4_check_commit_author file1 alice && p4_check_commit_author file2 bob ) @@ -69,7 +71,7 @@ test_expect_success 'refuse to preserve users without perms' ' git config git-p4.skipSubmitEditCheck true && echo "username-noperms: 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 && + P4EDITOR="test-chmtime +5" P4USER=bob P4PASSWD=secret && export P4EDITOR P4USER P4PASSWD && test_must_fail git p4 commit --preserve-user && ! git diff --exit-code HEAD..p4/master @@ -87,7 +89,7 @@ test_expect_success 'preserve user where author is unknown to p4' ' 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@example.com>" -m "preserve: a change by charlie" file1 && - P4EDITOR=touch P4USER=alice P4PASSWD=secret && + P4EDITOR="test-chmtime +5" P4USER=alice P4PASSWD=secret && export P4EDITOR P4USER P4PASSWD && test_must_fail git p4 commit --preserve-user && ! git diff --exit-code HEAD..p4/master && diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh index 99bb71b89c..c89992cf95 100755 --- a/t/t9814-git-p4-rename.sh +++ b/t/t9814-git-p4-rename.sh @@ -226,14 +226,9 @@ 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 +test_lazy_prereq P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW ' + p4 configure show run.move.allow >out && + egrep ^run.move.allow: out ' # If move can be disabled, turn it off and test p4 move handling diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh index 4cff6a760f..37b42d03a2 100755 --- a/t/t9815-git-p4-submit-fail.sh +++ b/t/t9815-git-p4-submit-fail.sh @@ -417,11 +417,8 @@ test_expect_success 'cleanup chmod after submit cancel' ' ! p4 fstat -T action text && test_path_is_file text+x && ! p4 fstat -T action text+x && - if test_have_prereq !CYGWIN - then - stat --format=%A text | egrep ^-r-- && - stat --format=%A text+x | egrep ^-r-x - fi + ls -l text | egrep ^-r-- && + ls -l text+x | egrep ^-r-x ) ' diff --git a/t/t9816-git-p4-locked.sh b/t/t9816-git-p4-locked.sh index e71e543343..d048bd33fa 100755 --- a/t/t9816-git-p4-locked.sh +++ b/t/t9816-git-p4-locked.sh @@ -35,13 +35,13 @@ test_expect_success 'edit with lock not taken' ' ) ' -test_expect_failure 'add with lock not taken' ' +test_expect_success '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 add add-lock-not-taken && git commit -m "add add-lock-not-taken" && git config git-p4.skipSubmitEdit true && git p4 submit --verbose @@ -107,7 +107,7 @@ test_expect_failure 'chmod with lock taken' ' ) ' -test_expect_failure 'copy with lock taken' ' +test_expect_success 'copy with lock taken' ' lock_in_another_client && test_when_finished cleanup_git && test_when_finished "cd \"$cli\" && p4 revert file2 && rm -f file2" && @@ -130,8 +130,8 @@ test_expect_failure 'move with lock taken' ' git p4 clone --dest="$git" //depot && ( cd "$git" && - git mv file1 file2 && - git commit -m "mv file1 to file2" && + git mv file1 file3 && + git commit -m "mv file1 to file3" && git config git-p4.skipSubmitEdit true && git config git-p4.detectRenames true && git p4 submit --verbose diff --git a/t/t9818-git-p4-block.sh b/t/t9818-git-p4-block.sh new file mode 100755 index 0000000000..8840a183ac --- /dev/null +++ b/t/t9818-git-p4-block.sh @@ -0,0 +1,145 @@ +#!/bin/sh + +test_description='git p4 fetching changes in multiple blocks' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +create_restricted_group() { + p4 group -i <<-EOF + Group: restricted + MaxResults: 7 + MaxScanRows: 40 + Users: author + EOF +} + +test_expect_success 'Create group with limited maxrows' ' + create_restricted_group +' + +test_expect_success 'Create a repo with many changes' ' + ( + client_view "//depot/included/... //client/included/..." \ + "//depot/excluded/... //client/excluded/..." && + mkdir -p "$cli/included" "$cli/excluded" && + cd "$cli/included" && + >file.txt && + p4 add file.txt && + p4 submit -d "Add file.txt" && + for i in $(test_seq 0 5) + do + >outer$i.txt && + p4 add outer$i.txt && + p4 submit -d "Adding outer$i.txt" && + for j in $(test_seq 0 5) + do + p4 edit file.txt && + echo $i$j >file.txt && + p4 submit -d "Commit $i$j" || exit + done || exit + done + ) +' + +test_expect_success 'Default user cannot fetch changes' ' + ! p4 changes -m 1 //depot/... +' + +test_expect_success 'Clone the repo' ' + git p4 clone --dest="$git" --changes-block-size=7 --verbose //depot/included@all +' + +test_expect_success 'All files are present' ' + echo file.txt >expected && + test_write_lines outer0.txt outer1.txt outer2.txt outer3.txt outer4.txt >>expected && + test_write_lines outer5.txt >>expected && + ls "$git" >current && + test_cmp expected current +' + +test_expect_success 'file.txt is correct' ' + echo 55 >expected && + test_cmp expected "$git/file.txt" +' + +test_expect_success 'Correct number of commits' ' + (cd "$git" && git log --oneline) >log && + wc -l log && + test_line_count = 43 log +' + +test_expect_success 'Previous version of file.txt is correct' ' + (cd "$git" && git checkout HEAD^^) && + echo 53 >expected && + test_cmp expected "$git/file.txt" +' + +# Test git-p4 sync, with some files outside the client specification. + +p4_add_file() { + (cd "$cli" && + >$1 && + p4 add $1 && + p4 submit -d "Added file $1" $1 + ) +} + +test_expect_success 'Add some more files' ' + for i in $(test_seq 0 10) + do + p4_add_file "included/x$i" && + p4_add_file "excluded/x$i" + done && + for i in $(test_seq 0 10) + do + p4_add_file "excluded/y$i" + done +' + +# This should pick up the 10 new files in "included", but not be confused +# by the additional files in "excluded" +test_expect_success 'Syncing files' ' + ( + cd "$git" && + git p4 sync --changes-block-size=7 && + git checkout p4/master && + ls -l x* > log && + test_line_count = 11 log + ) +' + +# Handling of multiple depot paths: +# git p4 clone //depot/pathA //depot/pathB +# +test_expect_success 'Create a repo with multiple depot paths' ' + client_view "//depot/pathA/... //client/pathA/..." \ + "//depot/pathB/... //client/pathB/..." && + mkdir -p "$cli/pathA" "$cli/pathB" && + for p in pathA pathB + do + for i in $(test_seq 1 10) + do + p4_add_file "$p/file$p$i" + done + done +' + +test_expect_success 'Clone repo with multiple depot paths' ' + ( + cd "$git" && + git p4 clone --changes-block-size=4 //depot/pathA@all //depot/pathB@all \ + --destination=dest && + ls -1 dest >log && + test_line_count = 20 log + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9819-git-p4-case-folding.sh b/t/t9819-git-p4-case-folding.sh new file mode 100755 index 0000000000..d808c008c1 --- /dev/null +++ b/t/t9819-git-p4-case-folding.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +test_description='interaction with P4 case-folding' + +. ./lib-git-p4.sh + +if test_have_prereq CASE_INSENSITIVE_FS +then + skip_all='skipping P4 case-folding tests; case insensitive file system detected' + test_done +fi + +test_expect_success 'start p4d with case folding enabled' ' + start_p4d -C1 +' + +test_expect_success 'Create a repo, name is lowercase' ' + ( + client_view "//depot/... //client/..." && + cd "$cli" && + mkdir -p lc UC && + >lc/file.txt && >UC/file.txt && + p4 add lc/file.txt UC/file.txt && + p4 submit -d "Add initial lc and UC repos" + ) +' + +test_expect_success 'Check p4 is in case-folding mode' ' + ( + cd "$cli" && + >lc/FILE.TXT && + p4 add lc/FILE.TXT && + test_must_fail p4 submit -d "Cannot add file differing only in case" lc/FILE.TXT + ) +' + +# Check we created the repo properly +test_expect_success 'Clone lc repo using lc name' ' + git p4 clone //depot/lc/... && + test_path_is_file lc/file.txt && + git p4 clone //depot/UC/... && + test_path_is_file UC/file.txt +' + +# The clone should fail, since there is no repo called LC, but because +# we have case-insensitive p4d enabled, it appears to go ahead and work, +# but leaves an empty git repo in place. +test_expect_failure 'Clone lc repo using uc name' ' + test_must_fail git p4 clone //depot/LC/... +' + +test_expect_failure 'Clone UC repo with lc name' ' + test_must_fail git p4 clone //depot/uc/... +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9820-git-p4-editor-handling.sh b/t/t9820-git-p4-editor-handling.sh new file mode 100755 index 0000000000..6dc6df032e --- /dev/null +++ b/t/t9820-git-p4-editor-handling.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +test_description='git p4 handling of EDITOR' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'init depot' ' + ( + cd "$cli" && + echo file1 >file1 && + p4 add file1 && + p4 submit -d "file1" + ) +' + +# Check that the P4EDITOR argument can be given command-line +# options, which git-p4 will then pass through to the shell. +test_expect_success 'EDITOR with options' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + echo change >file1 && + git commit -m "change" file1 && + P4EDITOR=": >\"$git/touched\" && test-chmtime +5" git p4 submit && + test_path_is_file "$git/touched" + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9821-git-p4-path-variations.sh b/t/t9821-git-p4-path-variations.sh new file mode 100755 index 0000000000..81e46acfa8 --- /dev/null +++ b/t/t9821-git-p4-path-variations.sh @@ -0,0 +1,200 @@ +#!/bin/sh + +test_description='Clone repositories with path case variations' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d with case folding enabled' ' + start_p4d -C1 +' + +test_expect_success 'Create a repo with path case variations' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + + mkdir -p Path/to && + >Path/to/File2.txt && + p4 add Path/to/File2.txt && + p4 submit -d "Add file2" && + rm -rf Path && + + mkdir -p path/TO && + >path/TO/file1.txt && + p4 add path/TO/file1.txt && + p4 submit -d "Add file1" && + rm -rf path && + + mkdir -p path/to && + >path/to/file3.txt && + p4 add path/to/file3.txt && + p4 submit -d "Add file3" && + rm -rf path && + + mkdir -p x-outside-spec && + >x-outside-spec/file4.txt && + p4 add x-outside-spec/file4.txt && + p4 submit -d "Add file4" && + rm -rf x-outside-spec + ) +' + +test_expect_success 'Clone root' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase false && + git p4 clone --use-client-spec --destination="$git" //depot && + # This method is used instead of "test -f" to ensure the case is + # checked even if the test is executed on case-insensitive file systems. + # All files are there as expected although the path cases look random. + cat >expect <<-\EOF && + Path/to/File2.txt + path/TO/file1.txt + path/to/file3.txt + x-outside-spec/file4.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone root (ignorecase)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase true && + git p4 clone --use-client-spec --destination="$git" //depot && + # This method is used instead of "test -f" to ensure the case is + # checked even if the test is executed on case-insensitive file systems. + # All files are there as expected although the path cases look random. + cat >expect <<-\EOF && + path/TO/File2.txt + path/TO/file1.txt + path/TO/file3.txt + x-outside-spec/file4.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone root and ignore one file' ' + client_view \ + "//depot/... //client/..." \ + "-//depot/path/TO/file1.txt //client/path/TO/file1.txt" && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase false && + git p4 clone --use-client-spec --destination="$git" //depot && + # We ignore one file in the client spec and all path cases change from + # "TO" to "to"! + cat >expect <<-\EOF && + Path/to/File2.txt + path/to/file3.txt + x-outside-spec/file4.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone root and ignore one file (ignorecase)' ' + client_view \ + "//depot/... //client/..." \ + "-//depot/path/TO/file1.txt //client/path/TO/file1.txt" && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase true && + git p4 clone --use-client-spec --destination="$git" //depot && + # We ignore one file in the client spec and all path cases change from + # "TO" to "to"! + cat >expect <<-\EOF && + Path/to/File2.txt + Path/to/file3.txt + x-outside-spec/file4.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone path' ' + client_view "//depot/Path/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase false && + git p4 clone --use-client-spec --destination="$git" //depot && + cat >expect <<-\EOF && + to/File2.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone path (ignorecase)' ' + client_view "//depot/Path/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase true && + git p4 clone --use-client-spec --destination="$git" //depot && + cat >expect <<-\EOF && + TO/File2.txt + TO/file1.txt + TO/file3.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +# It looks like P4 determines the path case based on the first file in +# lexicographical order. Please note the lower case "to" directory for all +# files triggered through the addition of "File0.txt". +test_expect_success 'Add a new file and clone path with new file (ignorecase)' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + mkdir -p Path/to && + >Path/to/File0.txt && + p4 add Path/to/File0.txt && + p4 submit -d "Add file" && + rm -rf Path + ) && + + client_view "//depot/Path/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase true && + git p4 clone --use-client-spec --destination="$git" //depot && + cat >expect <<-\EOF && + to/File0.txt + to/File2.txt + to/file1.txt + to/file3.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9822-git-p4-path-encoding.sh b/t/t9822-git-p4-path-encoding.sh new file mode 100755 index 0000000000..7b83e696a9 --- /dev/null +++ b/t/t9822-git-p4-path-encoding.sh @@ -0,0 +1,58 @@ +#!/bin/sh + +test_description='Clone repositories with non ASCII paths' + +. ./lib-git-p4.sh + +UTF8_ESCAPED="a-\303\244_o-\303\266_u-\303\274.txt" +ISO8859_ESCAPED="a-\344_o-\366_u-\374.txt" + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'Create a repo containing iso8859-1 encoded paths' ' + ( + cd "$cli" && + ISO8859="$(printf "$ISO8859_ESCAPED")" && + echo content123 >"$ISO8859" && + p4 add "$ISO8859" && + p4 submit -d "test commit" + ) +' + +test_expect_failure 'Clone auto-detects depot with iso8859-1 paths' ' + git p4 clone --destination="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + UTF8="$(printf "$UTF8_ESCAPED")" && + echo "$UTF8" >expect && + git -c core.quotepath=false ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone repo containing iso8859-1 encoded paths with git-p4.pathEncoding' ' + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.pathEncoding iso8859-1 && + git p4 clone --use-client-spec --destination="$git" //depot && + UTF8="$(printf "$UTF8_ESCAPED")" && + echo "$UTF8" >expect && + git -c core.quotepath=false ls-files >actual && + test_cmp expect actual && + + echo content123 >expect && + cat "$UTF8" >actual && + test_cmp expect actual + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9823-git-p4-mock-lfs.sh b/t/t9823-git-p4-mock-lfs.sh new file mode 100755 index 0000000000..1f2dc369bf --- /dev/null +++ b/t/t9823-git-p4-mock-lfs.sh @@ -0,0 +1,192 @@ +#!/bin/sh + +test_description='Clone repositories and store files in Mock LFS' + +. ./lib-git-p4.sh + +test_file_is_not_in_mock_lfs () { + FILE="$1" && + CONTENT="$2" && + echo "$CONTENT" >expect_content && + test_path_is_file "$FILE" && + test_cmp expect_content "$FILE" +} + +test_file_is_in_mock_lfs () { + FILE="$1" && + CONTENT="$2" && + LOCAL_STORAGE=".git/mock-storage/local/$CONTENT" && + SERVER_STORAGE=".git/mock-storage/remote/$CONTENT" && + echo "pointer-$CONTENT" >expect_pointer && + echo "$CONTENT" >expect_content && + test_path_is_file "$FILE" && + test_path_is_file "$LOCAL_STORAGE" && + test_path_is_file "$SERVER_STORAGE" && + test_cmp expect_pointer "$FILE" && + test_cmp expect_content "$LOCAL_STORAGE" && + test_cmp expect_content "$SERVER_STORAGE" +} + +test_file_is_deleted_in_mock_lfs () { + FILE="$1" && + CONTENT="$2" && + LOCAL_STORAGE=".git/mock-storage/local/$CONTENT" && + SERVER_STORAGE=".git/mock-storage/remote/$CONTENT" && + echo "pointer-$CONTENT" >expect_pointer && + echo "$CONTENT" >expect_content && + test_path_is_missing "$FILE" && + test_path_is_file "$LOCAL_STORAGE" && + test_path_is_file "$SERVER_STORAGE" && + test_cmp expect_content "$LOCAL_STORAGE" && + test_cmp expect_content "$SERVER_STORAGE" +} + +test_file_count_in_dir () { + DIR="$1" && + EXPECTED_COUNT="$2" && + find "$DIR" -type f >actual && + test_line_count = $EXPECTED_COUNT actual +} + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'Create repo with binary files' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + + echo "content 1 txt 23 bytes" >file1.txt && + p4 add file1.txt && + echo "content 2-3 bin 25 bytes" >file2.dat && + p4 add file2.dat && + p4 submit -d "Add text and binary file" && + + mkdir "path with spaces" && + echo "content 2-3 bin 25 bytes" >"path with spaces/file3.bin" && + p4 add "path with spaces/file3.bin" && + p4 submit -d "Add another binary file with same content and spaces in path" && + + echo "content 4 bin 26 bytes XX" >file4.bin && + p4 add file4.bin && + p4 submit -d "Add another binary file with different content" + ) +' + +test_expect_success 'Store files in Mock LFS based on size (>24 bytes)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem MockLFS && + git config git-p4.largeFileThreshold 24 && + git config git-p4.largeFilePush True && + git p4 clone --destination="$git" //depot@all && + + test_file_is_not_in_mock_lfs file1.txt "content 1 txt 23 bytes" && + test_file_is_in_mock_lfs file2.dat "content 2-3 bin 25 bytes" && + test_file_is_in_mock_lfs "path with spaces/file3.bin" "content 2-3 bin 25 bytes" && + test_file_is_in_mock_lfs file4.bin "content 4 bin 26 bytes XX" && + + test_file_count_in_dir ".git/mock-storage/local" 2 && + test_file_count_in_dir ".git/mock-storage/remote" 2 + ) +' + +test_expect_success 'Store files in Mock LFS based on extension (dat)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem MockLFS && + git config git-p4.largeFileExtensions dat && + git config git-p4.largeFilePush True && + git p4 clone --destination="$git" //depot@all && + + test_file_is_not_in_mock_lfs file1.txt "content 1 txt 23 bytes" && + test_file_is_in_mock_lfs file2.dat "content 2-3 bin 25 bytes" && + test_file_is_not_in_mock_lfs "path with spaces/file3.bin" "content 2-3 bin 25 bytes" && + test_file_is_not_in_mock_lfs file4.bin "content 4 bin 26 bytes XX" && + + test_file_count_in_dir ".git/mock-storage/local" 1 && + test_file_count_in_dir ".git/mock-storage/remote" 1 + ) +' + +test_expect_success 'Store files in Mock LFS based on extension (dat) and use git p4 sync and no client spec' ' + test_when_finished cleanup_git && + ( + cd "$git" && + git init && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem MockLFS && + git config git-p4.largeFileExtensions dat && + git config git-p4.largeFilePush True && + git p4 sync //depot && + git checkout p4/master && + + test_file_is_not_in_mock_lfs file1.txt "content 1 txt 23 bytes" && + test_file_is_in_mock_lfs file2.dat "content 2-3 bin 25 bytes" && + test_file_is_not_in_mock_lfs "path with spaces/file3.bin" "content 2-3 bin 25 bytes" && + test_file_is_not_in_mock_lfs file4.bin "content 4 bin 26 bytes XX" && + + test_file_count_in_dir ".git/mock-storage/local" 1 && + test_file_count_in_dir ".git/mock-storage/remote" 1 + ) +' + +test_expect_success 'Remove file from repo and store files in Mock LFS based on size (>24 bytes)' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + p4 delete file4.bin && + p4 submit -d "Remove file" + ) && + + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem MockLFS && + git config git-p4.largeFileThreshold 24 && + git config git-p4.largeFilePush True && + git p4 clone --destination="$git" //depot@all && + + test_file_is_not_in_mock_lfs file1.txt "content 1 txt 23 bytes" && + test_file_is_in_mock_lfs file2.dat "content 2-3 bin 25 bytes" && + test_file_is_in_mock_lfs "path with spaces/file3.bin" "content 2-3 bin 25 bytes" && + test_file_is_deleted_in_mock_lfs file4.bin "content 4 bin 26 bytes XX" && + + test_file_count_in_dir ".git/mock-storage/local" 2 && + test_file_count_in_dir ".git/mock-storage/remote" 2 + ) +' + +test_expect_success 'Run git p4 submit in repo configured with large file system' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem MockLFS && + git config git-p4.largeFileThreshold 24 && + git config git-p4.largeFilePush True && + git p4 clone --destination="$git" //depot@all && + + test_must_fail git p4 submit + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9824-git-p4-git-lfs.sh b/t/t9824-git-p4-git-lfs.sh new file mode 100755 index 0000000000..0b664a377c --- /dev/null +++ b/t/t9824-git-p4-git-lfs.sh @@ -0,0 +1,288 @@ +#!/bin/sh + +test_description='Clone repositories and store files in Git LFS' + +. ./lib-git-p4.sh + +git lfs help >/dev/null 2>&1 || { + skip_all='skipping git p4 Git LFS tests; Git LFS not found' + test_done +} + +test_file_in_lfs () { + FILE="$1" && + SIZE="$2" && + EXPECTED_CONTENT="$3" && + cat "$FILE" | grep "size $SIZE" && + HASH=$(cat "$FILE" | grep "oid sha256:" | sed -e "s/oid sha256://g") && + LFS_FILE=".git/lfs/objects/$(echo "$HASH" | cut -c1-2)/$(echo "$HASH" | cut -c3-4)/$HASH" && + echo $EXPECTED_CONTENT >expect && + test_path_is_file "$FILE" && + test_path_is_file "$LFS_FILE" && + test_cmp expect "$LFS_FILE" +} + +test_file_count_in_dir () { + DIR="$1" && + EXPECTED_COUNT="$2" && + find "$DIR" -type f >actual && + test_line_count = $EXPECTED_COUNT actual +} + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'Create repo with binary files' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + + echo "content 1 txt 23 bytes" >file1.txt && + p4 add file1.txt && + echo "content 2-3 bin 25 bytes" >file2.dat && + p4 add file2.dat && + p4 submit -d "Add text and binary file" && + + mkdir "path with spaces" && + echo "content 2-3 bin 25 bytes" >"path with spaces/file3.bin" && + p4 add "path with spaces/file3.bin" && + p4 submit -d "Add another binary file with same content and spaces in path" && + + echo "content 4 bin 26 bytes XX" >file4.bin && + p4 add file4.bin && + p4 submit -d "Add another binary file with different content" + ) +' + +test_expect_success 'Store files in LFS based on size (>24 bytes)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileThreshold 24 && + git p4 clone --destination="$git" //depot@all && + + test_file_in_lfs file2.dat 25 "content 2-3 bin 25 bytes" && + test_file_in_lfs "path with spaces/file3.bin" 25 "content 2-3 bin 25 bytes" && + test_file_in_lfs file4.bin 26 "content 4 bin 26 bytes XX" && + + test_file_count_in_dir ".git/lfs/objects" 2 && + + cat >expect <<-\EOF && + + # + # Git LFS (see https://git-lfs.github.com/) + # + /file2.dat filter=lfs -text + /file4.bin filter=lfs -text + /path[[:space:]]with[[:space:]]spaces/file3.bin filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'Store files in LFS based on size (>25 bytes)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileThreshold 25 && + git p4 clone --destination="$git" //depot@all && + + test_file_in_lfs file4.bin 26 "content 4 bin 26 bytes XX" && + test_file_count_in_dir ".git/lfs/objects" 1 && + + cat >expect <<-\EOF && + + # + # Git LFS (see https://git-lfs.github.com/) + # + /file4.bin filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'Store files in LFS based on extension (dat)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileExtensions dat && + git p4 clone --destination="$git" //depot@all && + + test_file_in_lfs file2.dat 25 "content 2-3 bin 25 bytes" && + test_file_count_in_dir ".git/lfs/objects" 1 && + + cat >expect <<-\EOF && + + # + # Git LFS (see https://git-lfs.github.com/) + # + *.dat filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'Store files in LFS based on size (>25 bytes) and extension (dat)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileExtensions dat && + git config git-p4.largeFileThreshold 25 && + git p4 clone --destination="$git" //depot@all && + + test_file_in_lfs file2.dat 25 "content 2-3 bin 25 bytes" && + test_file_in_lfs file4.bin 26 "content 4 bin 26 bytes XX" && + test_file_count_in_dir ".git/lfs/objects" 2 && + + cat >expect <<-\EOF && + + # + # Git LFS (see https://git-lfs.github.com/) + # + *.dat filter=lfs -text + /file4.bin filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'Remove file from repo and store files in LFS based on size (>24 bytes)' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + p4 delete file4.bin && + p4 submit -d "Remove file" + ) && + + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileThreshold 24 && + git p4 clone --destination="$git" //depot@all && + + test_file_in_lfs file2.dat 25 "content 2-3 bin 25 bytes" && + test_file_in_lfs "path with spaces/file3.bin" 25 "content 2-3 bin 25 bytes" && + test_path_is_missing file4.bin && + test_file_count_in_dir ".git/lfs/objects" 2 && + + cat >expect <<-\EOF && + + # + # Git LFS (see https://git-lfs.github.com/) + # + /file2.dat filter=lfs -text + /path[[:space:]]with[[:space:]]spaces/file3.bin filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'Add .gitattributes and store files in LFS based on size (>24 bytes)' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + echo "*.txt text" >.gitattributes && + p4 add .gitattributes && + p4 submit -d "Add .gitattributes" + ) && + + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileThreshold 24 && + git p4 clone --destination="$git" //depot@all && + + test_file_in_lfs file2.dat 25 "content 2-3 bin 25 bytes" && + test_file_in_lfs "path with spaces/file3.bin" 25 "content 2-3 bin 25 bytes" && + test_path_is_missing file4.bin && + test_file_count_in_dir ".git/lfs/objects" 2 && + + cat >expect <<-\EOF && + *.txt text + + # + # Git LFS (see https://git-lfs.github.com/) + # + /file2.dat filter=lfs -text + /path[[:space:]]with[[:space:]]spaces/file3.bin filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'Add big files to repo and store files in LFS based on compressed size (>28 bytes)' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + echo "content 5 bin 40 bytes XXXXXXXXXXXXXXXX" >file5.bin && + p4 add file5.bin && + p4 submit -d "Add file with small footprint after compression" && + + echo "content 6 bin 39 bytes XXXXXYYYYYZZZZZ" >file6.bin && + p4 add file6.bin && + p4 submit -d "Add file with large footprint after compression" + ) && + + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileCompressedThreshold 28 && + # We only import HEAD here ("@all" is missing!) + git p4 clone --destination="$git" //depot && + + test_file_in_lfs file6.bin 13 "content 6 bin 39 bytes XXXXXYYYYYZZZZZ" + test_file_count_in_dir ".git/lfs/objects" 1 && + + cat >expect <<-\EOF && + *.txt text + + # + # Git LFS (see https://git-lfs.github.com/) + # + /file6.bin filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9825-git-p4-handle-utf16-without-bom.sh b/t/t9825-git-p4-handle-utf16-without-bom.sh new file mode 100755 index 0000000000..1551845dc1 --- /dev/null +++ b/t/t9825-git-p4-handle-utf16-without-bom.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +test_description='git p4 handling of UTF-16 files without BOM' + +. ./lib-git-p4.sh + +UTF16="\227\000\227\000" + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'init depot with UTF-16 encoded file and artificially remove BOM' ' + ( + cd "$cli" && + printf "$UTF16" >file1 && + p4 add -t utf16 file1 && + p4 submit -d "file1" + ) && + + ( + cd db && + p4d -jc && + # P4D automatically adds a BOM. Remove it here to make the file invalid. + sed -e "\$d" depot/file1,v >depot/file1,v.new && + mv depot/file1,v.new depot/file1,v && + printf "@$UTF16@" >>depot/file1,v && + p4d -jrF checkpoint.1 + ) +' + +test_expect_success 'clone depot with invalid UTF-16 file in verbose mode' ' + git p4 clone --dest="$git" --verbose //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + printf "$UTF16" >expect && + test_cmp_bin expect file1 + ) +' + +test_expect_failure 'clone depot with invalid UTF-16 file in non-verbose mode' ' + git p4 clone --dest="$git" //depot +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9826-git-p4-keep-empty-commits.sh b/t/t9826-git-p4-keep-empty-commits.sh new file mode 100755 index 0000000000..be12960d39 --- /dev/null +++ b/t/t9826-git-p4-keep-empty-commits.sh @@ -0,0 +1,134 @@ +#!/bin/sh + +test_description='Clone repositories and keep empty commits' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'Create a repo' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + + mkdir -p subdir && + + >subdir/file1.txt && + p4 add subdir/file1.txt && + p4 submit -d "Add file 1" && + + >file2.txt && + p4 add file2.txt && + p4 submit -d "Add file 2" && + + >subdir/file3.txt && + p4 add subdir/file3.txt && + p4 submit -d "Add file 3" && + + >file4.txt && + p4 add file4.txt && + p4 submit -d "Add file 4" && + + p4 delete subdir/file3.txt && + p4 submit -d "Remove file 3" && + + p4 delete file4.txt && + p4 submit -d "Remove file 4" + ) +' + +test_expect_success 'Clone repo root path with all history' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git p4 clone --use-client-spec --destination="$git" //depot@all && + cat >expect <<-\EOF && +Remove file 4 +[git-p4: depot-paths = "//depot/": change = 6] + +Remove file 3 +[git-p4: depot-paths = "//depot/": change = 5] + +Add file 4 +[git-p4: depot-paths = "//depot/": change = 4] + +Add file 3 +[git-p4: depot-paths = "//depot/": change = 3] + +Add file 2 +[git-p4: depot-paths = "//depot/": change = 2] + +Add file 1 +[git-p4: depot-paths = "//depot/": change = 1] + + EOF + git log --format=%B >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone repo subdir with all history but keep empty commits' ' + client_view "//depot/subdir/... //client/subdir/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.keepEmptyCommits true && + git p4 clone --use-client-spec --destination="$git" //depot@all && + cat >expect <<-\EOF && +Remove file 4 +[git-p4: depot-paths = "//depot/": change = 6] + +Remove file 3 +[git-p4: depot-paths = "//depot/": change = 5] + +Add file 4 +[git-p4: depot-paths = "//depot/": change = 4] + +Add file 3 +[git-p4: depot-paths = "//depot/": change = 3] + +Add file 2 +[git-p4: depot-paths = "//depot/": change = 2] + +Add file 1 +[git-p4: depot-paths = "//depot/": change = 1] + + EOF + git log --format=%B >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone repo subdir with all history' ' + client_view "//depot/subdir/... //client/subdir/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git p4 clone --use-client-spec --destination="$git" --verbose //depot@all && + cat >expect <<-\EOF && +Remove file 3 +[git-p4: depot-paths = "//depot/": change = 5] + +Add file 3 +[git-p4: depot-paths = "//depot/": change = 3] + +Add file 1 +[git-p4: depot-paths = "//depot/": change = 1] + + EOF + git log --format=%B >actual && + test_cmp expect actual + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 4a14a5892e..2ba62fbc17 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -370,6 +370,40 @@ test_expect_success '__git_remotes - list remotes from $GIT_DIR/remotes and from test_cmp expect actual ' +test_expect_success '__git_get_config_variables' ' + cat >expect <<-EOF && + name-1 + name-2 + EOF + test_config interesting.name-1 good && + test_config interesting.name-2 good && + test_config subsection.interesting.name-3 bad && + __git_get_config_variables interesting >actual && + test_cmp expect actual +' + +test_expect_success '__git_pretty_aliases' ' + cat >expect <<-EOF && + author + hash + EOF + test_config pretty.author "%an %ae" && + test_config pretty.hash %H && + __git_pretty_aliases >actual && + test_cmp expect actual +' + +test_expect_success '__git_aliases' ' + cat >expect <<-EOF && + ci + co + EOF + test_config alias.ci commit && + test_config alias.co checkout && + __git_aliases >actual && + test_cmp expect actual +' + test_expect_success 'basic' ' run_completion "git " && # built-in diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh index 49d58e6726..af82049f82 100755 --- a/t/t9903-bash-prompt.sh +++ b/t/t9903-bash-prompt.sh @@ -273,11 +273,36 @@ test_expect_success 'prompt - dirty status indicator - dirty index and worktree' test_cmp expected "$actual" ' -test_expect_success 'prompt - dirty status indicator - before root commit' ' - printf " (master #)" >expected && +test_expect_success 'prompt - dirty status indicator - orphan branch - clean' ' + printf " (orphan #)" >expected && + test_when_finished "git checkout master" && + git checkout --orphan orphan && + git reset --hard && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - orphan branch - dirty index' ' + printf " (orphan +)" >expected && + test_when_finished "git checkout master" && + git checkout --orphan orphan && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - orphan branch - dirty index and worktree' ' + printf " (orphan *+)" >expected && + test_when_finished "git checkout master" && + git checkout --orphan orphan && + >file && ( GIT_PS1_SHOWDIRTYSTATE=y && - cd otherrepo && __git_ps1 >"$actual" ) && test_cmp expected "$actual" @@ -397,6 +422,31 @@ test_expect_success 'prompt - untracked files status indicator - untracked files test_cmp expected "$actual" ' +test_expect_success 'prompt - untracked files status indicator - empty untracked dir' ' + printf " (master)" >expected && + mkdir otherrepo/untracked-dir && + test_when_finished "rm -rf otherrepo/untracked-dir" && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + cd otherrepo && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - non-empty untracked dir' ' + printf " (master %%)" >expected && + mkdir otherrepo/untracked-dir && + test_when_finished "rm -rf otherrepo/untracked-dir" && + >otherrepo/untracked-dir/untracked-file && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + cd otherrepo && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + test_expect_success 'prompt - untracked files status indicator - untracked files outside cwd' ' printf " (master %%)" >expected && ( diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 8f8858a5f0..8d99eb303f 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -145,6 +145,14 @@ test_pause () { fi } +# Wrap git in gdb. Adding this to a command can make it easier to +# understand what is going on in a failing test. +# +# Example: "debug git checkout master". +debug () { + GIT_TEST_GDB=1 "$@" +} + # Call test_commit with the arguments "<message> [<file> [<contents> [<tag>]]]" # # This will commit a file with the given contents and the given commit @@ -201,7 +209,14 @@ test_chmod () { # Unset a configuration variable, but don't fail if it doesn't exist. test_unconfig () { - git config --unset-all "$@" + config_dir= + if test "$1" = -C + then + shift + config_dir=$1 + shift + fi + git ${config_dir:+-C "$config_dir"} config --unset-all "$@" config_status=$? case "$config_status" in 5) # ok, nothing to unset @@ -213,8 +228,15 @@ test_unconfig () { # Set git config, automatically unsetting it after the test is over. test_config () { - test_when_finished "test_unconfig '$1'" && - git config "$@" + config_dir= + if test "$1" = -C + then + shift + config_dir=$1 + shift + fi + test_when_finished "test_unconfig ${config_dir:+-C '$config_dir'} '$1'" && + git ${config_dir:+-C "$config_dir"} config "$@" } test_config_global () { @@ -348,11 +370,18 @@ test_declared_prereq () { return 1 } +test_verify_prereq () { + test -z "$test_prereq" || + expr >/dev/null "$test_prereq" : '[A-Z0-9_,!]*$' || + error "bug in the test script: '$test_prereq' does not look like a 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" + test_verify_prereq export test_prereq if ! test_skip "$@" then @@ -372,6 +401,7 @@ test_expect_success () { test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test-expect-success" + test_verify_prereq export test_prereq if ! test_skip "$@" then @@ -400,6 +430,7 @@ test_external () { error >&5 "bug in the test script: not 3 or 4 parameters to test_external" descr="$1" shift + test_verify_prereq export test_prereq if ! test_skip "$descr" "$@" then @@ -538,6 +569,21 @@ test_line_count () { fi } +# Returns success if a comma separated string of keywords ($1) contains a +# given keyword ($2). +# Examples: +# `list_contains "foo,bar" bar` returns 0 +# `list_contains "foo" bar` returns 1 + +list_contains () { + case ",$1," in + *,$2,*) + return 0 + ;; + esac + return 1 +} + # This is not among top-level (test_expect_success | test_expect_failure) # but is a prefix that can be used in the test script, like: # @@ -551,18 +597,34 @@ test_line_count () { # the failure could be due to a segv. We want a controlled failure. test_must_fail () { + case "$1" in + ok=*) + _test_ok=${1#ok=} + shift + ;; + *) + _test_ok= + ;; + esac "$@" exit_code=$? - if test $exit_code = 0; then + if test $exit_code -eq 0 && ! list_contains "$_test_ok" success + then echo >&2 "test_must_fail: command succeeded: $*" return 1 - elif test $exit_code -gt 129 && test $exit_code -le 192; then - echo >&2 "test_must_fail: died by signal: $*" + elif test $exit_code -eq 141 && list_contains "$_test_ok" sigpipe + then + return 0 + elif test $exit_code -gt 129 && test $exit_code -le 192 + then + echo >&2 "test_must_fail: died by signal $(($exit_code - 128)): $*" return 1 - elif test $exit_code = 127; then + elif test $exit_code -eq 127 + then echo >&2 "test_must_fail: command not found: $*" return 1 - elif test $exit_code = 126; then + elif test $exit_code -eq 126 + then echo >&2 "test_must_fail: valgrind error: $*" return 1 fi @@ -581,16 +643,7 @@ test_must_fail () { # because we want to notice if it fails due to segv. test_might_fail () { - "$@" - exit_code=$? - if test $exit_code -gt 129 && test $exit_code -le 192; then - echo >&2 "test_might_fail: died by signal: $*" - return 1 - elif test $exit_code = 127; then - echo >&2 "test_might_fail: command not found: $*" - return 1 - fi - return 0 + test_must_fail ok=success "$@" } # Similar to test_must_fail and test_might_fail, but check that a @@ -713,6 +766,11 @@ test_seq () { # what went wrong. test_when_finished () { + # We cannot detect when we are in a subshell in general, but by + # doing so on Bash is better than nothing (the test will + # silently pass on other shells). + test "${BASH_SUBSHELL-0}" = 0 || + error "bug in test script: test_when_finished does nothing in a subshell" test_cleanup="{ $* } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" } diff --git a/t/test-lib.sh b/t/test-lib.sh index 05efbad71c..51e4a88c33 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -531,6 +531,10 @@ maybe_setup_valgrind () { fi } +want_trace () { + test "$trace" = t && test "$verbose" = t +} + # This is a separate function because some tests use # "return" to end a test_expect_success block early # (and we want to make sure we run any cleanup like @@ -538,7 +542,7 @@ maybe_setup_valgrind () { test_eval_inner_ () { # Do not add anything extra (including LF) after '$*' eval " - test \"$trace\" = t && set -x + want_trace && set -x $*" } @@ -554,7 +558,7 @@ test_eval_ () { { test_eval_inner_ "$@" </dev/null >&3 2>&4 test_eval_ret_=$? - if test "$trace" = t + if want_trace then set +x if test "$test_eval_ret_" != 0 @@ -570,13 +574,18 @@ test_run_ () { test_cleanup=: expecting_failure=$2 - if test "${GIT_TEST_CHAIN_LINT:-0}" != 0; then + if test "${GIT_TEST_CHAIN_LINT:-1}" != 0; then + # turn off tracing for this test-eval, as it simply creates + # confusing noise in the "-x" output + trace_tmp=$trace + trace= # 117 is magic because it is unlikely to match the exit # code of other programs test_eval_ "(exit 117) && $1" if test "$?" != 117; then error "bug in the test script: broken &&-chain: $1" fi + trace=$trace_tmp fi setup_malloc_check @@ -898,9 +907,11 @@ yes () { y="$*" fi - while echo "$y" + i=0 + while test $i -lt 99 do - : + echo "$y" + i=$(($i+1)) done } @@ -1045,20 +1056,28 @@ test_lazy_prereq NOT_ROOT ' test "$uid" != 0 ' -# On a filesystem that lacks SANITY, a file can be deleted even if -# the containing directory doesn't have write permissions, or a file -# can be accessed even if the containing directory doesn't have read -# or execute permissions, causing our tests that validate that Git -# works sensibly in such situations. +# SANITY is about "can you correctly predict what the filesystem would +# do by only looking at the permission bits of the files and +# directories?" A typical example of !SANITY is running the test +# suite as root, where a test may expect "chmod -r file && cat file" +# to fail because file is supposed to be unreadable after a successful +# chmod. In an environment (i.e. combination of what filesystem is +# being used and who is running the tests) that lacks SANITY, you may +# be able to delete or create a file when the containing directory +# doesn't have write permissions, or access a file even if the +# containing directory doesn't have read or execute permissions. + test_lazy_prereq SANITY ' mkdir SANETESTD.1 SANETESTD.2 && chmod +w SANETESTD.1 SANETESTD.2 && >SANETESTD.1/x 2>SANETESTD.2/x && chmod -w SANETESTD.1 && + chmod -r SANETESTD.1/x && chmod -rx SANETESTD.2 || error "bug in test sript: cannot prepare SANETESTD" + ! test -r SANETESTD.1/x && ! rm SANETESTD.1/x && ! test -f SANETESTD.2/x status=$? diff --git a/t/test-terminal.perl b/t/test-terminal.perl index 1fb373f25b..96b6a03e1c 100755 --- a/t/test-terminal.perl +++ b/t/test-terminal.perl @@ -5,15 +5,17 @@ use warnings; use IO::Pty; use File::Copy; -# Run @$argv in the background with stdio redirected to $out and $err. +# Run @$argv in the background with stdio redirected to $in, $out and $err. sub start_child { - my ($argv, $out, $err) = @_; + my ($argv, $in, $out, $err) = @_; my $pid = fork; if (not defined $pid) { die "fork failed: $!" } elsif ($pid == 0) { + open STDIN, "<&", $in; open STDOUT, ">&", $out; open STDERR, ">&", $err; + close $in; close $out; exec(@$argv) or die "cannot exec '$argv->[0]': $!" } @@ -49,6 +51,17 @@ sub xsendfile { copy($in, $out, 4096) or $!{EIO} or die "cannot copy from child: $!"; } +sub copy_stdin { + my ($in) = @_; + my $pid = fork; + if (!$pid) { + xsendfile($in, \*STDIN); + exit 0; + } + close($in); + return $pid; +} + sub copy_stdio { my ($out, $err) = @_; my $pid = fork; @@ -67,14 +80,25 @@ sub copy_stdio { if ($#ARGV < 1) { die "usage: test-terminal program args"; } +my $master_in = new IO::Pty; my $master_out = new IO::Pty; my $master_err = new IO::Pty; +$master_in->set_raw(); $master_out->set_raw(); $master_err->set_raw(); +$master_in->slave->set_raw(); $master_out->slave->set_raw(); $master_err->slave->set_raw(); -my $pid = start_child(\@ARGV, $master_out->slave, $master_err->slave); +my $pid = start_child(\@ARGV, $master_in->slave, $master_out->slave, $master_err->slave); +close $master_in->slave; close $master_out->slave; close $master_err->slave; +my $in_pid = copy_stdin($master_in); copy_stdio($master_out, $master_err); -exit(finish_child($pid)); +my $ret = finish_child($pid); +# If the child process terminates before our copy_stdin() process is able to +# write all of its data to $master_in, the copy_stdin() process could stall. +# Send SIGTERM to it to ensure it terminates. +kill 'TERM', $in_pid; +finish_child($in_pid); +exit($ret); |