diff options
Diffstat (limited to 't')
49 files changed, 3848 insertions, 608 deletions
diff --git a/t/Git-SVN/00compile.t b/t/Git-SVN/00compile.t new file mode 100644 index 0000000000..c92fee453f --- /dev/null +++ b/t/Git-SVN/00compile.t @@ -0,0 +1,14 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More tests => 7; + +require_ok 'Git::SVN'; +require_ok 'Git::SVN::Utils'; +require_ok 'Git::SVN::Ra'; +require_ok 'Git::SVN::Log'; +require_ok 'Git::SVN::Migration'; +require_ok 'Git::IndexInfo'; +require_ok 'Git::SVN::GlobSpec'; diff --git a/t/Git-SVN/Utils/can_compress.t b/t/Git-SVN/Utils/can_compress.t new file mode 100644 index 0000000000..d7b49b8d54 --- /dev/null +++ b/t/Git-SVN/Utils/can_compress.t @@ -0,0 +1,11 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils qw(can_compress); + +# !! is the "convert this to boolean" operator. +is !!can_compress(), !!eval { require Compress::Zlib }; diff --git a/t/Git-SVN/Utils/fatal.t b/t/Git-SVN/Utils/fatal.t new file mode 100644 index 0000000000..49e1438295 --- /dev/null +++ b/t/Git-SVN/Utils/fatal.t @@ -0,0 +1,34 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +BEGIN { + # Override exit at BEGIN time before Git::SVN::Utils is loaded + # so it will see our local exit later. + *CORE::GLOBAL::exit = sub(;$) { + return @_ ? CORE::exit($_[0]) : CORE::exit(); + }; +} + +use Git::SVN::Utils qw(fatal); + +# fatal() +{ + # Capture the exit code and prevent exit. + my $exit_status; + no warnings 'redefine'; + local *CORE::GLOBAL::exit = sub { $exit_status = $_[0] || 0 }; + + # Trap fatal's message to STDERR + my $stderr; + close STDERR; + ok open STDERR, ">", \$stderr; + + fatal "Some", "Stuff", "Happened"; + + is $stderr, "Some Stuff Happened\n"; + is $exit_status, 1; +} diff --git a/t/lib-bash.sh b/t/lib-bash.sh new file mode 100644 index 0000000000..11397f747b --- /dev/null +++ b/t/lib-bash.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# +# Ensures that tests are run under Bash; primarily intended for running tests +# of the completion script. + +if test -n "$BASH" && test -z "$POSIXLY_CORRECT"; then + # we are in full-on bash mode + true +elif type bash >/dev/null 2>&1; then + # execute in full-on bash mode + unset POSIXLY_CORRECT + exec bash "$0" "$@" +else + echo '1..0 #SKIP skipping bash completion tests; bash not available' + exit 0 +fi + +. ./test-lib.sh diff --git a/t/lib-credential.sh b/t/lib-credential.sh index 4a37cd79e5..957ae936e8 100755 --- a/t/lib-credential.sh +++ b/t/lib-credential.sh @@ -4,10 +4,20 @@ # stdout and stderr should be provided on stdin, # separated by "--". check() { + credential_opts= + credential_cmd=$1 + shift + for arg in "$@"; do + credential_opts="$credential_opts -c credential.helper='$arg'" + done read_chunk >stdin && read_chunk >expect-stdout && read_chunk >expect-stderr && - test-credential "$@" <stdin >stdout 2>stderr && + if ! eval "git $credential_opts credential $credential_cmd <stdin >stdout 2>stderr"; then + echo "git credential failed with code $?" && + cat stderr && + false + fi && test_cmp expect-stdout stdout && test_cmp expect-stderr stderr } @@ -41,7 +51,7 @@ reject() { echo protocol=$2 echo host=$3 echo username=$4 - ) | test-credential reject $1 + ) | git -c credential.helper=$1 credential reject } helper_test() { @@ -52,6 +62,8 @@ helper_test() { protocol=https host=example.com -- + protocol=https + host=example.com username=askpass-username password=askpass-password -- @@ -74,6 +86,8 @@ helper_test() { protocol=https host=example.com -- + protocol=https + host=example.com username=store-user password=store-pass -- @@ -85,6 +99,8 @@ helper_test() { protocol=http host=example.com -- + protocol=http + host=example.com username=askpass-username password=askpass-password -- @@ -98,6 +114,8 @@ helper_test() { protocol=https host=other.tld -- + protocol=https + host=other.tld username=askpass-username password=askpass-password -- @@ -112,6 +130,8 @@ helper_test() { host=example.com username=other -- + protocol=https + host=example.com username=other password=askpass-password -- @@ -133,6 +153,9 @@ helper_test() { host=path.tld path=bar.git -- + protocol=http + host=path.tld + path=bar.git username=askpass-username password=askpass-password -- @@ -150,6 +173,8 @@ helper_test() { protocol=https host=example.com -- + protocol=https + host=example.com username=askpass-username password=askpass-password -- @@ -176,6 +201,8 @@ helper_test() { host=example.com username=user1 -- + protocol=https + host=example.com username=user1 password=pass1 EOF @@ -184,6 +211,8 @@ helper_test() { host=example.com username=user2 -- + protocol=https + host=example.com username=user2 password=pass2 EOF @@ -200,6 +229,8 @@ helper_test() { host=example.com username=user1 -- + protocol=https + host=example.com username=user1 password=askpass-password -- @@ -213,6 +244,8 @@ helper_test() { host=example.com username=user2 -- + protocol=https + host=example.com username=user2 password=pass2 EOF @@ -234,6 +267,8 @@ helper_test_timeout() { protocol=https host=timeout.tld -- + protocol=https + host=timeout.tld username=askpass-username password=askpass-password -- diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh index 121e38002b..2d753ab7e1 100644 --- a/t/lib-git-p4.sh +++ b/t/lib-git-p4.sh @@ -2,6 +2,10 @@ # Library code for git p4 tests # +# p4 tests never use the top-level repo; always build/clone into +# a subdirectory called "$git" +TEST_NO_CREATE_REPO=NoThanks + . ./test-lib.sh if ! test_have_prereq PYTHON; then @@ -27,23 +31,48 @@ export P4CLIENT=client export P4EDITOR=: db="$TRASH_DIRECTORY/db" -cli="$TRASH_DIRECTORY/cli" +cli=$(test-path-utils real_path "$TRASH_DIRECTORY/cli") git="$TRASH_DIRECTORY/git" pidfile="$TRASH_DIRECTORY/p4d.pid" start_p4d() { mkdir -p "$db" "$cli" "$git" && + rm -f "$pidfile" && ( p4d -q -r "$db" -p $P4DPORT & echo $! >"$pidfile" ) && - for i in 1 2 3 4 5 ; do - p4 info >/dev/null 2>&1 && break || true && - echo waiting for p4d to start && + + # This gives p4d a long time to start up, as it can be + # quite slow depending on the machine. Set this environment + # variable to something smaller to fail faster in, say, + # an automated test setup. If the p4d process dies, that + # will be caught with the "kill -0" check below. + i=${P4D_START_PATIENCE:-300} + pid=$(cat "$pidfile") + ready= + while test $i -gt 0 + do + # succeed when p4 client commands start to work + if p4 info >/dev/null 2>&1 + then + ready=true + break + fi + # fail if p4d died + kill -0 $pid 2>/dev/null || break + echo waiting for p4d to start sleep 1 - done && - # complain if it never started - p4 info >/dev/null && + i=$(( $i - 1 )) + done + + if test -z "$ready" + then + # p4d failed to start + return 1 + fi + + # build a client ( cd "$cli" && p4 client -i <<-EOF @@ -53,6 +82,7 @@ start_p4d() { View: //depot/... //client/... EOF ) + return 0 } kill_p4d() { @@ -69,5 +99,19 @@ kill_p4d() { } cleanup_git() { - rm -rf "$git" + rm -rf "$git" && + mkdir "$git" +} + +marshal_dump() { + what=$1 && + line=${2:-1} && + cat >"$TRASH_DIRECTORY/marshal-dump.py" <<-EOF && + import marshal + import sys + for i in range($line): + d = marshal.load(sys.stdin) + print d['$what'] + EOF + "$PYTHON_PATH" "$TRASH_DIRECTORY/marshal-dump.py" } diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index 094d490893..d773542680 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -43,6 +43,10 @@ TEST_PATH="$TEST_DIRECTORY"/lib-httpd HTTPD_ROOT_PATH="$PWD"/httpd HTTPD_DOCUMENT_ROOT_PATH=$HTTPD_ROOT_PATH/www +# hack to suppress apache PassEnv warnings +GIT_VALGRIND=$GIT_VALGRIND; export GIT_VALGRIND +GIT_VALGRIND_OPTIONS=$GIT_VALGRIND_OPTIONS; export GIT_VALGRIND_OPTIONS + if ! test -x "$LIB_HTTPD_PATH" then skip_all="skipping test, no web server found at '$LIB_HTTPD_PATH'" diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index de3762e247..36b1596a10 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -42,6 +42,9 @@ ErrorLog error.log </IfModule> </IfVersion> +PassEnv GIT_VALGRIND +PassEnv GIT_VALGRIND_OPTIONS + Alias /dumb/ www/ Alias /auth/ www/auth/ @@ -62,7 +65,7 @@ ScriptAlias /smart/ ${GIT_EXEC_PATH}/git-http-backend/ ScriptAlias /smart_noexport/ ${GIT_EXEC_PATH}/git-http-backend/ ScriptAlias /smart_custom_env/ ${GIT_EXEC_PATH}/git-http-backend/ <Directory ${GIT_EXEC_PATH}> - Options None + Options FollowSymlinks </Directory> <Files ${GIT_EXEC_PATH}/git-http-backend> Options ExecCGI diff --git a/t/t0201-gettext-fallbacks.sh b/t/t0201-gettext-fallbacks.sh index 52b1c27c2c..5d80a985fb 100755 --- a/t/t0201-gettext-fallbacks.sh +++ b/t/t0201-gettext-fallbacks.sh @@ -51,16 +51,16 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate v test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces' ' cmdline="git am" && export cmdline; - printf "When you have resolved this problem run git am --resolved." >expect && - eval_gettext "When you have resolved this problem run \$cmdline --resolved." >actual + printf "When you have resolved this problem, run git am --resolved." >expect && + eval_gettext "When you have resolved this problem, run \$cmdline --resolved." >actual test_i18ncmp expect actual ' test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces and quotes' ' cmdline="git am" && export cmdline; - printf "When you have resolved this problem run \"git am --resolved\"." >expect && - eval_gettext "When you have resolved this problem run \"\$cmdline --resolved\"." >actual + printf "When you have resolved this problem, run \"git am --resolved\"." >expect && + eval_gettext "When you have resolved this problem, run \"\$cmdline --resolved\"." >actual test_i18ncmp expect actual ' diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index 20e28e34e7..538ea5fb1c 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -82,6 +82,9 @@ test_expect_success 'credential_fill passes along metadata' ' host=example.com path=foo.git -- + protocol=ftp + host=example.com + path=foo.git username=one password=two -- @@ -213,6 +216,8 @@ test_expect_success 'match configured credential' ' host=example.com path=repo.git -- + protocol=https + host=example.com username=foo password=bar -- @@ -225,6 +230,8 @@ test_expect_success 'do not match configured credential' ' protocol=https host=bar -- + protocol=https + host=bar username=askpass-username password=askpass-password -- @@ -239,6 +246,8 @@ test_expect_success 'pull username from config' ' protocol=https host=example.com -- + protocol=https + host=example.com username=foo password=askpass-password -- @@ -252,6 +261,8 @@ test_expect_success 'http paths can be part of context' ' host=example.com path=foo.git -- + protocol=https + host=example.com username=foo password=bar -- @@ -265,6 +276,9 @@ test_expect_success 'http paths can be part of context' ' host=example.com path=foo.git -- + protocol=https + host=example.com + path=foo.git username=foo password=bar -- diff --git a/t/t1050-large.sh b/t/t1050-large.sh index 55ed955cef..fd10528009 100755 --- a/t/t1050-large.sh +++ b/t/t1050-large.sh @@ -130,10 +130,27 @@ test_expect_success 'git-show a large file' ' ' +test_expect_success 'index-pack' ' + git clone file://"`pwd`"/.git foo && + GIT_DIR=non-existent git index-pack --strict --verify foo/.git/objects/pack/*.pack +' + test_expect_success 'repack' ' git repack -ad ' +test_expect_success 'pack-objects with large loose object' ' + SHA1=`git hash-object huge` && + test_create_repo loose && + echo $SHA1 | git pack-objects --stdout | + GIT_ALLOC_LIMIT=0 GIT_DIR=loose/.git git unpack-objects && + echo $SHA1 | GIT_DIR=loose/.git git pack-objects pack && + test_create_repo packed && + mv pack-* packed/.git/objects/pack && + GIT_DIR=packed/.git git cat-file blob $SHA1 >actual && + cmp huge actual +' + test_expect_success 'tar achiving' ' git archive --format=tar HEAD >/dev/null ' diff --git a/t/t1100-commit-tree-options.sh b/t/t1100-commit-tree-options.sh index a3b77239f4..f8457f9d14 100755 --- a/t/t1100-commit-tree-options.sh +++ b/t/t1100-commit-tree-options.sh @@ -47,6 +47,7 @@ test_expect_success \ test_expect_success 'flags and then non flags' ' + test_tick && echo comment text | git commit-tree $(cat treeid) >commitid && echo comment text | diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh index 2b962cfda7..79045abb51 100755 --- a/t/t1304-default-acl.sh +++ b/t/t1304-default-acl.sh @@ -14,16 +14,15 @@ umask 077 # We need an arbitrary other user give permission to using ACLs. root # is a good candidate: exists on all unices, and it has permission # anyway, so we don't create a security hole running the testsuite. - -setfacl_out="$(setfacl -m u:root:rwx . 2>&1)" -setfacl_ret=$? - -if test $setfacl_ret != 0 -then - say "Unable to use setfacl (output: '$setfacl_out'; return code: '$setfacl_ret')" -else - test_set_prereq SETFACL -fi +test_expect_success 'checking for a working acl setup' ' + if setfacl -m d:m:rwx -m u:root:rwx . && + getfacl . | grep user:root:rwx && + touch should-have-readable-acl && + getfacl should-have-readable-acl | egrep "mask::?rw-" + then + test_set_prereq SETFACL + fi +' if test -z "$LOGNAME" then diff --git a/t/t1306-xdg-files.sh b/t/t1306-xdg-files.sh new file mode 100755 index 0000000000..8b14ab187c --- /dev/null +++ b/t/t1306-xdg-files.sh @@ -0,0 +1,197 @@ +#!/bin/sh +# +# Copyright (c) 2012 Valentin Duperray, Lucien Kong, Franck Jonas, +# Thomas Nguy, Khoi Nguyen +# Grenoble INP Ensimag +# + +test_description='Compatibility with $XDG_CONFIG_HOME/git/ files' + +. ./test-lib.sh + +test_expect_success 'read config: xdg file exists and ~/.gitconfig doesn'\''t' ' + mkdir -p .config/git && + echo "[alias]" >.config/git/config && + echo " myalias = !echo in_config" >>.config/git/config && + echo in_config >expected && + git myalias >actual && + test_cmp expected actual +' + + +test_expect_success 'read config: xdg file exists and ~/.gitconfig exists' ' + >.gitconfig && + echo "[alias]" >.gitconfig && + echo " myalias = !echo in_gitconfig" >>.gitconfig && + echo in_gitconfig >expected && + git myalias >actual && + test_cmp expected actual +' + + +test_expect_success 'read with --get: xdg file exists and ~/.gitconfig doesn'\''t' ' + rm .gitconfig && + echo "[user]" >.config/git/config && + echo " name = read_config" >>.config/git/config && + echo read_config >expected && + git config --get user.name >actual && + test_cmp expected actual +' + +test_expect_success '"$XDG_CONFIG_HOME overrides $HOME/.config/git' ' + mkdir -p "$HOME"/xdg/git && + echo "[user]name = in_xdg" >"$HOME"/xdg/git/config && + echo in_xdg >expected && + XDG_CONFIG_HOME="$HOME"/xdg git config --get-all user.name >actual && + test_cmp expected actual +' + +test_expect_success 'read with --get: xdg file exists and ~/.gitconfig exists' ' + >.gitconfig && + echo "[user]" >.gitconfig && + echo " name = read_gitconfig" >>.gitconfig && + echo read_gitconfig >expected && + git config --get user.name >actual && + test_cmp expected actual +' + + +test_expect_success 'read with --list: xdg file exists and ~/.gitconfig doesn'\''t' ' + rm .gitconfig && + echo user.name=read_config >expected && + git config --global --list >actual && + test_cmp expected actual +' + + +test_expect_success 'read with --list: xdg file exists and ~/.gitconfig exists' ' + >.gitconfig && + echo "[user]" >.gitconfig && + echo " name = read_gitconfig" >>.gitconfig && + echo user.name=read_gitconfig >expected && + git config --global --list >actual && + test_cmp expected actual +' + + +test_expect_success 'Setup' ' + git init git && + cd git && + echo foo >to_be_excluded +' + + +test_expect_success 'Exclusion of a file in the XDG ignore file' ' + mkdir -p "$HOME"/.config/git/ && + echo to_be_excluded >"$HOME"/.config/git/ignore && + test_must_fail git add to_be_excluded +' + +test_expect_success '$XDG_CONFIG_HOME overrides $HOME/.config/git/ignore' ' + mkdir -p "$HOME"/xdg/git && + echo content >excluded_by_xdg_only && + echo excluded_by_xdg_only >"$HOME"/xdg/git/ignore && + test_when_finished "git read-tree --empty" && + (XDG_CONFIG_HOME="$HOME/xdg" && + export XDG_CONFIG_HOME && + git add to_be_excluded && + test_must_fail git add excluded_by_xdg_only + ) +' + +test_expect_success 'Exclusion in both XDG and local ignore files' ' + echo to_be_excluded >.gitignore && + test_must_fail git add to_be_excluded +' + + +test_expect_success 'Exclusion in a non-XDG global ignore file' ' + rm .gitignore && + echo >"$HOME"/.config/git/ignore && + echo to_be_excluded >"$HOME"/my_gitignore && + git config core.excludesfile "$HOME"/my_gitignore && + test_must_fail git add to_be_excluded +' + +test_expect_success 'Checking XDG ignore file when HOME is unset' ' + >expected && + (sane_unset HOME && + git config --unset core.excludesfile && + git ls-files --exclude-standard --ignored >actual) && + test_cmp expected actual +' + +test_expect_success 'Checking attributes in the XDG attributes file' ' + echo foo >f && + git check-attr -a f >actual && + test_line_count -eq 0 actual && + echo "f attr_f" >"$HOME"/.config/git/attributes && + echo "f: attr_f: set" >expected && + git check-attr -a f >actual && + test_cmp expected actual +' + +test_expect_success 'Checking XDG attributes when HOME is unset' ' + >expected && + (sane_unset HOME && + git check-attr -a f >actual) && + test_cmp expected actual +' + +test_expect_success '$XDG_CONFIG_HOME overrides $HOME/.config/git/attributes' ' + mkdir -p "$HOME"/xdg/git && + echo "f attr_f=xdg" >"$HOME"/xdg/git/attributes && + echo "f: attr_f: xdg" >expected && + XDG_CONFIG_HOME="$HOME/xdg" git check-attr -a f >actual && + test_cmp expected actual +' + +test_expect_success 'Checking attributes in both XDG and local attributes files' ' + echo "f -attr_f" >.gitattributes && + echo "f: attr_f: unset" >expected && + git check-attr -a f >actual && + test_cmp expected actual +' + + +test_expect_success 'Checking attributes in a non-XDG global attributes file' ' + test_might_fail rm .gitattributes && + echo "f attr_f=test" >"$HOME"/my_gitattributes && + git config core.attributesfile "$HOME"/my_gitattributes && + echo "f: attr_f: test" >expected && + git check-attr -a f >actual && + test_cmp expected actual +' + + +test_expect_success 'write: xdg file exists and ~/.gitconfig doesn'\''t' ' + mkdir -p "$HOME"/.config/git && + >"$HOME"/.config/git/config && + test_might_fail rm "$HOME"/.gitconfig && + git config --global user.name "write_config" && + echo "[user]" >expected && + echo " name = write_config" >>expected && + test_cmp expected "$HOME"/.config/git/config +' + + +test_expect_success 'write: xdg file exists and ~/.gitconfig exists' ' + >"$HOME"/.gitconfig && + git config --global user.name "write_gitconfig" && + echo "[user]" >expected && + echo " name = write_gitconfig" >>expected && + test_cmp expected "$HOME"/.gitconfig +' + + +test_expect_success 'write: ~/.config/git/ exists and config file doesn'\''t' ' + test_might_fail rm "$HOME"/.gitconfig && + test_might_fail rm "$HOME"/.config/git/config && + git config --global user.name "write_gitconfig" && + echo "[user]" >expected && + echo " name = write_gitconfig" >>expected && + test_cmp expected "$HOME"/.gitconfig +' + + +test_done diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh new file mode 100755 index 0000000000..6b3d797cea --- /dev/null +++ b/t/t1512-rev-parse-disambiguation.sh @@ -0,0 +1,264 @@ +#!/bin/sh + +test_description='object name disambiguation + +Create blobs, trees, commits and a tag that all share the same +prefix, and make sure "git rev-parse" can take advantage of +type information to disambiguate short object names that are +not necessarily unique. + +The final history used in the test has five commits, with the bottom +one tagged as v1.0.0. They all have one regular file each. + + +-------------------------------------------+ + | | + | .-------b3wettvi---- ad2uee | + | / / | + | a2onsxbvj---czy8f73t--ioiley5o | + | | + +-------------------------------------------+ + +' + +. ./test-lib.sh + +test_expect_success 'blob and tree' ' + test_tick && + ( + for i in 0 1 2 3 4 5 6 7 8 9 + do + echo $i + done + echo + echo b1rwzyc3 + ) >a0blgqsjc && + + # create one blob 0000000000b36 + git add a0blgqsjc && + + # create one tree 0000000000cdc + git write-tree +' + +test_expect_success 'warn ambiguity when no candidate matches type hint' ' + test_must_fail git rev-parse --verify 000000000^{commit} 2>actual && + grep "short SHA1 000000000 is ambiguous" actual +' + +test_expect_success 'disambiguate tree-ish' ' + # feed tree-ish in an unambiguous way + git rev-parse --verify 0000000000cdc:a0blgqsjc && + + # ambiguous at the object name level, but there is only one + # such tree-ish (the other is a blob) + git rev-parse --verify 000000000:a0blgqsjc +' + +test_expect_success 'disambiguate blob' ' + sed -e "s/|$//" >patch <<-EOF && + diff --git a/frotz b/frotz + index 000000000..ffffff 100644 + --- a/frotz + +++ b/frotz + @@ -10,3 +10,4 @@ + 9 + | + b1rwzyc3 + +irwry + EOF + ( + GIT_INDEX_FILE=frotz && + export GIT_INDEX_FILE && + git apply --build-fake-ancestor frotz patch && + git cat-file blob :frotz >actual + ) && + test_cmp a0blgqsjc actual +' + +test_expect_success 'disambiguate tree' ' + commit=$(echo "d7xm" | git commit-tree 000000000) && + test $(git rev-parse $commit^{tree}) = $(git rev-parse 0000000000cdc) +' + +test_expect_success 'first commit' ' + # create one commit 0000000000e4f + git commit -m a2onsxbvj +' + +test_expect_success 'disambiguate commit-ish' ' + # feed commit-ish in an unambiguous way + git rev-parse --verify 0000000000e4f^{commit} && + + # ambiguous at the object name level, but there is only one + # such commit (the others are tree and blob) + git rev-parse --verify 000000000^{commit} && + + # likewise + git rev-parse --verify 000000000^0 +' + +test_expect_success 'disambiguate commit' ' + commit=$(echo "hoaxj" | git commit-tree 0000000000cdc -p 000000000) && + test $(git rev-parse $commit^) = $(git rev-parse 0000000000e4f) +' + +test_expect_success 'log name1..name2 takes only commit-ishes on both ends' ' + git log 000000000..000000000 && + git log ..000000000 && + git log 000000000.. && + git log 000000000...000000000 && + git log ...000000000 && + git log 000000000... +' + +test_expect_success 'rev-parse name1..name2 takes only commit-ishes on both ends' ' + git rev-parse 000000000..000000000 && + git rev-parse ..000000000 && + git rev-parse 000000000.. +' + +test_expect_success 'git log takes only commit-ish' ' + git log 000000000 +' + +test_expect_success 'git reset takes only commit-ish' ' + git reset 000000000 +' + +test_expect_success 'first tag' ' + # create one tag 0000000000f8f + git tag -a -m j7cp83um v1.0.0 +' + +test_expect_failure 'two semi-ambiguous commit-ish' ' + # Once the parser becomes ultra-smart, it could notice that + # 110282 before ^{commit} name many different objects, but + # that only two (HEAD and v1.0.0 tag) can be peeled to commit, + # and that peeling them down to commit yield the same commit + # without ambiguity. + git rev-parse --verify 110282^{commit} && + + # likewise + git log 000000000..000000000 && + git log ..000000000 && + git log 000000000.. && + git log 000000000...000000000 && + git log ...000000000 && + git log 000000000... +' + +test_expect_failure 'three semi-ambiguous tree-ish' ' + # Likewise for tree-ish. HEAD, v1.0.0 and HEAD^{tree} share + # the prefix but peeling them to tree yields the same thing + git rev-parse --verify 000000000^{tree} +' + +test_expect_success 'parse describe name' ' + # feed an unambiguous describe name + git rev-parse --verify v1.0.0-0-g0000000000e4f && + + # ambiguous at the object name level, but there is only one + # such commit (others are blob, tree and tag) + git rev-parse --verify v1.0.0-0-g000000000 +' + +test_expect_success 'more history' ' + # commit 0000000000043 + git mv a0blgqsjc d12cr3h8t && + echo h62xsjeu >>d12cr3h8t && + git add d12cr3h8t && + + test_tick && + git commit -m czy8f73t && + + # commit 00000000008ec + git mv d12cr3h8t j000jmpzn && + echo j08bekfvt >>j000jmpzn && + git add j000jmpzn && + + test_tick && + git commit -m ioiley5o && + + # commit 0000000005b0 + git checkout v1.0.0^0 && + git mv a0blgqsjc f5518nwu && + + for i in h62xsjeu j08bekfvt kg7xflhm + do + echo $i + done >>f5518nwu && + git add f5518nwu && + + test_tick && + git commit -m b3wettvi && + side=$(git rev-parse HEAD) && + + # commit 000000000066 + git checkout master && + + # If you use recursive, merge will fail and you will need to + # clean up a0blgqsjc as well. If you use resolve, merge will + # succeed. + test_might_fail git merge --no-commit -s recursive $side && + git rm -f f5518nwu j000jmpzn && + + test_might_fail git rm -f a0blgqsjc && + ( + git cat-file blob $side:f5518nwu + echo j3l0i9s6 + ) >ab2gs879 && + git add ab2gs879 && + + test_tick && + git commit -m ad2uee + +' + +test_expect_failure 'parse describe name taking advantage of generation' ' + # ambiguous at the object name level, but there is only one + # such commit at generation 0 + git rev-parse --verify v1.0.0-0-g000000000 && + + # likewise for generation 2 and 4 + git rev-parse --verify v1.0.0-2-g000000000 && + git rev-parse --verify v1.0.0-4-g000000000 +' + +# Note: because rev-parse does not even try to disambiguate based on +# the generation number, this test currently succeeds for a wrong +# reason. When it learns to use the generation number, the previous +# test should succeed, and also this test should fail because the +# describe name used in the test with generation number can name two +# commits. Make sure that such a future enhancement does not randomly +# pick one. +test_expect_success 'parse describe name not ignoring ambiguity' ' + # ambiguous at the object name level, and there are two such + # commits at generation 1 + test_must_fail git rev-parse --verify v1.0.0-1-g000000000 +' + +test_expect_success 'ambiguous commit-ish' ' + # Now there are many commits that begin with the + # common prefix, none of these should pick one at + # random. They all should result in ambiguity errors. + test_must_fail git rev-parse --verify 110282^{commit} && + + # likewise + test_must_fail git log 000000000..000000000 && + test_must_fail git log ..000000000 && + test_must_fail git log 000000000.. && + test_must_fail git log 000000000...000000000 && + test_must_fail git log ...000000000 && + test_must_fail git log 000000000... +' + +test_expect_success 'rev-parse --disambiguate' ' + # The test creates 16 objects that share the prefix and two + # commits created by commit-tree in earlier tests share a + # different prefix. + git rev-parse --disambiguate=000000000 >actual && + test $(wc -l <actual) = 16 && + test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000 +' + +test_done diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 7788ae02ad..1de0ebda25 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -68,24 +68,24 @@ test_expect_success 'rebase against master' ' test_expect_success 'rebase against master twice' ' git rebase master >out && - grep "Current branch my-topic-branch is up to date" out + test_i18ngrep "Current branch my-topic-branch is up to date" out ' test_expect_success 'rebase against master twice with --force' ' git rebase --force-rebase master >out && - grep "Current branch my-topic-branch is up to date, rebase forced" out + test_i18ngrep "Current branch my-topic-branch is up to date, rebase forced" out ' test_expect_success 'rebase against master twice from another branch' ' git checkout my-topic-branch^ && git rebase master my-topic-branch >out && - grep "Current branch my-topic-branch is up to date" out + test_i18ngrep "Current branch my-topic-branch is up to date" out ' test_expect_success 'rebase fast-forward to master' ' git checkout my-topic-branch^ && git rebase my-topic-branch >out && - grep "Fast-forwarded HEAD to my-topic-branch" out + test_i18ngrep "Fast-forwarded HEAD to my-topic-branch" out ' test_expect_success 'the rebase operation should not have destroyed author information' ' diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 025c1c610e..7304b663c3 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -755,4 +755,160 @@ test_expect_success 'rebase-i history with funny messages' ' test_cmp expect actual ' + +test_expect_success 'prepare for rebase -i --exec' ' + git checkout master && + git checkout -b execute && + test_commit one_exec main.txt one_exec && + test_commit two_exec main.txt two_exec && + test_commit three_exec main.txt three_exec +' + + +test_expect_success 'running "git rebase -i --exec git show HEAD"' ' + git rebase -i --exec "git show HEAD" HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,9d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'running "git rebase --exec git show HEAD -i"' ' + git reset --hard execute && + git rebase --exec "git show HEAD" -i HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,9d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'running "git rebase -ix git show HEAD"' ' + git reset --hard execute && + git rebase -ix "git show HEAD" HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,9d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'rebase -ix with several <CMD>' ' + git reset --hard execute && + git rebase -ix "git show HEAD; pwd" HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,9d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'rebase -ix with several instances of --exec' ' + git reset --hard execute && + git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2 + exec_git_show_HEAD exec_pwd" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,11d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'rebase -ix with --autosquash' ' + git reset --hard execute && + git checkout -b autosquash && + echo second >second.txt && + git add second.txt && + git commit -m "fixup! two_exec" && + echo bis >bis.txt && + git add bis.txt && + git commit -m "fixup! two_exec" && + ( + git checkout -b autosquash_actual && + git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual + ) && + git checkout autosquash && + ( + git checkout -b autosquash_expected && + FAKE_LINES="1 fixup 3 fixup 4 exec_git_show_HEAD 2 exec_git_show_HEAD" && + export FAKE_LINES && + git rebase -i HEAD~4 >expect + ) && + sed -e "1,13d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'rebase --exec without -i shows error message' ' + git reset --hard execute && + test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual && + echo "The --exec option must be used with the --interactive option" >expected && + test_i18ncmp expected actual +' + + +test_expect_success 'rebase -i --exec without <CMD>' ' + git reset --hard execute && + test_must_fail git rebase -i --exec 2>tmp && + sed -e "1d" tmp >actual && + test_must_fail git rebase -h >expected && + test_cmp expected actual && + git checkout master +' + +test_expect_success 'rebase -i --root re-order and drop commits' ' + git checkout E && + FAKE_LINES="3 1 2 5" git rebase -i --root && + test E = $(git cat-file commit HEAD | sed -ne \$p) && + test B = $(git cat-file commit HEAD^ | sed -ne \$p) && + test A = $(git cat-file commit HEAD^^ | sed -ne \$p) && + test C = $(git cat-file commit HEAD^^^ | sed -ne \$p) && + test 0 = $(git cat-file commit HEAD^^^ | grep -c ^parent\ ) +' + +test_expect_success 'rebase -i --root retain root commit author and message' ' + git checkout A && + echo B >file7 && + git add file7 && + GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" && + FAKE_LINES="2" git rebase -i --root && + git cat-file commit HEAD | grep -q "^author Twerp Snog" && + git cat-file commit HEAD | grep -q "^different author$" +' + +test_expect_success 'rebase -i --root temporary sentinel commit' ' + git checkout B && + ( + FAKE_LINES="2" && + export FAKE_LINES && + test_must_fail git rebase -i --root + ) && + git cat-file commit HEAD | grep "^tree 4b825dc642cb" && + git rebase --abort +' + +test_expect_success 'rebase -i --root fixup root commit' ' + git checkout B && + FAKE_LINES="1 fixup 2" git rebase -i --root && + test A = $(git cat-file commit HEAD | sed -ne \$p) && + test B = $(git show HEAD:file1) && + test 0 = $(git cat-file commit HEAD | grep -c ^parent\ ) +' + test_done diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh index e5ad67c643..19eddadcf7 100755 --- a/t/t3405-rebase-malformed.sh +++ b/t/t3405-rebase-malformed.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='rebase should not insist on git message convention' +test_description='rebase should handle arbitrary git message' . ./test-lib.sh @@ -12,6 +12,11 @@ It has two paragraphs, but its first paragraph is not friendly to oneline summary format. EOF +cat >G <<\EOF +commit log message containing a diff +EOF + + test_expect_success setup ' >file1 && @@ -19,8 +24,9 @@ test_expect_success setup ' git add file1 file2 && test_tick && git commit -m "Initial commit" && + git branch diff-in-message - git checkout -b side && + git checkout -b multi-line-subject && cat F >file2 && git add file2 && test_tick && @@ -28,6 +34,17 @@ test_expect_success setup ' git cat-file commit HEAD | sed -e "1,/^\$/d" >F0 && + git checkout diff-in-message && + echo "commit log message containing a diff" >G && + echo "" >>G + cat G >file2 && + git add file2 && + git diff --cached >>G && + test_tick && + git commit -F G && + + git cat-file commit HEAD | sed -e "1,/^\$/d" >G0 && + git checkout master && echo One >file1 && @@ -36,13 +53,20 @@ test_expect_success setup ' git commit -m "Second commit" ' -test_expect_success rebase ' +test_expect_success 'rebase commit with multi-line subject' ' - git rebase master side && + git rebase master multi-line-subject && git cat-file commit HEAD | sed -e "1,/^\$/d" >F1 && test_cmp F0 F1 && test_cmp F F0 ' +test_expect_success 'rebase commit with diff in message' ' + git rebase master diff-in-message && + git cat-file commit HEAD | sed -e "1,/^$/d" >G1 && + test_cmp G0 G1 && + test_cmp G G0 +' + test_done diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index 6898377910..e6a9a0d436 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -62,9 +62,16 @@ test_expect_success 'rebase -n overrides config rebase.stat config' ' ! grep "^ fileX | *1 +$" diffstat.txt ' +# Output to stderr: +# +# "Does not point to a valid commit: invalid-ref" +# +# NEEDSWORK: This "grep" is fine in real non-C locales, but +# GETTEXT_POISON poisons the refname along with the enclosing +# error message. test_expect_success 'rebase --onto outputs the invalid ref' ' test_must_fail git rebase --onto invalid-ref HEAD HEAD 2>err && - grep "invalid-ref" err + test_i18ngrep "invalid-ref" err ' test_done diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh index 086c91c7b4..0b52105728 100755 --- a/t/t3412-rebase-root.sh +++ b/t/t3412-rebase-root.sh @@ -22,8 +22,9 @@ test_expect_success 'prepare repository' ' test_commit 4 B ' -test_expect_success 'rebase --root expects --onto' ' - test_must_fail git rebase --root +test_expect_success 'rebase --root fails with too many args' ' + git checkout -B fail other && + test_must_fail git rebase --onto master --root fail fail ' test_expect_success 'setup pre-rebase hook' ' @@ -42,7 +43,7 @@ cat > expect <<EOF EOF test_expect_success 'rebase --root --onto <newbase>' ' - git checkout -b work && + git checkout -b work other && git rebase --root --onto master && git log --pretty=tformat:"%s" > rebased && test_cmp expect rebased diff --git a/t/t3910-mac-os-precompose.sh b/t/t3910-mac-os-precompose.sh new file mode 100755 index 0000000000..88b7a20c11 --- /dev/null +++ b/t/t3910-mac-os-precompose.sh @@ -0,0 +1,164 @@ +#!/bin/sh +# +# Copyright (c) 2012 Torsten Bögershausen +# + +test_description='utf-8 decomposed (nfd) converted to precomposed (nfc)' + +. ./test-lib.sh + +Adiarnfc=`printf '\303\204'` +Adiarnfd=`printf 'A\314\210'` + +# check if the feature is compiled in +mkdir junk && +>junk/"$Adiarnfc" && +case "$(cd junk && echo *)" in + "$Adiarnfd") + test_nfd=1 + ;; + *) ;; +esac +rm -rf junk + + +if test "$test_nfd" +then + # create more utf-8 variables + Odiarnfc=`printf '\303\226'` + Odiarnfd=`printf 'O\314\210'` + AEligatu=`printf '\303\206'` + Invalidu=`printf '\303\377'` + + + #Create a string with 255 bytes (decomposed) + Alongd=$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd #21 Byte + Alongd=$Alongd$Alongd$Alongd #63 Byte + Alongd=$Alongd$Alongd$Alongd$Alongd$Adiarnfd #255 Byte + + #Create a string with 254 bytes (precomposed) + Alongc=$AEligatu$AEligatu$AEligatu$AEligatu$AEligatu #10 Byte + Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #50 Byte + Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #250 Byte + Alongc=$Alongc$AEligatu$AEligatu #254 Byte + + test_expect_success "detect if nfd needed" ' + precomposeunicode=`git config core.precomposeunicode` && + test "$precomposeunicode" = false && + git config core.precomposeunicode true + ' + test_expect_success "setup" ' + >x && + git add x && + git commit -m "1st commit" && + git rm x && + git commit -m "rm x" + ' + test_expect_success "setup case mac" ' + git checkout -b mac_os + ' + # This will test nfd2nfc in readdir() + test_expect_success "add file Adiarnfc" ' + echo f.Adiarnfc >f.$Adiarnfc && + git add f.$Adiarnfc && + git commit -m "add f.$Adiarnfc" + ' + # This will test nfd2nfc in git stage() + test_expect_success "stage file d.Adiarnfd/f.Adiarnfd" ' + mkdir d.$Adiarnfd && + echo d.$Adiarnfd/f.$Adiarnfd >d.$Adiarnfd/f.$Adiarnfd && + git stage d.$Adiarnfd/f.$Adiarnfd && + git commit -m "add d.$Adiarnfd/f.$Adiarnfd" + ' + test_expect_success "add link Adiarnfc" ' + ln -s d.$Adiarnfd/f.$Adiarnfd l.$Adiarnfc && + git add l.$Adiarnfc && + git commit -m "add l.Adiarnfc" + ' + # This will test git log + test_expect_success "git log f.Adiar" ' + git log f.$Adiarnfc > f.Adiarnfc.log && + git log f.$Adiarnfd > f.Adiarnfd.log && + test -s f.Adiarnfc.log && + test -s f.Adiarnfd.log && + test_cmp f.Adiarnfc.log f.Adiarnfd.log && + rm f.Adiarnfc.log f.Adiarnfd.log + ' + # This will test git ls-files + test_expect_success "git lsfiles f.Adiar" ' + git ls-files f.$Adiarnfc > f.Adiarnfc.log && + git ls-files f.$Adiarnfd > f.Adiarnfd.log && + test -s f.Adiarnfc.log && + test -s f.Adiarnfd.log && + test_cmp f.Adiarnfc.log f.Adiarnfd.log && + rm f.Adiarnfc.log f.Adiarnfd.log + ' + # This will test git mv + test_expect_success "git mv" ' + git mv f.$Adiarnfd f.$Odiarnfc && + git mv d.$Adiarnfd d.$Odiarnfc && + git mv l.$Adiarnfd l.$Odiarnfc && + git commit -m "mv Adiarnfd Odiarnfc" + ' + # Files can be checked out as nfc + # And the link has been corrected from nfd to nfc + test_expect_success "git checkout nfc" ' + rm f.$Odiarnfc && + git checkout f.$Odiarnfc + ' + # Make it possible to checkout files with their NFD names + test_expect_success "git checkout file nfd" ' + rm -f f.* && + git checkout f.$Odiarnfd + ' + # Make it possible to checkout links with their NFD names + test_expect_success "git checkout link nfd" ' + rm l.* && + git checkout l.$Odiarnfd + ' + test_expect_success "setup case mac2" ' + git checkout master && + git reset --hard && + git checkout -b mac_os_2 + ' + # This will test nfd2nfc in git commit + test_expect_success "commit file d2.Adiarnfd/f.Adiarnfd" ' + mkdir d2.$Adiarnfd && + echo d2.$Adiarnfd/f.$Adiarnfd >d2.$Adiarnfd/f.$Adiarnfd && + git add d2.$Adiarnfd/f.$Adiarnfd && + git commit -m "add d2.$Adiarnfd/f.$Adiarnfd" -- d2.$Adiarnfd/f.$Adiarnfd + ' + test_expect_success "setup for long decomposed filename" ' + git checkout master && + git reset --hard && + git checkout -b mac_os_long_nfd_fn + ' + test_expect_success "Add long decomposed filename" ' + echo longd >$Alongd && + git add * && + git commit -m "Long filename" + ' + test_expect_success "setup for long precomposed filename" ' + git checkout master && + git reset --hard && + git checkout -b mac_os_long_nfc_fn + ' + test_expect_success "Add long precomposed filename" ' + echo longc >$Alongc && + git add * && + git commit -m "Long filename" + ' + # Test if the global core.precomposeunicode stops autosensing + # Must be the last test case + test_expect_success "respect git config --global core.precomposeunicode" ' + git config --global core.precomposeunicode true && + rm -rf .git && + git init && + precomposeunicode=`git config core.precomposeunicode` && + test "$precomposeunicode" = "true" + ' +else + say "Skipping nfc/nfd tests" +fi + +test_done diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh index 6cebb3951b..ec4deea192 100755 --- a/t/t4012-diff-binary.sh +++ b/t/t4012-diff-binary.sh @@ -15,13 +15,14 @@ cat >expect.binary-numstat <<\EOF - - d EOF -test_expect_success 'prepare repository' \ - 'echo AIT >a && echo BIT >b && echo CIT >c && echo DIT >d && - git update-index --add a b c d && - echo git >a && - cat "$TEST_DIRECTORY"/test-binary-1.png >b && - echo git >c && - cat b b >d' +test_expect_success 'prepare repository' ' + echo AIT >a && echo BIT >b && echo CIT >c && echo DIT >d && + git update-index --add a b c d && + echo git >a && + cat "$TEST_DIRECTORY"/test-binary-1.png >b && + echo git >c && + cat b b >d +' cat > expected <<\EOF a | 2 +- @@ -30,16 +31,16 @@ cat > expected <<\EOF d | Bin 4 files changed, 2 insertions(+), 2 deletions(-) EOF -test_expect_success '"apply --stat" output for binary file change' ' +test_expect_success 'apply --stat output for binary file change' ' git diff >diff && git apply --stat --summary <diff >current && test_i18ncmp expected current ' test_expect_success 'diff --shortstat output for binary file change' ' - echo " 4 files changed, 2 insertions(+), 2 deletions(-)" >expected && + tail -n 1 expected >expect && git diff --shortstat >current && - test_i18ncmp expected current + test_i18ncmp expect current ' test_expect_success 'diff --shortstat output for binary file change only' ' @@ -62,49 +63,42 @@ test_expect_success 'apply --numstat understands diff --binary format' ' # apply needs to be able to skip the binary material correctly # in order to report the line number of a corrupt patch. -test_expect_success 'apply detecting corrupt patch correctly' \ - 'git diff | sed -e 's/-CIT/xCIT/' >broken && - if git apply --stat --summary broken 2>detected - then - echo unhappy - should have detected an error - (exit 1) - else - echo happy - fi && - detected=`cat detected` && - detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && - detected=`sed -ne "${detected}p" broken` && - test "$detected" = xCIT' - -test_expect_success 'apply detecting corrupt patch correctly' \ - 'git diff --binary | sed -e 's/-CIT/xCIT/' >broken && - if git apply --stat --summary broken 2>detected - then - echo unhappy - should have detected an error - (exit 1) - else - echo happy - fi && - detected=`cat detected` && - detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && - detected=`sed -ne "${detected}p" broken` && - test "$detected" = xCIT' +test_expect_success 'apply detecting corrupt patch correctly' ' + git diff >output && + sed -e "s/-CIT/xCIT/" <output >broken && + test_must_fail git apply --stat --summary broken 2>detected && + detected=`cat detected` && + detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && + detected=`sed -ne "${detected}p" broken` && + test "$detected" = xCIT +' + +test_expect_success 'apply detecting corrupt patch correctly' ' + git diff --binary | sed -e "s/-CIT/xCIT/" >broken && + test_must_fail git apply --stat --summary broken 2>detected && + detected=`cat detected` && + detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && + detected=`sed -ne "${detected}p" broken` && + test "$detected" = xCIT +' test_expect_success 'initial commit' 'git commit -a -m initial' # Try removal (b), modification (d), and creation (e). -test_expect_success 'diff-index with --binary' \ - 'echo AIT >a && mv b e && echo CIT >c && cat e >d && - git update-index --add --remove a b c d e && - tree0=`git write-tree` && - git diff --cached --binary >current && - git apply --stat --summary current' - -test_expect_success 'apply binary patch' \ - 'git reset --hard && - git apply --binary --index <current && - tree1=`git write-tree` && - test "$tree1" = "$tree0"' +test_expect_success 'diff-index with --binary' ' + echo AIT >a && mv b e && echo CIT >c && cat e >d && + git update-index --add --remove a b c d e && + tree0=`git write-tree` && + git diff --cached --binary >current && + git apply --stat --summary current +' + +test_expect_success 'apply binary patch' ' + git reset --hard && + git apply --binary --index <current && + tree1=`git write-tree` && + test "$tree1" = "$tree0" +' test_expect_success 'diff --no-index with binary creation' ' echo Q | q_to_nul >binary && @@ -125,7 +119,7 @@ cat >expect <<EOF EOF test_expect_success 'diff --stat with binary files and big change count' ' - echo X | dd of=binfile bs=1k seek=1 && + printf "\01\00%1024d" 1 >binfile && git add binfile && i=0 && while test $i -lt 10000; do diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh new file mode 100755 index 0000000000..fa5d4efb89 --- /dev/null +++ b/t/t4108-apply-threeway.sh @@ -0,0 +1,157 @@ +#!/bin/sh + +test_description='git apply --3way' + +. ./test-lib.sh + +create_file () { + for i + do + echo "$i" + done +} + +sanitize_conflicted_diff () { + sed -e ' + /^index /d + s/^\(+[<>][<>][<>][<>]*\) .*/\1/ + ' +} + +test_expect_success setup ' + test_tick && + create_file >one 1 2 3 4 5 6 7 && + cat one >two && + git add one two && + git commit -m initial && + + git branch side && + + test_tick && + create_file >one 1 two 3 4 5 six 7 && + create_file >two 1 two 3 4 5 6 7 && + git commit -a -m master && + + git checkout side && + create_file >one 1 2 3 4 five 6 7 && + create_file >two 1 2 3 4 five 6 7 && + git commit -a -m side && + + git checkout master +' + +test_expect_success 'apply without --3way' ' + git diff side^ side >P.diff && + + # should fail to apply + git reset --hard && + git checkout master^0 && + test_must_fail git apply --index P.diff && + # should leave things intact + git diff-files --exit-code && + git diff-index --exit-code --cached HEAD +' + +test_expect_success 'apply with --3way' ' + # Merging side should be similar to applying this patch + git diff ...side >P.diff && + + # The corresponding conflicted merge + git reset --hard && + git checkout master^0 && + test_must_fail git merge --no-commit side && + git ls-files -s >expect.ls && + git diff HEAD | sanitize_conflicted_diff >expect.diff && + + # should fail to apply + git reset --hard && + git checkout master^0 && + test_must_fail git apply --index --3way P.diff && + git ls-files -s >actual.ls && + git diff HEAD | sanitize_conflicted_diff >actual.diff && + + # The result should resemble the corresponding merge + test_cmp expect.ls actual.ls && + test_cmp expect.diff actual.diff +' + +test_expect_success 'apply with --3way with rerere enabled' ' + git config rerere.enabled true && + + # Merging side should be similar to applying this patch + git diff ...side >P.diff && + + # The corresponding conflicted merge + git reset --hard && + git checkout master^0 && + test_must_fail git merge --no-commit side && + + # Manually resolve and record the resolution + create_file 1 two 3 4 five six 7 >one && + git rerere && + cat one >expect && + + # should fail to apply + git reset --hard && + git checkout master^0 && + test_must_fail git apply --index --3way P.diff && + + # but rerere should have replayed the recorded resolution + test_cmp expect one +' + +test_expect_success 'apply -3 with add/add conflict setup' ' + git reset --hard && + + git checkout -b adder && + create_file 1 2 3 4 5 6 7 >three && + create_file 1 2 3 4 5 6 7 >four && + git add three four && + git commit -m "add three and four" && + + git checkout -b another adder^ && + create_file 1 2 3 4 5 6 7 >three && + create_file 1 2 3 four 5 6 7 >four && + git add three four && + git commit -m "add three and four" && + + # Merging another should be similar to applying this patch + git diff adder...another >P.diff && + + git checkout adder^0 && + test_must_fail git merge --no-commit another && + git ls-files -s >expect.ls && + git diff HEAD | sanitize_conflicted_diff >expect.diff +' + +test_expect_success 'apply -3 with add/add conflict' ' + # should fail to apply ... + git reset --hard && + git checkout adder^0 && + test_must_fail git apply --index --3way P.diff && + # ... and leave conflicts in the index and in the working tree + git ls-files -s >actual.ls && + git diff HEAD | sanitize_conflicted_diff >actual.diff && + + # The result should resemble the corresponding merge + test_cmp expect.ls actual.ls && + test_cmp expect.diff actual.diff +' + +test_expect_success 'apply -3 with add/add conflict (dirty working tree)' ' + # should fail to apply ... + git reset --hard && + git checkout adder^0 && + echo >>four && + cat four >four.save && + cat three >three.save && + git ls-files -s >expect.ls && + test_must_fail git apply --index --3way P.diff && + # ... and should not touch anything + git ls-files -s >actual.ls && + test_cmp expect.ls actual.ls && + test_cmp four.save four && + test_cmp three.save three +' + +test_done diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh index e9ccd161ee..8e15ecbdfd 100755 --- a/t/t4117-apply-reject.sh +++ b/t/t4117-apply-reject.sh @@ -46,6 +46,14 @@ test_expect_success setup ' cat file1 >saved.file1 ' +test_expect_success 'apply --reject is incompatible with --3way' ' + test_when_finished "cat saved.file1 >file1" && + git diff >patch.0 && + git checkout file1 && + test_must_fail git apply --reject --3way patch.0 && + git diff --exit-code +' + test_expect_success 'apply without --reject should fail' ' if git apply patch.1 diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 4fd69a19eb..2e52f8b838 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -418,4 +418,9 @@ test_expect_success \ 'test_must_fail git index-pack -o bad.idx test-3.pack 2>msg && grep "SHA1 COLLISION FOUND" msg' +test_expect_success \ + 'make sure index-pack detects the SHA1 collision (large blobs)' \ + 'test_must_fail git -c core.bigfilethreshold=1 index-pack -o bad.idx test-3.pack 2>msg && + grep "SHA1 COLLISION FOUND" msg' + test_done diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 6764d511ce..d16e5d384a 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -87,17 +87,15 @@ test_expect_success 'use branch.<name>.remote if possible' ' test_expect_success 'confuses pattern as remote when no remote specified' ' cat >exp <<-\EOF && fatal: '\''refs*master'\'' does not appear to be a git repository - fatal: The remote end hung up unexpectedly + fatal: Could not read from remote repository. + + Please make sure you have the correct access rights + and the repository exists. EOF # - # Do not expect "git ls-remote <pattern>" to work; ls-remote, correctly, - # confuses <pattern> for <remote>. Although ugly, this behaviour is akin - # to the confusion of refspecs for remotes by git-fetch and git-push, - # eg: - # - # $ git fetch branch - # - + # Do not expect "git ls-remote <pattern>" to work; ls-remote needs + # <remote> if you want to feed <pattern>, just like you cannot say + # fetch <branch>. # We could just as easily have used "master"; the "*" emphasizes its # role as a pattern. test_must_fail git ls-remote refs*master >actual 2>&1 && diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index c6feca44e3..7ff6e0e16c 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -124,4 +124,14 @@ test_expect_success 'cloning non-git directory fails' ' test_must_fail git clone not-a-git-repo not-a-git-repo-clone ' +test_expect_success 'cloning file:// does not hardlink' ' + git clone --bare file://"$(pwd)"/a non-local && + ! repo_is_hardlinked non-local +' + +test_expect_success 'cloning a local path with --no-local does not hardlink' ' + git clone --bare --no-local a force-nonlocal && + ! repo_is_hardlinked force-nonlocal +' + test_done diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index 1104249182..c680f789a7 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -242,10 +242,10 @@ test_expect_success 'merge of identical changes in a renamed file' ' rm -f A M N && git reset --hard && git checkout change+rename && - GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" && + GIT_MERGE_VERBOSITY=3 git merge change | test_i18ngrep "^Skipped B" && git reset --hard HEAD^ && git checkout change && - GIT_MERGE_VERBOSITY=3 git merge change+rename | grep "^Skipped B" + GIT_MERGE_VERBOSITY=3 git merge change+rename | test_i18ngrep "^Skipped B" ' test_expect_success 'setup for rename + d/f conflicts' ' @@ -303,9 +303,9 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' ' git checkout -q renamed-file-has-no-conflicts^0 && test_must_fail git merge --strategy=recursive dir-in-way >output && - grep "CONFLICT (modify/delete): dir/file-in-the-way" output && - grep "Auto-merging dir" output && - grep "Adding as dir~HEAD instead" output && + test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output && + test_i18ngrep "Auto-merging dir" output && + test_i18ngrep "Adding as dir~HEAD instead" output && test 3 -eq "$(git ls-files -u | wc -l)" && test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" && @@ -325,9 +325,9 @@ test_expect_success 'Same as previous, but merged other way' ' test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors && ! grep "error: refusing to lose untracked file at" errors && - grep "CONFLICT (modify/delete): dir/file-in-the-way" output && - grep "Auto-merging dir" output && - grep "Adding as dir~renamed-file-has-no-conflicts instead" output && + test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output && + test_i18ngrep "Auto-merging dir" output && + test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output && test 3 -eq "$(git ls-files -u | wc -l)" && test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" && diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh index 466fa3804b..411550d2b6 100755 --- a/t/t6042-merge-rename-corner-cases.sh +++ b/t/t6042-merge-rename-corner-cases.sh @@ -380,7 +380,7 @@ test_expect_success 'handle rename/rename (2to1) conflict correctly' ' git checkout B^0 && test_must_fail git merge -s recursive C^0 >out && - grep "CONFLICT (rename/rename)" out && + test_i18ngrep "CONFLICT (rename/rename)" out && test 2 -eq $(git ls-files -s | wc -l) && test 2 -eq $(git ls-files -u | wc -l) && diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index b8cb4906aa..f4f38a5e73 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -30,6 +30,9 @@ test_expect_success 'Report new path with conflict' ' cat >expect <<EOF # On branch side +# You have unmerged paths. +# (fix conflicts and run "git commit") +# # Unmerged paths: # (use "git add/rm <file>..." as appropriate to mark resolution) # @@ -118,4 +121,97 @@ test_expect_success 'git diff-index --cached -C shows 2 copies + 1 unmerged' ' test_cmp expected actual ' + +test_expect_success 'status when conflicts with add and rm advice (deleted by them)' ' + git reset --hard && + git checkout master && + test_commit init main.txt init && + git checkout -b second_branch && + git rm main.txt && + git commit -m "main.txt deleted on second_branch" && + test_commit second conflict.txt second && + git checkout master && + test_commit on_second main.txt on_second && + test_commit master conflict.txt master && + test_must_fail git merge second_branch && + cat >expected <<-\EOF && + # On branch master + # You have unmerged paths. + # (fix conflicts and run "git commit") + # + # Unmerged paths: + # (use "git add/rm <file>..." as appropriate to mark resolution) + # + # both added: conflict.txt + # deleted by them: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for conflicts' ' + git reset --hard && + git checkout -b conflict && + test_commit one main.txt one && + git branch conflict_second && + git mv main.txt sub_master.txt && + git commit -m "main.txt renamed in sub_master.txt" && + git checkout conflict_second && + git mv main.txt sub_second.txt && + git commit -m "main.txt renamed in sub_second.txt" +' + + +test_expect_success 'status when conflicts with add and rm advice (both deleted)' ' + test_must_fail git merge conflict && + cat >expected <<-\EOF && + # On branch conflict_second + # You have unmerged paths. + # (fix conflicts and run "git commit") + # + # Unmerged paths: + # (use "git add/rm <file>..." as appropriate to mark resolution) + # + # both deleted: main.txt + # added by them: sub_master.txt + # added by us: sub_second.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when conflicts with only rm advice (both deleted)' ' + git reset --hard conflict_second && + test_must_fail git merge conflict && + git add sub_master.txt && + git add sub_second.txt && + cat >expected <<-\EOF && + # On branch conflict_second + # You have unmerged paths. + # (fix conflicts and run "git commit") + # + # Changes to be committed: + # + # new file: sub_master.txt + # + # Unmerged paths: + # (use "git rm <file>..." to mark resolution) + # + # both deleted: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual && + git reset --hard && + git checkout master +' + + test_done diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 81827e696f..c73bec9551 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -483,21 +483,72 @@ test_expect_success 'set up for relative path tests' ' git add sub && git config -f .gitmodules submodule.sub.path sub && git config -f .gitmodules submodule.sub.url ../subrepo && - cp .git/config pristine-.git-config + cp .git/config pristine-.git-config && + cp .gitmodules pristine-.gitmodules ) ' -test_expect_success 'relative path works with URL' ' +test_expect_success '../subrepo works with URL - ssh://hostname/repo' ' ( cd reltest && cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && git config remote.origin.url ssh://hostname/repo && git submodule init && test "$(git config submodule.sub.url)" = ssh://hostname/subrepo ) ' -test_expect_success 'relative path works with user@host:path' ' +test_expect_success '../subrepo works with port-qualified URL - ssh://hostname:22/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ssh://hostname:22/repo && + git submodule init && + test "$(git config submodule.sub.url)" = ssh://hostname:22/subrepo + ) +' + +# About the choice of the path in the next test: +# - double-slash side-steps path mangling issues on Windows +# - it is still an absolute local path +# - there cannot be a server with a blank in its name just in case the +# path is used erroneously to access a //server/share style path +test_expect_success '../subrepo path works with local path - //somewhere else/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url "//somewhere else/repo" && + git submodule init && + test "$(git config submodule.sub.url)" = "//somewhere else/subrepo" + ) +' + +test_expect_success '../subrepo works with file URL - file:///tmp/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url file:///tmp/repo && + git submodule init && + test "$(git config submodule.sub.url)" = file:///tmp/subrepo + ) +' + +test_expect_success '../subrepo works with helper URL- helper:://hostname/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url helper:://hostname/repo && + git submodule init && + test "$(git config submodule.sub.url)" = helper:://hostname/subrepo + ) +' + +test_expect_success '../subrepo works with scp-style URL - user@host:repo' ' ( cd reltest && cp pristine-.git-config .git/config && @@ -507,6 +558,98 @@ test_expect_success 'relative path works with user@host:path' ' ) ' +test_expect_success '../subrepo works with scp-style URL - user@host:path/to/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url user@host:path/to/repo && + git submodule init && + test "$(git config submodule.sub.url)" = user@host:path/to/subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - foo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url foo && + # actual: fails with an error + git submodule init && + test "$(git config submodule.sub.url)" = subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - foo/bar' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url foo/bar && + git submodule init && + test "$(git config submodule.sub.url)" = foo/subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - ./foo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ./foo && + git submodule init && + test "$(git config submodule.sub.url)" = subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - ./foo/bar' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ./foo/bar && + git submodule init && + test "$(git config submodule.sub.url)" = foo/subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - ../foo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ../foo && + git submodule init && + test "$(git config submodule.sub.url)" = ../subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - ../foo/bar' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ../foo/bar && + git submodule init && + test "$(git config submodule.sub.url)" = ../foo/subrepo + ) +' + +test_expect_success '../bar/a/b/c works with relative local path - ../foo/bar.git' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + mkdir -p a/b/c && + (cd a/b/c; git init) && + git config remote.origin.url ../foo/bar.git && + git submodule add ../bar/a/b/c ./a/b/c && + git submodule init && + test "$(git config submodule.a/b/c.url)" = ../foo/bar/a/b/c + ) +' + test_expect_success 'moving the superproject does not break submodules' ' ( cd addtest && diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh index 3620215c1f..524d5c1b21 100755 --- a/t/t7403-submodule-sync.sh +++ b/t/t7403-submodule-sync.sh @@ -26,7 +26,9 @@ test_expect_success setup ' (cd super-clone && git submodule update --init) && git clone super empty-clone && (cd empty-clone && git submodule init) && - git clone super top-only-clone + git clone super top-only-clone && + git clone super relative-clone && + (cd relative-clone && git submodule update --init) ' test_expect_success 'change submodule' ' @@ -86,4 +88,90 @@ test_expect_success '"git submodule sync" should not vivify uninteresting submod ) ' +test_expect_success '"git submodule sync" handles origin URL of the form foo' ' + (cd relative-clone && + git remote set-url origin foo && + git submodule sync && + (cd submodule && + #actual fails with: "cannot strip off url foo + test "$(git config remote.origin.url)" = "../submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form foo/bar' ' + (cd relative-clone && + git remote set-url origin foo/bar && + git submodule sync && + (cd submodule && + #actual foo/submodule + test "$(git config remote.origin.url)" = "../foo/submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ./foo' ' + (cd relative-clone && + git remote set-url origin ./foo && + git submodule sync && + (cd submodule && + #actual ./submodule + test "$(git config remote.origin.url)" = "../submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ./foo/bar' ' + (cd relative-clone && + git remote set-url origin ./foo/bar && + git submodule sync && + (cd submodule && + #actual ./foo/submodule + test "$(git config remote.origin.url)" = "../foo/submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ../foo' ' + (cd relative-clone && + git remote set-url origin ../foo && + git submodule sync && + (cd submodule && + #actual ../submodule + test "$(git config remote.origin.url)" = "../../submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ../foo/bar' ' + (cd relative-clone && + git remote set-url origin ../foo/bar && + git submodule sync && + (cd submodule && + #actual ../foo/submodule + test "$(git config remote.origin.url)" = "../../foo/submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ../foo/bar with deeply nested submodule' ' + (cd relative-clone && + git remote set-url origin ../foo/bar && + mkdir -p a/b/c && + ( cd a/b/c && + git init && + :> .gitignore && + git add .gitignore && + test_tick && + git commit -m "initial commit" ) && + git submodule add ../bar/a/b/c ./a/b/c && + git submodule sync && + (cd a/b/c && + #actual ../foo/bar/a/b/c + test "$(git config remote.origin.url)" = "../../../../foo/bar/a/b/c" + ) + ) +' + + test_done diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-worktree.sh new file mode 100755 index 0000000000..2fec13dcd3 --- /dev/null +++ b/t/t7409-submodule-detached-worktree.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# +# Copyright (c) 2012 Daniel Graña +# + +test_description='Test submodules on detached working tree + +This test verifies that "git submodule" initialization, update and addition works +on detahced working trees +' + +TEST_NO_CREATE_REPO=1 +. ./test-lib.sh + +test_expect_success 'submodule on detached working tree' ' + git init --bare remote && + test_create_repo bundle1 && + ( + cd bundle1 && + test_commit "shoot" && + git rev-parse --verify HEAD >../expect + ) && + mkdir home && + ( + cd home && + export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" && + git clone --bare ../remote .dotfiles && + git submodule add ../bundle1 .vim/bundle/sogood && + test_commit "sogood" && + ( + unset GIT_WORK_TREE GIT_DIR && + cd .vim/bundle/sogood && + git rev-parse --verify HEAD >actual && + test_cmp ../../../../expect actual + ) && + git push origin master + ) && + mkdir home2 && + ( + cd home2 && + git clone --bare ../remote .dotfiles && + export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" && + git checkout master && + git submodule update --init && + ( + unset GIT_WORK_TREE GIT_DIR && + cd .vim/bundle/sogood && + git rev-parse --verify HEAD >actual && + test_cmp ../../../../expect actual + ) + ) +' + +test_expect_success 'submodule on detached working pointed by core.worktree' ' + mkdir home3 && + ( + cd home3 && + export GIT_DIR="$(pwd)/.dotfiles" && + git clone --bare ../remote "$GIT_DIR" && + git config core.bare false && + git config core.worktree .. && + git checkout master && + git submodule add ../bundle1 .vim/bundle/dupe && + test_commit "dupe" && + git push origin master + ) && + ( + cd home && + export GIT_DIR="$(pwd)/.dotfiles" && + git config core.bare false && + git config core.worktree .. && + git pull && + git submodule update --init && + test -f .vim/bundle/dupe/shoot.t + ) +' + +test_done diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index 181456aa9a..deb187eb7b 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -235,44 +235,56 @@ test_expect_success 'cleanup commit messages (strip,-F,-e): output' ' test_i18ncmp expect actual ' -echo "# -# Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> -#" >> expect - -test_expect_success 'author different from committer' ' +test_expect_success 'message shows author when it is not equal to committer' ' echo >>negative && - test_might_fail git commit -e -m "sample" && - head -n 7 .git/COMMIT_EDITMSG >actual && - test_i18ncmp expect actual + git commit -e -m "sample" -a && + test_i18ngrep \ + "^# Author: *A U Thor <author@example.com>\$" \ + .git/COMMIT_EDITMSG ' -mv expect expect.tmp -sed '$d' < expect.tmp > expect -rm -f expect.tmp -echo "# Committer: -#" >> expect +test_expect_success 'setup auto-ident prerequisite' ' + if (sane_unset GIT_COMMITTER_EMAIL && + sane_unset GIT_COMMITTER_NAME && + git var GIT_COMMITTER_IDENT); then + test_set_prereq AUTOIDENT + else + test_set_prereq NOAUTOIDENT + fi +' -test_expect_success 'committer is automatic' ' +test_expect_success AUTOIDENT 'message shows committer when it is automatic' ' echo >>negative && ( sane_unset GIT_COMMITTER_EMAIL && sane_unset GIT_COMMITTER_NAME && - # must fail because there is no change - test_must_fail git commit -e -m "sample" + git commit -e -m "sample" -a ) && - head -n 8 .git/COMMIT_EDITMSG | \ - sed "s/^# Committer: .*/# Committer:/" >actual - test_i18ncmp expect actual + # the ident is calculated from the system, so we cannot + # check the actual value, only that it is there + test_i18ngrep "^# Committer: " .git/COMMIT_EDITMSG ' -pwd=`pwd` -cat >> .git/FAKE_EDITOR << EOF -#! /bin/sh -echo editor started > "$pwd/.git/result" +write_script .git/FAKE_EDITOR <<EOF +echo editor started > "$(pwd)/.git/result" exit 0 EOF -chmod +x .git/FAKE_EDITOR + +test_expect_success NOAUTOIDENT 'do not fire editor when committer is bogus' ' + >.git/result + >expect && + + echo >>negative && + ( + sane_unset GIT_COMMITTER_EMAIL && + sane_unset GIT_COMMITTER_NAME && + GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" && + export GIT_EDITOR && + test_must_fail git commit -e -m sample -a + ) && + test_cmp expect .git/result +' test_expect_success 'do not fire editor in the presence of conflicts' ' @@ -293,16 +305,14 @@ test_expect_success 'do not fire editor in the presence of conflicts' ' test_must_fail git cherry-pick -n master && echo "editor not started" >.git/result && ( - GIT_EDITOR="$(pwd)/.git/FAKE_EDITOR" && + GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" && export GIT_EDITOR && test_must_fail git commit ) && test "$(cat .git/result)" = "editor not started" ' -pwd=`pwd` -cat >.git/FAKE_EDITOR <<EOF -#! $SHELL_PATH +write_script .git/FAKE_EDITOR <<EOF # kill -TERM command added below. EOF @@ -339,13 +349,12 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo ' -cat >.git/FAKE_EDITOR <<EOF -#!$SHELL_PATH -mv "\$1" "\$1.orig" +write_script .git/FAKE_EDITOR <<\EOF +mv "$1" "$1.orig" ( echo message - cat "\$1.orig" -) >"\$1" + cat "$1.orig" +) >"$1" EOF echo '## Custom template' >template diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh new file mode 100755 index 0000000000..b3f6eb9c68 --- /dev/null +++ b/t/t7512-status-help.sh @@ -0,0 +1,649 @@ +#!/bin/sh +# +# Copyright (c) 2012 Valentin Duperray, Lucien Kong, Franck Jonas, +# Thomas Nguy, Khoi Nguyen +# Grenoble INP Ensimag +# + +test_description='git status advices' + +. ./test-lib.sh + +. "$TEST_DIRECTORY"/lib-rebase.sh + +set_fake_editor + +test_expect_success 'prepare for conflicts' ' + test_commit init main.txt init && + git branch conflicts && + test_commit on_master main.txt on_master && + git checkout conflicts && + test_commit on_conflicts main.txt on_conflicts +' + + +test_expect_success 'status when conflicts unresolved' ' + test_must_fail git merge master && + cat >expected <<-\EOF && + # On branch conflicts + # You have unmerged paths. + # (fix conflicts and run "git commit") + # + # Unmerged paths: + # (use "git add <file>..." to mark resolution) + # + # both modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when conflicts resolved before commit' ' + git reset --hard conflicts && + test_must_fail git merge master && + echo one >main.txt && + git add main.txt && + cat >expected <<-\EOF && + # On branch conflicts + # All conflicts fixed but you are still merging. + # (use "git commit" to conclude merge) + # + # Changes to be committed: + # + # modified: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for rebase conflicts' ' + git reset --hard master && + git checkout -b rebase_conflicts && + test_commit one_rebase main.txt one && + test_commit two_rebase main.txt two && + test_commit three_rebase main.txt three +' + + +test_expect_success 'status when rebase in progress before resolving conflicts' ' + test_when_finished "git rebase --abort" && + test_must_fail git rebase HEAD^ --onto HEAD^^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # (fix conflicts and then run "git rebase --continue") + # (use "git rebase --skip" to skip this patch) + # (use "git rebase --abort" to check out the original branch) + # + # Unmerged paths: + # (use "git reset HEAD <file>..." to unstage) + # (use "git add <file>..." to mark resolution) + # + # both modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when rebase in progress before rebase --continue' ' + git reset --hard rebase_conflicts && + test_when_finished "git rebase --abort" && + test_must_fail git rebase HEAD^ --onto HEAD^^ && + echo three >main.txt && + git add main.txt && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # (all conflicts fixed: run "git rebase --continue") + # + # Changes to be committed: + # (use "git reset HEAD <file>..." to unstage) + # + # modified: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for rebase_i_conflicts' ' + git reset --hard master && + git checkout -b rebase_i_conflicts && + test_commit one_unmerge main.txt one_unmerge && + git branch rebase_i_conflicts_second && + test_commit one_master main.txt one_master && + git checkout rebase_i_conflicts_second && + test_commit one_second main.txt one_second +' + + +test_expect_success 'status during rebase -i when conflicts unresolved' ' + test_when_finished "git rebase --abort" && + test_must_fail git rebase -i rebase_i_conflicts && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # (fix conflicts and then run "git rebase --continue") + # (use "git rebase --skip" to skip this patch) + # (use "git rebase --abort" to check out the original branch) + # + # Unmerged paths: + # (use "git reset HEAD <file>..." to unstage) + # (use "git add <file>..." to mark resolution) + # + # both modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status during rebase -i after resolving conflicts' ' + git reset --hard rebase_i_conflicts_second && + test_when_finished "git rebase --abort" && + test_must_fail git rebase -i rebase_i_conflicts && + git add main.txt && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # (all conflicts fixed: run "git rebase --continue") + # + # Changes to be committed: + # (use "git reset HEAD <file>..." to unstage) + # + # modified: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when rebasing -i in edit mode' ' + git reset --hard master && + git checkout -b rebase_i_edit && + test_commit one_rebase_i main.txt one && + test_commit two_rebase_i main.txt two && + test_commit three_rebase_i main.txt three && + FAKE_LINES="1 edit 2" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~2 && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when splitting a commit' ' + git reset --hard master && + git checkout -b split_commit && + test_commit one_split main.txt one && + test_commit two_split main.txt two && + test_commit three_split main.txt three && + test_commit four_split main.txt four && + FAKE_LINES="1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git reset HEAD^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently splitting a commit during a rebase. + # (Once your working directory is clean, run "git rebase --continue") + # + # Changes not staged for commit: + # (use "git add <file>..." to update what will be committed) + # (use "git checkout -- <file>..." to discard changes in working directory) + # + # modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status after editing the last commit with --amend during a rebase -i' ' + git reset --hard master && + git checkout -b amend_last && + test_commit one_amend main.txt one && + test_commit two_amend main.txt two && + test_commit three_amend main.txt three && + test_commit four_amend main.txt four && + FAKE_LINES="1 2 edit 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git commit --amend -m "foo" && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for several edits' ' + git reset --hard master && + git checkout -b several_edits && + test_commit one_edits main.txt one && + test_commit two_edits main.txt two && + test_commit three_edits main.txt three && + test_commit four_edits main.txt four +' + + +test_expect_success 'status: (continue first edit) second edit' ' + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git rebase --continue && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (continue first edit) second edit and split' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git rebase --continue && + git reset HEAD^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently splitting a commit during a rebase. + # (Once your working directory is clean, run "git rebase --continue") + # + # Changes not staged for commit: + # (use "git add <file>..." to update what will be committed) + # (use "git checkout -- <file>..." to discard changes in working directory) + # + # modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (continue first edit) second edit and amend' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git rebase --continue && + git commit --amend -m "foo" && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (amend first edit) second edit' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git commit --amend -m "a" && + git rebase --continue && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (amend first edit) second edit and split' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git commit --amend -m "b" && + git rebase --continue && + git reset HEAD^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently splitting a commit during a rebase. + # (Once your working directory is clean, run "git rebase --continue") + # + # Changes not staged for commit: + # (use "git add <file>..." to update what will be committed) + # (use "git checkout -- <file>..." to discard changes in working directory) + # + # modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (amend first edit) second edit and amend' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git commit --amend -m "c" && + git rebase --continue && + git commit --amend -m "d" && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (split first edit) second edit' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git reset HEAD^ && + git add main.txt && + git commit -m "e" && + git rebase --continue && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (split first edit) second edit and split' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git reset HEAD^ && + git add main.txt && + git commit --amend -m "f" && + git rebase --continue && + git reset HEAD^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently splitting a commit during a rebase. + # (Once your working directory is clean, run "git rebase --continue") + # + # Changes not staged for commit: + # (use "git add <file>..." to update what will be committed) + # (use "git checkout -- <file>..." to discard changes in working directory) + # + # modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (split first edit) second edit and amend' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git reset HEAD^ && + git add main.txt && + git commit --amend -m "g" && + git rebase --continue && + git commit --amend -m "h" && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare am_session' ' + git reset --hard master && + git checkout -b am_session && + test_commit one_am one.txt "one" && + test_commit two_am two.txt "two" && + test_commit three_am three.txt "three" +' + + +test_expect_success 'status in an am session: file already exists' ' + git checkout -b am_already_exists && + test_when_finished "rm Maildir/* && git am --abort" && + git format-patch -1 -oMaildir && + test_must_fail git am Maildir/*.patch && + cat >expected <<-\EOF && + # On branch am_already_exists + # You are in the middle of an am session. + # (fix conflicts and then run "git am --resolved") + # (use "git am --skip" to skip this patch) + # (use "git am --abort" to restore the original branch) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status in an am session: file does not exist' ' + git reset --hard am_session && + git checkout -b am_not_exists && + git rm three.txt && + git commit -m "delete three.txt" && + test_when_finished "rm Maildir/* && git am --abort" && + git format-patch -1 -oMaildir && + test_must_fail git am Maildir/*.patch && + cat >expected <<-\EOF && + # On branch am_not_exists + # You are in the middle of an am session. + # (fix conflicts and then run "git am --resolved") + # (use "git am --skip" to skip this patch) + # (use "git am --abort" to restore the original branch) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status in an am session: empty patch' ' + git reset --hard am_session && + git checkout -b am_empty && + test_when_finished "rm Maildir/* && git am --abort" && + git format-patch -3 -oMaildir && + git rm one.txt two.txt three.txt && + git commit -m "delete all am_empty" && + echo error >Maildir/0002-two_am.patch && + test_must_fail git am Maildir/*.patch && + cat >expected <<-\EOF && + # On branch am_empty + # You are in the middle of an am session. + # The current patch is empty. + # (use "git am --skip" to skip this patch) + # (use "git am --abort" to restore the original branch) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when bisecting' ' + git reset --hard master && + git checkout -b bisect && + test_commit one_bisect main.txt one && + test_commit two_bisect main.txt two && + test_commit three_bisect main.txt three && + test_when_finished "git bisect reset" && + git bisect start && + git bisect bad && + git bisect good one_bisect && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently bisecting. + # (use "git bisect reset" to get back to the original branch) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when rebase conflicts with statushints disabled' ' + git reset --hard master && + git checkout -b statushints_disabled && + test_when_finished "git config --local advice.statushints true" && + git config --local advice.statushints false && + test_commit one_statushints main.txt one && + test_commit two_statushints main.txt two && + test_commit three_statushints main.txt three && + test_when_finished "git rebase --abort" && + test_must_fail git rebase HEAD^ --onto HEAD^^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # + # Unmerged paths: + # both modified: main.txt + # + no changes added to commit + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for cherry-pick conflicts' ' + git reset --hard master && + git checkout -b cherry_branch && + test_commit one_cherry main.txt one && + test_commit two_cherries main.txt two && + git checkout -b cherry_branch_second && + test_commit second_cherry main.txt second && + git checkout cherry_branch && + test_commit three_cherries main.txt three +' + + +test_expect_success 'status when cherry-picking before resolving conflicts' ' + test_when_finished "git cherry-pick --abort" && + test_must_fail git cherry-pick cherry_branch_second && + cat >expected <<-\EOF && + # On branch cherry_branch + # You are currently cherry-picking. + # (fix conflicts and run "git commit") + # + # Unmerged paths: + # (use "git add <file>..." to mark resolution) + # + # both modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when cherry-picking after resolving conflicts' ' + git reset --hard cherry_branch && + test_when_finished "git cherry-pick --abort" && + test_must_fail git cherry-pick cherry_branch_second && + echo end >main.txt && + git add main.txt && + cat >expected <<-\EOF && + # On branch cherry_branch + # You are currently cherry-picking. + # (all conflicts fixed: run "git commit") + # + # Changes to be committed: + # + # modified: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_done diff --git a/t/t9163-git-svn-reset-clears-caches.sh b/t/t9163-git-svn-reset-clears-caches.sh new file mode 100755 index 0000000000..cd4c662ba2 --- /dev/null +++ b/t/t9163-git-svn-reset-clears-caches.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# +# Copyright (c) 2012 Peter Baumann +# + +test_description='git svn reset clears memoized caches' +. ./lib-git-svn.sh + +svn_ver="$(svn --version --quiet)" +case $svn_ver in +0.* | 1.[0-4].*) + skip_all="skipping git-svn test - SVN too old ($svn_ver)" + test_done + ;; +esac + +# ... a - b - m <- trunk +# \ / +# ... c <- branch1 +# +# SVN Commits not interesting for this test are abbreviated with "..." +# +test_expect_success 'initialize source svn repo' ' + svn_cmd mkdir -m "create trunk" "$svnrepo"/trunk && + svn_cmd mkdir -m "create branches" "$svnrepo/branches" && + svn_cmd co "$svnrepo"/trunk "$SVN_TREE" && + ( + cd "$SVN_TREE" && + touch foo && + svn_cmd add foo && + svn_cmd commit -m "a" && + svn_cmd cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 && + svn_cmd switch "$svnrepo"/branches/branch1 && + touch bar && + svn_cmd add bar && + svn_cmd commit -m b && + svn_cmd switch "$svnrepo"/trunk && + touch baz && + svn_cmd add baz && + svn_cmd commit -m c && + svn_cmd up && + svn_cmd merge "$svnrepo"/branches/branch1 && + svn_cmd commit -m "m" + ) && + rm -rf "$SVN_TREE" +' + +test_expect_success 'fetch to merge-base (a)' ' + git svn init -s "$svnrepo" && + git svn fetch --revision BASE:3 +' + +# git svn rebase looses the merge commit +# +# ... a - b - m <- trunk +# \ +# ... c +# +test_expect_success 'rebase looses SVN merge (m)' ' + git svn rebase && + git svn fetch && + test 1 = $(git cat-file -p master|grep parent|wc -l) +' + +# git svn fetch creates correct history with merge commit +# +# ... a - b - m <- trunk +# \ / +# ... c <- branch1 +# +test_expect_success 'reset and fetch gets the SVN merge (m) correctly' ' + git svn reset -r 3 && + git reset --hard trunk && + git svn fetch && + test 2 = $(git cat-file -p trunk|grep parent|wc -l) +' + +test_done diff --git a/t/t9164-git-svn-dcommit-concrrent.sh b/t/t9164-git-svn-dcommit-concrrent.sh new file mode 100755 index 0000000000..aac2ddadf2 --- /dev/null +++ b/t/t9164-git-svn-dcommit-concrrent.sh @@ -0,0 +1,216 @@ +#!/bin/sh +# +# Copyright (c) 2012 Robert Luberda +# + +test_description='concurrent git svn dcommit' +. ./lib-git-svn.sh + + + +test_expect_success 'setup svn repository' ' + svn_cmd checkout "$svnrepo" work.svn && + ( + cd work.svn && + echo >file && echo > auto_updated_file + svn_cmd add file auto_updated_file && + svn_cmd commit -m "initial commit" + ) && + svn_cmd checkout "$svnrepo" work-auto-commits.svn +' +N=0 +next_N() +{ + N=$(( $N + 1 )) +} + +# Setup SVN repository hooks to emulate SVN failures or concurrent commits +# The function adds +# either pre-commit hook, which causes SVN commit given in second argument +# to fail +# or post-commit hook, which creates a new commit (a new line added to +# auto_updated_file) after given SVN commit +# The first argument contains a type of the hook +# The second argument contains a number (not SVN revision) of commit +# the hook should be applied for (each time the hook is run, the given +# number is decreased by one until it gets 0, in which case the hook +# will execute its real action) +setup_hook() +{ + hook_type="$1" # "pre-commit" or "post-commit" + skip_revs="$2" + [ "$hook_type" = "pre-commit" ] || + [ "$hook_type" = "post-commit" ] || + { echo "ERROR: invalid argument ($hook_type)" \ + "passed to setup_hook" >&2 ; return 1; } + echo "cnt=$skip_revs" > "$hook_type-counter" + rm -f "$rawsvnrepo/hooks/"*-commit # drop previous hooks + hook="$rawsvnrepo/hooks/$hook_type" + cat > "$hook" <<- 'EOF1' + #!/bin/sh + set -e + cd "$1/.." # "$1" is repository location + exec >> svn-hook.log 2>&1 + hook="$(basename "$0")" + echo "*** Executing $hook $@" + set -x + . ./$hook-counter + cnt="$(($cnt - 1))" + echo "cnt=$cnt" > ./$hook-counter + [ "$cnt" = "0" ] || exit 0 +EOF1 + if [ "$hook_type" = "pre-commit" ]; then + echo "echo 'commit disallowed' >&2; exit 1" >> "$hook" + else + echo "PATH=\"$PATH\"; export PATH" >> $hook + echo "svnconf=\"$svnconf\"" >> $hook + cat >> "$hook" <<- 'EOF2' + cd work-auto-commits.svn + svn up --config-dir "$svnconf" + echo "$$" >> auto_updated_file + svn commit --config-dir "$svnconf" \ + -m "auto-committing concurrent change" + exit 0 +EOF2 + fi + chmod 755 "$hook" +} + +check_contents() +{ + gitdir="$1" + (cd ../work.svn && svn_cmd up) && + test_cmp file ../work.svn/file && + test_cmp auto_updated_file ../work.svn/auto_updated_file +} + +test_expect_success 'check if post-commit hook creates a concurrent commit' ' + setup_hook post-commit 1 && + ( + cd work.svn && + cp auto_updated_file au_file_saved && + echo 1 >> file && + svn_cmd commit -m "changing file" && + svn_cmd up && + test_must_fail test_cmp auto_updated_file au_file_saved + ) +' + +test_expect_success 'check if pre-commit hook fails' ' + setup_hook pre-commit 2 && + ( + cd work.svn && + echo 2 >> file && + svn_cmd commit -m "changing file once again" && + echo 3 >> file && + test_must_fail svn_cmd commit -m "this commit should fail" && + svn_cmd revert file + ) +' + +test_expect_success 'dcommit error handling' ' + setup_hook pre-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + echo 1 >> file && git commit -am "commit change $N.1" && + echo 2 >> file && git commit -am "commit change $N.2" && + echo 3 >> file && git commit -am "commit change $N.3" && + # should fail to dcommit 2nd and 3rd change + # but still should leave the repository in reasonable state + test_must_fail git svn dcommit && + git update-index --refresh && + git show HEAD~2 | grep -q git-svn-id && + ! git show HEAD~1 | grep -q git-svn-id && + ! git show HEAD | grep -q git-svn-id + ) +' + +test_expect_success 'dcommit concurrent change in non-changed file' ' + setup_hook post-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + echo 1 >> file && git commit -am "commit change $N.1" && + echo 2 >> file && git commit -am "commit change $N.2" && + echo 3 >> file && git commit -am "commit change $N.3" && + # should rebase and leave the repository in reasonable state + git svn dcommit && + git update-index --refresh && + check_contents && + git show HEAD~3 | grep -q git-svn-id && + git show HEAD~2 | grep -q git-svn-id && + git show HEAD~1 | grep -q auto-committing && + git show HEAD | grep -q git-svn-id + ) +' + +# An utility function used in the following test +delete_first_line() +{ + file="$1" && + sed 1d < "$file" > "${file}.tmp" && + rm "$file" && + mv "${file}.tmp" "$file" +} + +test_expect_success 'dcommit concurrent non-conflicting change' ' + setup_hook post-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + cat file >> auto_updated_file && + git commit -am "commit change $N.1" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.2" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.3" && + # should rebase and leave the repository in reasonable state + git svn dcommit && + git update-index --refresh && + check_contents && + git show HEAD~3 | grep -q git-svn-id && + git show HEAD~2 | grep -q git-svn-id && + git show HEAD~1 | grep -q auto-committing && + git show HEAD | grep -q git-svn-id + ) +' + +test_expect_success 'dcommit --no-rebase concurrent non-conflicting change' ' + setup_hook post-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + cat file >> auto_updated_file && + git commit -am "commit change $N.1" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.2" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.3" && + # should fail as rebase is needed + test_must_fail git svn dcommit --no-rebase && + # but should leave HEAD unchanged + git update-index --refresh && + ! git show HEAD~2 | grep -q git-svn-id && + ! git show HEAD~1 | grep -q git-svn-id && + ! git show HEAD | grep -q git-svn-id + ) +' + +test_expect_success 'dcommit fails on concurrent conflicting change' ' + setup_hook post-commit 1 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + echo a >> file && + git commit -am "commit change $N.1" && + echo b >> auto_updated_file && + git commit -am "commit change $N.2" && + echo c >> auto_updated_file && + git commit -am "commit change $N.3" && + test_must_fail git svn dcommit && # rebase should fail + test_must_fail git update-index --refresh + ) +' + +test_done diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh index 0f410c45f7..b7ad716b09 100755 --- a/t/t9800-git-p4-basic.sh +++ b/t/t9800-git-p4-basic.sh @@ -45,7 +45,8 @@ test_expect_success 'git p4 sync uninitialized repo' ' test_when_finished cleanup_git && ( cd "$git" && - test_must_fail git p4 sync + test_must_fail git p4 sync 2>errs && + test_i18ngrep "Perhaps you never did" errs ) ' @@ -126,150 +127,24 @@ test_expect_success 'clone two dirs, @all, conflicting files' ' ' test_expect_success 'exit when p4 fails to produce marshaled output' ' - badp4dir="$TRASH_DIRECTORY/badp4dir" && - mkdir "$badp4dir" && - test_when_finished "rm \"$badp4dir/p4\" && rmdir \"$badp4dir\"" && - cat >"$badp4dir"/p4 <<-EOF && + mkdir badp4dir && + test_when_finished "rm badp4dir/p4 && rmdir badp4dir" && + cat >badp4dir/p4 <<-EOF && #!$SHELL_PATH exit 1 EOF - chmod 755 "$badp4dir"/p4 && - PATH="$badp4dir:$PATH" git p4 clone --dest="$git" //depot >errs 2>&1 ; retval=$? && - test $retval -eq 1 && - test_must_fail grep -q Traceback errs -' - -test_expect_success 'add p4 files with wildcards in the names' ' - ( - cd "$cli" && - echo file-wild-hash >file-wild#hash && - echo file-wild-star >file-wild\*star && - echo file-wild-at >file-wild@at && - echo file-wild-percent >file-wild%percent && - p4 add -f file-wild* && - p4 submit -d "file wildcards" - ) -' - -test_expect_success 'wildcard files git p4 clone' ' - git p4 clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - test -f file-wild#hash && - test -f file-wild\*star && - test -f file-wild@at && - test -f file-wild%percent - ) -' - -test_expect_success 'wildcard files submit back to p4, add' ' - test_when_finished cleanup_git && - git p4 clone --dest="$git" //depot && - ( - cd "$git" && - echo git-wild-hash >git-wild#hash && - echo git-wild-star >git-wild\*star && - echo git-wild-at >git-wild@at && - echo git-wild-percent >git-wild%percent && - git add git-wild* && - git commit -m "add some wildcard filenames" && - git config git-p4.skipSubmitEdit true && - git p4 submit - ) && - ( - cd "$cli" && - test_path_is_file git-wild#hash && - test_path_is_file git-wild\*star && - test_path_is_file git-wild@at && - test_path_is_file git-wild%percent - ) -' - -test_expect_success 'wildcard files submit back to p4, modify' ' - test_when_finished cleanup_git && - git p4 clone --dest="$git" //depot && - ( - cd "$git" && - echo new-line >>git-wild#hash && - echo new-line >>git-wild\*star && - echo new-line >>git-wild@at && - echo new-line >>git-wild%percent && - git add git-wild* && - git commit -m "modify the wildcard files" && - git config git-p4.skipSubmitEdit true && - git p4 submit - ) && - ( - cd "$cli" && - test_line_count = 2 git-wild#hash && - test_line_count = 2 git-wild\*star && - test_line_count = 2 git-wild@at && - test_line_count = 2 git-wild%percent - ) -' - -test_expect_success 'wildcard files submit back to p4, copy' ' - test_when_finished cleanup_git && - git p4 clone --dest="$git" //depot && + chmod 755 badp4dir/p4 && ( - cd "$git" && - cp file2 git-wild-cp#hash && - git add git-wild-cp#hash && - cp git-wild\*star file-wild-3 && - git add file-wild-3 && - git commit -m "wildcard copies" && - git config git-p4.detectCopies true && - git config git-p4.detectCopiesHarder true && - git config git-p4.skipSubmitEdit true && - git p4 submit + PATH="$TRASH_DIRECTORY/badp4dir:$PATH" && + export PATH && + test_expect_code 1 git p4 clone --dest="$git" //depot >errs 2>&1 ) && - ( - cd "$cli" && - test_path_is_file git-wild-cp#hash && - test_path_is_file file-wild-3 - ) -' - -test_expect_success 'wildcard files submit back to p4, rename' ' - test_when_finished cleanup_git && - git p4 clone --dest="$git" //depot && - ( - cd "$git" && - git mv git-wild@at file-wild-4 && - git mv file-wild-3 git-wild-cp%percent && - git commit -m "wildcard renames" && - git config git-p4.detectRenames true && - git config git-p4.skipSubmitEdit true && - git p4 submit - ) && - ( - cd "$cli" && - test_path_is_missing git-wild@at && - test_path_is_file git-wild-cp%percent - ) -' - -test_expect_success 'wildcard files submit back to p4, delete' ' - test_when_finished cleanup_git && - git p4 clone --dest="$git" //depot && - ( - cd "$git" && - git rm git-wild* && - git commit -m "delete the wildcard files" && - git config git-p4.skipSubmitEdit true && - git p4 submit - ) && - ( - cd "$cli" && - test_path_is_missing git-wild#hash && - test_path_is_missing git-wild\*star && - test_path_is_missing git-wild@at && - test_path_is_missing git-wild%percent - ) + cat errs && + ! test_i18ngrep Traceback errs ' test_expect_success 'clone bare' ' + rm -rf "$git" && git p4 clone --dest="$git" --bare //depot && test_when_finished cleanup_git && ( @@ -280,138 +155,6 @@ test_expect_success 'clone bare' ' ) ' -p4_add_user() { - name=$1 fullname=$2 && - p4 user -f -i <<-EOF && - User: $name - Email: $name@localhost - FullName: $fullname - EOF - p4 passwd -P secret $name -} - -p4_grant_admin() { - name=$1 && - { - p4 protect -o && - echo " admin user $name * //depot/..." - } | p4 protect -i -} - -p4_check_commit_author() { - file=$1 user=$2 && - p4 changes -m 1 //depot/$file | grep -q $user -} - -make_change_by_user() { - file=$1 name=$2 email=$3 && - echo "username: a change by $name" >>"$file" && - git add "$file" && - git commit --author "$name <$email>" -m "a change by $name" -} - -# Test username support, submitting as user 'alice' -test_expect_success 'preserve users' ' - p4_add_user alice Alice && - p4_add_user bob Bob && - p4_grant_admin alice && - git p4 clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - echo "username: a change by alice" >>file1 && - echo "username: a change by bob" >>file2 && - git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 && - git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 && - git config git-p4.skipSubmitEditCheck true && - P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user && - p4_check_commit_author file1 alice && - p4_check_commit_author file2 bob - ) -' - -# Test username support, submitting as bob, who lacks admin rights. Should -# not submit change to p4 (git diff should show deltas). -test_expect_success 'refuse to preserve users without perms' ' - git p4 clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEditCheck true && - echo "username-noperms: a change by alice" >>file1 && - git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 && - P4EDITOR=touch P4USER=bob P4PASSWD=secret && - export P4EDITOR P4USER P4PASSWD && - test_must_fail git p4 commit --preserve-user && - ! git diff --exit-code HEAD..p4/master - ) -' - -# What happens with unknown author? Without allowMissingP4Users it should fail. -test_expect_success 'preserve user where author is unknown to p4' ' - git p4 clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEditCheck true && - echo "username-bob: a change by bob" >>file1 && - git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 && - echo "username-unknown: a change by charlie" >>file1 && - git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 && - P4EDITOR=touch P4USER=alice P4PASSWD=secret && - export P4EDITOR P4USER P4PASSWD && - test_must_fail git p4 commit --preserve-user && - ! git diff --exit-code HEAD..p4/master && - - echo "$0: repeat with allowMissingP4Users enabled" && - git config git-p4.allowMissingP4Users true && - git config git-p4.preserveUser true && - git p4 commit && - git diff --exit-code HEAD..p4/master && - p4_check_commit_author file1 alice - ) -' - -# If we're *not* using --preserve-user, git p4 should warn if we're submitting -# changes that are not all ours. -# Test: user in p4 and user unknown to p4. -# Test: warning disabled and user is the same. -test_expect_success 'not preserving user with mixed authorship' ' - git p4 clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEditCheck true && - p4_add_user derek Derek && - - make_change_by_user usernamefile3 Derek derek@localhost && - P4EDITOR=cat P4USER=alice P4PASSWD=secret && - export P4EDITOR P4USER P4PASSWD && - git p4 commit |\ - grep "git author derek@localhost does not match" && - - make_change_by_user usernamefile3 Charlie charlie@localhost && - git p4 commit |\ - grep "git author charlie@localhost does not match" && - - make_change_by_user usernamefile3 alice alice@localhost && - git p4 commit |\ - test_must_fail grep "git author.*does not match" && - - git config git-p4.skipUserNameCheck true && - make_change_by_user usernamefile3 Charlie charlie@localhost && - git p4 commit |\ - test_must_fail grep "git author.*does not match" && - - p4_check_commit_author usernamefile3 alice - ) -' - -marshal_dump() { - what=$1 - "$PYTHON_PATH" -c 'import marshal, sys; d = marshal.load(sys.stdin); print d["'$what'"]' -} - # Sleep a bit so that the top-most p4 change did not happen "now". Then # import the repo and make sure that the initial import has the same time # as the top-most change. @@ -429,146 +172,6 @@ test_expect_success 'initial import time from top change time' ' ) ' -# Rename a file and confirm that rename is not detected in P4. -# Rename the new file again with detectRenames option enabled and confirm that -# this is detected in P4. -# Rename the new file again adding an extra line, configure a big threshold in -# detectRenames and confirm that rename is not detected in P4. -# Repeat, this time with a smaller threshold and confirm that the rename is -# detected in P4. -test_expect_success 'detect renames' ' - git p4 clone --dest="$git" //depot@all && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEdit true && - - git mv file1 file4 && - git commit -a -m "Rename file1 to file4" && - git diff-tree -r -M HEAD && - git p4 submit && - p4 filelog //depot/file4 && - p4 filelog //depot/file4 | test_must_fail grep -q "branch from" && - - git mv file4 file5 && - git commit -a -m "Rename file4 to file5" && - git diff-tree -r -M HEAD && - git config git-p4.detectRenames true && - git p4 submit && - p4 filelog //depot/file5 && - p4 filelog //depot/file5 | grep -q "branch from //depot/file4" && - - git mv file5 file6 && - echo update >>file6 && - git add file6 && - git commit -a -m "Rename file5 to file6 with changes" && - git diff-tree -r -M HEAD && - level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && - test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && - git config git-p4.detectRenames $(($level + 2)) && - git p4 submit && - p4 filelog //depot/file6 && - p4 filelog //depot/file6 | test_must_fail grep -q "branch from" && - - git mv file6 file7 && - echo update >>file7 && - git add file7 && - git commit -a -m "Rename file6 to file7 with changes" && - git diff-tree -r -M HEAD && - level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && - test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && - git config git-p4.detectRenames $(($level - 2)) && - git p4 submit && - p4 filelog //depot/file7 && - p4 filelog //depot/file7 | grep -q "branch from //depot/file6" - ) -' - -# Copy a file and confirm that copy is not detected in P4. -# Copy a file with detectCopies option enabled and confirm that copy is not -# detected in P4. -# Modify and copy a file with detectCopies option enabled and confirm that copy -# is detected in P4. -# Copy a file with detectCopies and detectCopiesHarder options enabled and -# confirm that copy is detected in P4. -# Modify and copy a file, configure a bigger threshold in detectCopies and -# confirm that copy is not detected in P4. -# Modify and copy a file, configure a smaller threshold in detectCopies and -# confirm that copy is detected in P4. -test_expect_success 'detect copies' ' - git p4 clone --dest="$git" //depot@all && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEdit true && - - cp file2 file8 && - git add file8 && - git commit -a -m "Copy file2 to file8" && - git diff-tree -r -C HEAD && - git p4 submit && - p4 filelog //depot/file8 && - p4 filelog //depot/file8 | test_must_fail grep -q "branch from" && - - cp file2 file9 && - git add file9 && - git commit -a -m "Copy file2 to file9" && - git diff-tree -r -C HEAD && - git config git-p4.detectCopies true && - git p4 submit && - p4 filelog //depot/file9 && - p4 filelog //depot/file9 | test_must_fail grep -q "branch from" && - - echo "file2" >>file2 && - cp file2 file10 && - git add file2 file10 && - git commit -a -m "Modify and copy file2 to file10" && - git diff-tree -r -C HEAD && - git p4 submit && - p4 filelog //depot/file10 && - p4 filelog //depot/file10 | grep -q "branch from //depot/file" && - - cp file2 file11 && - git add file11 && - git commit -a -m "Copy file2 to file11" && - git diff-tree -r -C --find-copies-harder HEAD && - src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 && - git config git-p4.detectCopiesHarder true && - git p4 submit && - p4 filelog //depot/file11 && - p4 filelog //depot/file11 | grep -q "branch from //depot/file" && - - cp file2 file12 && - echo "some text" >>file12 && - git add file12 && - git commit -a -m "Copy file2 to file12 with changes" && - git diff-tree -r -C --find-copies-harder HEAD && - level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && - test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && - src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 && - git config git-p4.detectCopies $(($level + 2)) && - git p4 submit && - p4 filelog //depot/file12 && - p4 filelog //depot/file12 | test_must_fail grep -q "branch from" && - - cp file2 file13 && - echo "different text" >>file13 && - git add file13 && - git commit -a -m "Copy file2 to file13 with changes" && - git diff-tree -r -C --find-copies-harder HEAD && - level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && - test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && - src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 && - git config git-p4.detectCopies $(($level - 2)) && - git p4 submit && - p4 filelog //depot/file13 && - p4 filelog //depot/file13 | grep -q "branch from //depot/file" - ) -' - test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9805-git-p4-skip-submit-edit.sh b/t/t9805-git-p4-skip-submit-edit.sh index 353dcfbe09..fb3c8ec12c 100755 --- a/t/t9805-git-p4-skip-submit-edit.sh +++ b/t/t9805-git-p4-skip-submit-edit.sh @@ -78,20 +78,19 @@ test_expect_success 'skipSubmitEditCheck' ' test_expect_success 'no config, edited' ' git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && - ed="$TRASH_DIRECTORY/ed.sh" && - test_when_finished "rm \"$ed\"" && - cat >"$ed" <<-EOF && + test_when_finished "rm ed.sh" && + cat >ed.sh <<-EOF && #!$SHELL_PATH sleep 1 touch "\$1" exit 0 EOF - chmod 755 "$ed" && + chmod 755 ed.sh && ( cd "$git" && echo line >>file1 && git commit -a -m "change 5" && - P4EDITOR="" EDITOR="\"$ed\"" git p4 submit && + P4EDITOR="" EDITOR="\"$TRASH_DIRECTORY/ed.sh\"" git p4 submit && p4 changes //depot/... >wc && test_line_count = 5 wc ) diff --git a/t/t9806-git-p4-options.sh b/t/t9806-git-p4-options.sh index 2892367830..fa40cc8bb5 100755 --- a/t/t9806-git-p4-options.sh +++ b/t/t9806-git-p4-options.sh @@ -39,10 +39,9 @@ test_expect_success 'clone --branch' ' ' test_expect_success 'clone --changesfile' ' - cf="$TRASH_DIRECTORY/cf" && - test_when_finished "rm \"$cf\"" && - printf "1\n3\n" >"$cf" && - git p4 clone --changesfile="$cf" --dest="$git" //depot && + test_when_finished "rm cf" && + printf "1\n3\n" >cf && + git p4 clone --changesfile="$TRASH_DIRECTORY/cf" --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && @@ -55,10 +54,9 @@ test_expect_success 'clone --changesfile' ' ' test_expect_success 'clone --changesfile, @all' ' - cf="$TRASH_DIRECTORY/cf" && - test_when_finished "rm \"$cf\"" && - printf "1\n3\n" >"$cf" && - test_must_fail git p4 clone --changesfile="$cf" --dest="$git" //depot@all + test_when_finished "rm cf" && + printf "1\n3\n" >cf && + test_must_fail git p4 clone --changesfile="$TRASH_DIRECTORY/cf" --dest="$git" //depot@all ' # imports both master and p4/master in refs/heads @@ -128,7 +126,7 @@ test_expect_success 'clone --use-client-spec' ' exec >/dev/null && test_must_fail git p4 clone --dest="$git" --use-client-spec ) && - cli2="$TRASH_DIRECTORY/cli2" && + cli2=$(test-path-utils real_path "$TRASH_DIRECTORY/cli2") && mkdir -p "$cli2" && test_when_finished "rmdir \"$cli2\"" && ( @@ -151,7 +149,6 @@ test_expect_success 'clone --use-client-spec' ' cleanup_git && # same thing again, this time with variable instead of option - mkdir "$git" && ( cd "$git" && git init && diff --git a/t/t9807-git-p4-submit.sh b/t/t9807-git-p4-submit.sh index f23b4c3620..9394fd4e9b 100755 --- a/t/t9807-git-p4-submit.sh +++ b/t/t9807-git-p4-submit.sh @@ -182,6 +182,161 @@ test_expect_success 'submit rename' ' ) ' +# +# Converting git commit message to p4 change description, including +# parsing out the optional Jobs: line. +# +test_expect_success 'simple one-line description' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc2 >desc2 && + git add desc2 && + cat >msg <<-EOF && + One-line description line for desc2. + EOF + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + git p4 submit && + change=$(p4 -G changes -m 1 //depot/... | \ + marshal_dump change) && + # marshal_dump always adds a newline + p4 -G describe $change | marshal_dump desc | sed \$d >pmsg && + test_cmp msg pmsg + ) +' + +test_expect_success 'description with odd formatting' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc3 >desc3 && + git add desc3 && + ( + printf "subject line\n\n\tExtra tab\nline.\n\n" && + printf "Description:\n\tBogus description marker\n\n" && + # git commit eats trailing newlines; only use one + printf "Files:\n\tBogus descs marker\n" + ) >msg && + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + git p4 submit && + change=$(p4 -G changes -m 1 //depot/... | \ + marshal_dump change) && + # marshal_dump always adds a newline + p4 -G describe $change | marshal_dump desc | sed \$d >pmsg && + test_cmp msg pmsg + ) +' + +make_job() { + name="$1" && + tab="$(printf \\t)" && + p4 job -o | \ + sed -e "/^Job:/s/.*/Job: $name/" \ + -e "/^Description/{ n; s/.*/$tab job text/; }" | \ + p4 job -i +} + +test_expect_success 'description with Jobs section at end' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc4 >desc4 && + git add desc4 && + echo 6060842 >jobname && + ( + printf "subject line\n\n\tExtra tab\nline.\n\n" && + printf "Files:\n\tBogus files marker\n" && + printf "Junk: 3164175\n" && + printf "Jobs: $(cat jobname)\n" + ) >msg && + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + # build a job + make_job $(cat jobname) && + git p4 submit && + change=$(p4 -G changes -m 1 //depot/... | \ + marshal_dump change) && + # marshal_dump always adds a newline + p4 -G describe $change | marshal_dump desc | sed \$d >pmsg && + # make sure Jobs line and all following is gone + sed "/^Jobs:/,\$d" msg >jmsg && + test_cmp jmsg pmsg && + # make sure p4 knows about job + p4 -G describe $change | marshal_dump job0 >job0 && + test_cmp jobname job0 + ) +' + +test_expect_success 'description with Jobs and values on separate lines' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc5 >desc5 && + git add desc5 && + echo PROJ-6060842 >jobname1 && + echo PROJ-6060847 >jobname2 && + ( + printf "subject line\n\n\tExtra tab\nline.\n\n" && + printf "Files:\n\tBogus files marker\n" && + printf "Junk: 3164175\n" && + printf "Jobs:\n" && + printf "\t$(cat jobname1)\n" && + printf "\t$(cat jobname2)\n" + ) >msg && + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + # build two jobs + make_job $(cat jobname1) && + make_job $(cat jobname2) && + git p4 submit && + change=$(p4 -G changes -m 1 //depot/... | \ + marshal_dump change) && + # marshal_dump always adds a newline + p4 -G describe $change | marshal_dump desc | sed \$d >pmsg && + # make sure Jobs line and all following is gone + sed "/^Jobs:/,\$d" msg >jmsg && + test_cmp jmsg pmsg && + # make sure p4 knows about the two jobs + p4 -G describe $change >change && + ( + marshal_dump job0 <change && + marshal_dump job1 <change + ) | sort >jobs && + cat jobname1 jobname2 | sort >expected && + test_cmp expected jobs + ) +' + +test_expect_success 'description with Jobs section and bogus following text' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc6 >desc6 && + git add desc6 && + echo 6060843 >jobname && + ( + printf "subject line\n\n\tExtra tab\nline.\n\n" && + printf "Files:\n\tBogus files marker\n" && + printf "Junk: 3164175\n" && + printf "Jobs: $(cat jobname)\n" && + printf "MoreJunk: 3711\n" + ) >msg && + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + # build a job + make_job $(cat jobname) && + test_must_fail git p4 submit 2>err && + test_i18ngrep "Unknown field name" err + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9808-git-p4-chdir.sh b/t/t9808-git-p4-chdir.sh index 2f8014a60e..dc92e60cd6 100755 --- a/t/t9808-git-p4-chdir.sh +++ b/t/t9808-git-p4-chdir.sh @@ -21,7 +21,7 @@ test_expect_success 'init depot' ' # environment variable is set test_expect_success 'P4CONFIG and absolute dir clone' ' printf "P4PORT=$P4PORT\nP4CLIENT=$P4CLIENT\n" >p4config && - test_when_finished "rm \"$TRASH_DIRECTORY/p4config\"" && + test_when_finished "rm p4config" && test_when_finished cleanup_git && ( P4CONFIG=p4config && export P4CONFIG && @@ -33,7 +33,7 @@ test_expect_success 'P4CONFIG and absolute dir clone' ' # same thing, but with relative directory name, note missing $ on --dest test_expect_success 'P4CONFIG and relative dir clone' ' printf "P4PORT=$P4PORT\nP4CLIENT=$P4CLIENT\n" >p4config && - test_when_finished "rm \"$TRASH_DIRECTORY/p4config\"" && + test_when_finished "rm p4config" && test_when_finished cleanup_git && ( P4CONFIG=p4config && export P4CONFIG && diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh index b00ad09d23..e9daa9c4f6 100755 --- a/t/t9810-git-p4-rcs.sh +++ b/t/t9810-git-p4-rcs.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-p4 rcs keywords' +test_description='git p4 rcs keywords' . ./lib-git-p4.sh @@ -147,7 +147,7 @@ test_expect_success 'scrub ko files differently' ' ) ' -# hack; git-p4 submit should do it on its own +# hack; git p4 submit should do it on its own test_expect_success 'cleanup after failure' ' ( cd "$cli" && @@ -193,7 +193,7 @@ test_expect_success 'do not scrub plain text' ' ) ' -# hack; git-p4 submit should do it on its own +# hack; git p4 submit should do it on its own test_expect_success 'cleanup after failure 2' ' ( cd "$cli" && @@ -244,7 +244,7 @@ test_expect_success 'cope with rcs keyword expansion damage' ' cd "$git" && git config git-p4.skipSubmitEdit true && git config git-p4.attemptRCSCleanup true && - (cd ../cli && p4_append_to_file kwfile1.c) && + (cd "$cli" && p4_append_to_file kwfile1.c) && old_lines=$(wc -l <kwfile1.c) && "$PERL_PATH" -n -i -e "print unless m/Revision:/" kwfile1.c && new_lines=$(wc -l <kwfile1.c) && diff --git a/t/t9812-git-p4-wildcards.sh b/t/t9812-git-p4-wildcards.sh new file mode 100755 index 0000000000..143d413057 --- /dev/null +++ b/t/t9812-git-p4-wildcards.sh @@ -0,0 +1,147 @@ +#!/bin/sh + +test_description='git p4 wildcards' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'add p4 files with wildcards in the names' ' + ( + cd "$cli" && + printf "file2\nhas\nsome\nrandom\ntext\n" >file2 && + p4 add file2 && + echo file-wild-hash >file-wild#hash && + echo file-wild-star >file-wild\*star && + echo file-wild-at >file-wild@at && + echo file-wild-percent >file-wild%percent && + p4 add -f file-wild* && + p4 submit -d "file wildcards" + ) +' + +test_expect_success 'wildcard files git p4 clone' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + test -f file-wild#hash && + test -f file-wild\*star && + test -f file-wild@at && + test -f file-wild%percent + ) +' + +test_expect_success 'wildcard files submit back to p4, add' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo git-wild-hash >git-wild#hash && + echo git-wild-star >git-wild\*star && + echo git-wild-at >git-wild@at && + echo git-wild-percent >git-wild%percent && + git add git-wild* && + git commit -m "add some wildcard filenames" && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file git-wild#hash && + test_path_is_file git-wild\*star && + test_path_is_file git-wild@at && + test_path_is_file git-wild%percent + ) +' + +test_expect_success 'wildcard files submit back to p4, modify' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo new-line >>git-wild#hash && + echo new-line >>git-wild\*star && + echo new-line >>git-wild@at && + echo new-line >>git-wild%percent && + git add git-wild* && + git commit -m "modify the wildcard files" && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_line_count = 2 git-wild#hash && + test_line_count = 2 git-wild\*star && + test_line_count = 2 git-wild@at && + test_line_count = 2 git-wild%percent + ) +' + +test_expect_success 'wildcard files submit back to p4, copy' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + cp file2 git-wild-cp#hash && + git add git-wild-cp#hash && + cp git-wild\*star file-wild-3 && + git add file-wild-3 && + git commit -m "wildcard copies" && + git config git-p4.detectCopies true && + git config git-p4.detectCopiesHarder true && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file git-wild-cp#hash && + test_path_is_file file-wild-3 + ) +' + +test_expect_success 'wildcard files submit back to p4, rename' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git mv git-wild@at file-wild-4 && + git mv file-wild-3 git-wild-cp%percent && + git commit -m "wildcard renames" && + git config git-p4.detectRenames true && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing git-wild@at && + test_path_is_file git-wild-cp%percent + ) +' + +test_expect_success 'wildcard files submit back to p4, delete' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git rm git-wild* && + git commit -m "delete the wildcard files" && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing git-wild#hash && + test_path_is_missing git-wild\*star && + test_path_is_missing git-wild@at && + test_path_is_missing git-wild%percent + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9813-git-p4-preserve-users.sh b/t/t9813-git-p4-preserve-users.sh new file mode 100755 index 0000000000..f2e85e518b --- /dev/null +++ b/t/t9813-git-p4-preserve-users.sh @@ -0,0 +1,153 @@ +#!/bin/sh + +test_description='git p4 preserve users' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'create files' ' + ( + cd "$cli" && + p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i && + echo file1 >file1 && + echo file2 >file2 && + p4 add file1 file2 && + p4 submit -d "add files" + ) +' + +p4_add_user() { + name=$1 fullname=$2 && + p4 user -f -i <<-EOF && + User: $name + Email: $name@localhost + FullName: $fullname + EOF + p4 passwd -P secret $name +} + +p4_grant_admin() { + name=$1 && + { + p4 protect -o && + echo " admin user $name * //depot/..." + } | p4 protect -i +} + +p4_check_commit_author() { + file=$1 user=$2 && + p4 changes -m 1 //depot/$file | grep -q $user +} + +make_change_by_user() { + file=$1 name=$2 email=$3 && + echo "username: a change by $name" >>"$file" && + git add "$file" && + git commit --author "$name <$email>" -m "a change by $name" +} + +# Test username support, submitting as user 'alice' +test_expect_success 'preserve users' ' + p4_add_user alice Alice && + p4_add_user bob Bob && + p4_grant_admin alice && + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + echo "username: a change by alice" >>file1 && + echo "username: a change by bob" >>file2 && + git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 && + git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 && + git config git-p4.skipSubmitEditCheck true && + P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user && + p4_check_commit_author file1 alice && + p4_check_commit_author file2 bob + ) +' + +# Test username support, submitting as bob, who lacks admin rights. Should +# not submit change to p4 (git diff should show deltas). +test_expect_success 'refuse to preserve users without perms' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEditCheck true && + echo "username-noperms: a change by alice" >>file1 && + git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 && + P4EDITOR=touch P4USER=bob P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + test_must_fail git p4 commit --preserve-user && + ! git diff --exit-code HEAD..p4/master + ) +' + +# What happens with unknown author? Without allowMissingP4Users it should fail. +test_expect_success 'preserve user where author is unknown to p4' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEditCheck true && + echo "username-bob: a change by bob" >>file1 && + git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 && + echo "username-unknown: a change by charlie" >>file1 && + git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 && + P4EDITOR=touch P4USER=alice P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + test_must_fail git p4 commit --preserve-user && + ! git diff --exit-code HEAD..p4/master && + + echo "$0: repeat with allowMissingP4Users enabled" && + git config git-p4.allowMissingP4Users true && + git config git-p4.preserveUser true && + git p4 commit && + git diff --exit-code HEAD..p4/master && + p4_check_commit_author file1 alice + ) +' + +# If we're *not* using --preserve-user, git-p4 should warn if we're submitting +# changes that are not all ours. +# Test: user in p4 and user unknown to p4. +# Test: warning disabled and user is the same. +test_expect_success 'not preserving user with mixed authorship' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEditCheck true && + p4_add_user derek Derek && + + make_change_by_user usernamefile3 Derek derek@localhost && + P4EDITOR=cat P4USER=alice P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + git p4 commit |\ + grep "git author derek@localhost does not match" && + + make_change_by_user usernamefile3 Charlie charlie@localhost && + git p4 commit |\ + grep "git author charlie@localhost does not match" && + + make_change_by_user usernamefile3 alice alice@localhost && + git p4 commit |\ + test_must_fail grep "git author.*does not match" && + + git config git-p4.skipUserNameCheck true && + make_change_by_user usernamefile3 Charlie charlie@localhost && + git p4 commit |\ + test_must_fail grep "git author.*does not match" && + + p4_check_commit_author usernamefile3 alice + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh new file mode 100755 index 0000000000..3bf1224ae0 --- /dev/null +++ b/t/t9814-git-p4-rename.sh @@ -0,0 +1,206 @@ +#!/bin/sh + +test_description='git p4 rename' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +# We rely on this behavior to detect for p4 move availability. +test_expect_success 'p4 help unknown returns 1' ' + ( + cd "$cli" && + ( + p4 help client >errs 2>&1 + echo $? >retval + ) + echo 0 >expected && + test_cmp expected retval && + rm retval && + ( + p4 help nosuchcommand >errs 2>&1 + echo $? >retval + ) + echo 1 >expected && + test_cmp expected retval && + rm retval + ) +' + +test_expect_success 'create files' ' + ( + cd "$cli" && + p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i && + cat >file1 <<-EOF && + A large block of text + in file1 that will generate + enough context so that rename + and copy detection will find + something interesting to do. + EOF + cat >file2 <<-EOF && + /* + * This blob looks a bit + * different. + */ + int main(int argc, char **argv) + { + char text[200]; + + strcpy(text, "copy/rename this"); + printf("text is %s\n", text); + return 0; + } + EOF + p4 add file1 file2 && + p4 submit -d "add files" + ) +' + +# Rename a file and confirm that rename is not detected in P4. +# Rename the new file again with detectRenames option enabled and confirm that +# this is detected in P4. +# Rename the new file again adding an extra line, configure a big threshold in +# detectRenames and confirm that rename is not detected in P4. +# Repeat, this time with a smaller threshold and confirm that the rename is +# detected in P4. +test_expect_success 'detect renames' ' + git p4 clone --dest="$git" //depot@all && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + + git mv file1 file4 && + git commit -a -m "Rename file1 to file4" && + git diff-tree -r -M HEAD && + git p4 submit && + p4 filelog //depot/file4 >filelog && + ! grep " from //depot" filelog && + + git mv file4 file5 && + git commit -a -m "Rename file4 to file5" && + git diff-tree -r -M HEAD && + git config git-p4.detectRenames true && + git p4 submit && + p4 filelog //depot/file5 >filelog && + grep " from //depot/file4" filelog && + + git mv file5 file6 && + echo update >>file6 && + git add file6 && + git commit -a -m "Rename file5 to file6 with changes" && + git diff-tree -r -M HEAD && + level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && + test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && + git config git-p4.detectRenames $(($level + 2)) && + git p4 submit && + p4 filelog //depot/file6 >filelog && + ! grep " from //depot" filelog && + + git mv file6 file7 && + echo update >>file7 && + git add file7 && + git commit -a -m "Rename file6 to file7 with changes" && + git diff-tree -r -M HEAD && + level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && + test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && + git config git-p4.detectRenames $(($level - 2)) && + git p4 submit && + p4 filelog //depot/file7 >filelog && + grep " from //depot/file6" filelog + ) +' + +# Copy a file and confirm that copy is not detected in P4. +# Copy a file with detectCopies option enabled and confirm that copy is not +# detected in P4. +# Modify and copy a file with detectCopies option enabled and confirm that copy +# is detected in P4. +# Copy a file with detectCopies and detectCopiesHarder options enabled and +# confirm that copy is detected in P4. +# Modify and copy a file, configure a bigger threshold in detectCopies and +# confirm that copy is not detected in P4. +# Modify and copy a file, configure a smaller threshold in detectCopies and +# confirm that copy is detected in P4. +test_expect_success 'detect copies' ' + git p4 clone --dest="$git" //depot@all && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + + cp file2 file8 && + git add file8 && + git commit -a -m "Copy file2 to file8" && + git diff-tree -r -C HEAD && + git p4 submit && + p4 filelog //depot/file8 && + p4 filelog //depot/file8 | test_must_fail grep -q "branch from" && + + cp file2 file9 && + git add file9 && + git commit -a -m "Copy file2 to file9" && + git diff-tree -r -C HEAD && + git config git-p4.detectCopies true && + git p4 submit && + p4 filelog //depot/file9 && + p4 filelog //depot/file9 | test_must_fail grep -q "branch from" && + + echo "file2" >>file2 && + cp file2 file10 && + git add file2 file10 && + git commit -a -m "Modify and copy file2 to file10" && + git diff-tree -r -C HEAD && + git p4 submit && + p4 filelog //depot/file10 && + p4 filelog //depot/file10 | grep -q "branch from //depot/file" && + + cp file2 file11 && + git add file11 && + git commit -a -m "Copy file2 to file11" && + git diff-tree -r -C --find-copies-harder HEAD && + src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && + test "$src" = file10 && + git config git-p4.detectCopiesHarder true && + git p4 submit && + p4 filelog //depot/file11 && + p4 filelog //depot/file11 | grep -q "branch from //depot/file" && + + cp file2 file12 && + echo "some text" >>file12 && + git add file12 && + git commit -a -m "Copy file2 to file12 with changes" && + git diff-tree -r -C --find-copies-harder HEAD && + level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && + test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && + src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && + test "$src" = file10 -o "$src" = file11 && + git config git-p4.detectCopies $(($level + 2)) && + git p4 submit && + p4 filelog //depot/file12 && + p4 filelog //depot/file12 | test_must_fail grep -q "branch from" && + + cp file2 file13 && + echo "different text" >>file13 && + git add file13 && + git commit -a -m "Copy file2 to file13 with changes" && + git diff-tree -r -C --find-copies-harder HEAD && + level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && + test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && + src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && + test "$src" = file10 -o "$src" = file11 -o "$src" = file12 && + git config git-p4.detectCopies $(($level - 2)) && + git p4 submit && + p4 filelog //depot/file13 && + p4 filelog //depot/file13 | grep -q "branch from //depot/file" + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 256e6a0b3f..92d7eb47c2 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -3,21 +3,9 @@ # Copyright (c) 2012 Felipe Contreras # -if test -n "$BASH" && test -z "$POSIXLY_CORRECT"; then - # we are in full-on bash mode - true -elif type bash >/dev/null 2>&1; then - # execute in full-on bash mode - unset POSIXLY_CORRECT - exec bash "$0" "$@" -else - echo '1..0 #SKIP skipping bash completion tests; bash not available' - exit 0 -fi - test_description='test bash completion' -. ./test-lib.sh +. ./lib-bash.sh complete () { diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh new file mode 100755 index 0000000000..f17c1f8b85 --- /dev/null +++ b/t/t9903-bash-prompt.sh @@ -0,0 +1,456 @@ +#!/bin/sh +# +# Copyright (c) 2012 SZEDER Gábor +# + +test_description='test git-specific bash prompt functions' + +. ./lib-bash.sh + +. "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh" + +actual="$TRASH_DIRECTORY/actual" + +test_expect_success 'setup for prompt tests' ' + mkdir -p subdir/subsubdir && + git init otherrepo && + echo 1 > file && + git add file && + test_tick && + git commit -m initial && + git tag -a -m msg1 t1 && + git checkout -b b1 && + echo 2 > file && + git commit -m "second b1" file && + echo 3 > file && + git commit -m "third b1" file && + git tag -a -m msg2 t2 && + git checkout -b b2 master && + echo 0 > file && + git commit -m "second b2" file && + git checkout master +' + +test_expect_success 'gitdir - from command line (through $__git_dir)' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + ( + __git_dir="$TRASH_DIRECTORY/otherrepo/.git" && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - repo as argument' ' + echo "otherrepo/.git" > expected && + __gitdir "otherrepo" > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - remote as argument' ' + echo "remote" > expected && + __gitdir "remote" > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - .git directory in cwd' ' + echo ".git" > expected && + __gitdir > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - .git directory in parent' ' + echo "$TRASH_DIRECTORY/.git" > expected && + ( + cd subdir/subsubdir && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - cwd is a .git directory' ' + echo "." > expected && + ( + cd .git && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - parent is a .git directory' ' + echo "$TRASH_DIRECTORY/.git" > expected && + ( + cd .git/refs/heads && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - $GIT_DIR set while .git directory in cwd' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + ( + GIT_DIR="$TRASH_DIRECTORY/otherrepo/.git" && + export GIT_DIR && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - $GIT_DIR set while .git directory in parent' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + ( + GIT_DIR="$TRASH_DIRECTORY/otherrepo/.git" && + export GIT_DIR && + cd subdir && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - non-existing $GIT_DIR' ' + ( + GIT_DIR="$TRASH_DIRECTORY/non-existing" && + export GIT_DIR && + test_must_fail __gitdir + ) +' + +test_expect_success 'gitdir - gitfile in cwd' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git && + test_when_finished "rm -f subdir/.git" && + ( + cd subdir && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - gitfile in parent' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git && + test_when_finished "rm -f subdir/.git" && + ( + cd subdir/subsubdir && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + mkdir otherrepo/dir && + test_when_finished "rm -rf otherrepo/dir" && + ln -s otherrepo/dir link && + test_when_finished "rm -f link" && + ( + cd link && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - not a git repository' ' + ( + cd subdir/subsubdir && + GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY" && + export GIT_CEILING_DIRECTORIES && + test_must_fail __gitdir + ) +' + +test_expect_success 'prompt - branch name' ' + printf " (master)" > expected && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - detached head' ' + printf " ((%s...))" $(git log -1 --format="%h" b1^) > expected && + git checkout b1^ && + test_when_finished "git checkout master" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - describe detached head - contains' ' + printf " ((t2~1))" > expected && + git checkout b1^ && + test_when_finished "git checkout master" && + ( + GIT_PS1_DESCRIBE_STYLE=contains && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - describe detached head - branch' ' + printf " ((b1~1))" > expected && + git checkout b1^ && + test_when_finished "git checkout master" && + ( + GIT_PS1_DESCRIBE_STYLE=branch && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - describe detached head - describe' ' + printf " ((t1-1-g%s))" $(git log -1 --format="%h" b1^) > expected && + git checkout b1^ && + test_when_finished "git checkout master" && + ( + GIT_PS1_DESCRIBE_STYLE=describe && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - describe detached head - default' ' + printf " ((t2))" > expected && + git checkout --detach b1 && + test_when_finished "git checkout master" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - inside .git directory' ' + printf " (GIT_DIR!)" > expected && + ( + cd .git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - deep inside .git directory' ' + printf " (GIT_DIR!)" > expected && + ( + cd .git/refs/heads && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - inside bare repository' ' + printf " (BARE:master)" > expected && + git init --bare bare.git && + test_when_finished "rm -rf bare.git" && + ( + cd bare.git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - interactive rebase' ' + printf " (b1|REBASE-i)" > expected + echo "#!$SHELL_PATH" >fake_editor.sh && + cat >>fake_editor.sh <<\EOF && +echo "edit $(git log -1 --format="%h")" > "$1" +EOF + test_when_finished "rm -f fake_editor.sh" && + chmod a+x fake_editor.sh && + test_set_editor "$TRASH_DIRECTORY/fake_editor.sh" && + git checkout b1 && + test_when_finished "git checkout master" && + git rebase -i HEAD^ && + test_when_finished "git rebase --abort" + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - rebase merge' ' + printf " (b2|REBASE-m)" > expected && + git checkout b2 && + test_when_finished "git checkout master" && + test_must_fail git rebase --merge b1 b2 && + test_when_finished "git rebase --abort" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - rebase' ' + printf " ((t2)|REBASE)" > expected && + git checkout b2 && + test_when_finished "git checkout master" && + test_must_fail git rebase b1 b2 && + test_when_finished "git rebase --abort" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - merge' ' + printf " (b1|MERGING)" > expected && + git checkout b1 && + test_when_finished "git checkout master" && + test_must_fail git merge b2 && + test_when_finished "git reset --hard" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - cherry-pick' ' + printf " (master|CHERRY-PICKING)" > expected && + test_must_fail git cherry-pick b1 && + test_when_finished "git reset --hard" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - bisect' ' + printf " (master|BISECTING)" > expected && + git bisect start && + test_when_finished "git bisect reset" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - clean' ' + printf " (master)" > expected && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - dirty worktree' ' + printf " (master *)" > expected && + echo "dirty" > file && + test_when_finished "git reset --hard" && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - dirty index' ' + printf " (master +)" > expected && + echo "dirty" > file && + test_when_finished "git reset --hard" && + git add -u && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - dirty index and worktree' ' + printf " (master *+)" > expected && + echo "dirty index" > file && + test_when_finished "git reset --hard" && + git add -u && + echo "dirty worktree" > file && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - before root commit' ' + printf " (master #)" > expected && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + cd otherrepo && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - disabled by config' ' + printf " (master)" > expected && + echo "dirty" > file && + test_when_finished "git reset --hard" && + test_config bash.showDirtyState false && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - not shown inside .git directory' ' + printf " (GIT_DIR!)" > expected && + echo "dirty" > file && + test_when_finished "git reset --hard" && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + cd .git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - stash status indicator - no stash' ' + printf " (master)" > expected && + ( + GIT_PS1_SHOWSTASHSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - stash status indicator - stash' ' + printf " (master $)" > expected && + echo 2 >file && + git stash && + test_when_finished "git stash drop" && + ( + GIT_PS1_SHOWSTASHSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - stash status indicator - not shown inside .git directory' ' + printf " (GIT_DIR!)" > expected && + echo 2 >file && + git stash && + test_when_finished "git stash drop" && + ( + GIT_PS1_SHOWSTASHSTATE=y && + cd .git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - no untracked files' ' + printf " (master)" > expected && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + cd otherrepo && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - untracked files' ' + printf " (master %%)" > expected && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - not shown inside .git directory' ' + printf " (GIT_DIR!)" > expected && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + cd .git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - format string starting with dash' ' + printf -- "-master" > expected && + __git_ps1 "-%s" > "$actual" && + test_cmp expected "$actual" +' + +test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index acda33d177..bb4f8865b2 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -34,6 +34,26 @@ esac # Keep the original TERM for say_color ORIGINAL_TERM=$TERM +# Test the binaries we have just built. The tests are kept in +# t/ subdirectory and are run in 'trash directory' subdirectory. +if test -z "$TEST_DIRECTORY" +then + # We allow tests to override this, in case they want to run tests + # outside of t/, e.g. for running tests on the test library + # itself. + TEST_DIRECTORY=$(pwd) +fi +if test -z "$TEST_OUTPUT_DIRECTORY" +then + # Similarly, override this to store the test-results subdir + # elsewhere + TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY +fi +GIT_BUILD_DIR="$TEST_DIRECTORY"/.. + +. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS +export PERL_PATH SHELL_PATH + # For repeatability, reset the environment to known value. LANG=C LC_ALL=C @@ -46,7 +66,7 @@ EDITOR=: # /usr/xpg4/bin/sh and /bin/ksh to bail out. So keep the unsets # deriving from the command substitution clustered with the other # ones. -unset VISUAL EMAIL LANGUAGE COLUMNS $(perl -e ' +unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e ' my @env = keys %ENV; my $ok = join("|", qw( TRACE @@ -61,6 +81,7 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $(perl -e ' my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env); print join("\n", @vars); ') +unset XDG_CONFIG_HOME GIT_AUTHOR_EMAIL=author@example.com GIT_AUTHOR_NAME='A U Thor' GIT_COMMITTER_EMAIL=committer@example.com @@ -229,7 +250,7 @@ trap 'die' EXIT # The user-facing functions are loaded from a separate file so that # test_perf subshells can have them too -. "${TEST_DIRECTORY:-.}"/test-lib-functions.sh +. "$TEST_DIRECTORY/test-lib-functions.sh" # You are not expected to call test_ok_ and test_failure_ directly, use # the text_expect_* functions instead. @@ -380,23 +401,6 @@ test_done () { esac } -# Test the binaries we have just built. The tests are kept in -# t/ subdirectory and are run in 'trash directory' subdirectory. -if test -z "$TEST_DIRECTORY" -then - # We allow tests to override this, in case they want to run tests - # outside of t/, e.g. for running tests on the test library - # itself. - TEST_DIRECTORY=$(pwd) -fi -if test -z "$TEST_OUTPUT_DIRECTORY" -then - # Similarly, override this to store the test-results subdir - # elsewhere - TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY -fi -GIT_BUILD_DIR="$TEST_DIRECTORY"/.. - if test -n "$valgrind" then make_symlink () { @@ -492,10 +496,6 @@ GIT_CONFIG_NOSYSTEM=1 GIT_ATTR_NOSYSTEM=1 export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM -. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS - -export PERL_PATH - if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" |