t / t7800-difftool.shon commit difftool: add a skeleton for the upcoming builtin (be8a90e)
   1#!/bin/sh
   2#
   3# Copyright (c) 2009, 2010, 2012, 2013 David Aguilar
   4#
   5
   6test_description='git-difftool
   7
   8Testing basic diff tool invocation
   9'
  10
  11. ./test-lib.sh
  12
  13difftool_test_setup ()
  14{
  15        test_config diff.tool test-tool &&
  16        test_config difftool.test-tool.cmd 'cat "$LOCAL"' &&
  17        test_config difftool.bogus-tool.cmd false
  18}
  19
  20prompt_given ()
  21{
  22        prompt="$1"
  23        test "$prompt" = "Launch 'test-tool' [Y/n]? branch"
  24}
  25
  26# NEEDSWORK: lose all the PERL prereqs once legacy-difftool is retired.
  27
  28# Create a file on master and change it on branch
  29test_expect_success PERL 'setup' '
  30        echo master >file &&
  31        git add file &&
  32        git commit -m "added file" &&
  33
  34        git checkout -b branch master &&
  35        echo branch >file &&
  36        git commit -a -m "branch changed file" &&
  37        git checkout master
  38'
  39
  40# Configure a custom difftool.<tool>.cmd and use it
  41test_expect_success PERL 'custom commands' '
  42        difftool_test_setup &&
  43        test_config difftool.test-tool.cmd "cat \"\$REMOTE\"" &&
  44        echo master >expect &&
  45        git difftool --no-prompt branch >actual &&
  46        test_cmp expect actual &&
  47
  48        test_config difftool.test-tool.cmd "cat \"\$LOCAL\"" &&
  49        echo branch >expect &&
  50        git difftool --no-prompt branch >actual &&
  51        test_cmp expect actual
  52'
  53
  54test_expect_success PERL 'custom tool commands override built-ins' '
  55        test_config difftool.vimdiff.cmd "cat \"\$REMOTE\"" &&
  56        echo master >expect &&
  57        git difftool --tool vimdiff --no-prompt branch >actual &&
  58        test_cmp expect actual
  59'
  60
  61test_expect_success PERL 'difftool ignores bad --tool values' '
  62        : >expect &&
  63        test_must_fail \
  64                git difftool --no-prompt --tool=bad-tool branch >actual &&
  65        test_cmp expect actual
  66'
  67
  68test_expect_success PERL 'difftool forwards arguments to diff' '
  69        difftool_test_setup &&
  70        >for-diff &&
  71        git add for-diff &&
  72        echo changes>for-diff &&
  73        git add for-diff &&
  74        : >expect &&
  75        git difftool --cached --no-prompt -- for-diff >actual &&
  76        test_cmp expect actual &&
  77        git reset -- for-diff &&
  78        rm for-diff
  79'
  80
  81test_expect_success PERL 'difftool ignores exit code' '
  82        test_config difftool.error.cmd false &&
  83        git difftool -y -t error branch
  84'
  85
  86test_expect_success PERL 'difftool forwards exit code with --trust-exit-code' '
  87        test_config difftool.error.cmd false &&
  88        test_must_fail git difftool -y --trust-exit-code -t error branch
  89'
  90
  91test_expect_success PERL 'difftool forwards exit code with --trust-exit-code for built-ins' '
  92        test_config difftool.vimdiff.path false &&
  93        test_must_fail git difftool -y --trust-exit-code -t vimdiff branch
  94'
  95
  96test_expect_success PERL 'difftool honors difftool.trustExitCode = true' '
  97        test_config difftool.error.cmd false &&
  98        test_config difftool.trustExitCode true &&
  99        test_must_fail git difftool -y -t error branch
 100'
 101
 102test_expect_success PERL 'difftool honors difftool.trustExitCode = false' '
 103        test_config difftool.error.cmd false &&
 104        test_config difftool.trustExitCode false &&
 105        git difftool -y -t error branch
 106'
 107
 108test_expect_success PERL 'difftool ignores exit code with --no-trust-exit-code' '
 109        test_config difftool.error.cmd false &&
 110        test_config difftool.trustExitCode true &&
 111        git difftool -y --no-trust-exit-code -t error branch
 112'
 113
 114test_expect_success PERL 'difftool stops on error with --trust-exit-code' '
 115        test_when_finished "rm -f for-diff .git/fail-right-file" &&
 116        test_when_finished "git reset -- for-diff" &&
 117        write_script .git/fail-right-file <<-\EOF &&
 118        echo "$2"
 119        exit 1
 120        EOF
 121        >for-diff &&
 122        git add for-diff &&
 123        echo file >expect &&
 124        test_must_fail git difftool -y --trust-exit-code \
 125                --extcmd .git/fail-right-file branch >actual &&
 126        test_cmp expect actual
 127'
 128
 129test_expect_success PERL 'difftool honors exit status if command not found' '
 130        test_config difftool.nonexistent.cmd i-dont-exist &&
 131        test_config difftool.trustExitCode false &&
 132        test_must_fail git difftool -y -t nonexistent branch
 133'
 134
 135test_expect_success PERL 'difftool honors --gui' '
 136        difftool_test_setup &&
 137        test_config merge.tool bogus-tool &&
 138        test_config diff.tool bogus-tool &&
 139        test_config diff.guitool test-tool &&
 140
 141        echo branch >expect &&
 142        git difftool --no-prompt --gui branch >actual &&
 143        test_cmp expect actual
 144'
 145
 146test_expect_success PERL 'difftool --gui last setting wins' '
 147        difftool_test_setup &&
 148        : >expect &&
 149        git difftool --no-prompt --gui --no-gui >actual &&
 150        test_cmp expect actual &&
 151
 152        test_config merge.tool bogus-tool &&
 153        test_config diff.tool bogus-tool &&
 154        test_config diff.guitool test-tool &&
 155        echo branch >expect &&
 156        git difftool --no-prompt --no-gui --gui branch >actual &&
 157        test_cmp expect actual
 158'
 159
 160test_expect_success PERL 'difftool --gui works without configured diff.guitool' '
 161        difftool_test_setup &&
 162        echo branch >expect &&
 163        git difftool --no-prompt --gui branch >actual &&
 164        test_cmp expect actual
 165'
 166
 167# Specify the diff tool using $GIT_DIFF_TOOL
 168test_expect_success PERL 'GIT_DIFF_TOOL variable' '
 169        difftool_test_setup &&
 170        git config --unset diff.tool &&
 171        echo branch >expect &&
 172        GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
 173        test_cmp expect actual
 174'
 175
 176# Test the $GIT_*_TOOL variables and ensure
 177# that $GIT_DIFF_TOOL always wins unless --tool is specified
 178test_expect_success PERL 'GIT_DIFF_TOOL overrides' '
 179        difftool_test_setup &&
 180        test_config diff.tool bogus-tool &&
 181        test_config merge.tool bogus-tool &&
 182
 183        echo branch >expect &&
 184        GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
 185        test_cmp expect actual &&
 186
 187        test_config diff.tool bogus-tool &&
 188        test_config merge.tool bogus-tool &&
 189        GIT_DIFF_TOOL=bogus-tool \
 190                git difftool --no-prompt --tool=test-tool branch >actual &&
 191        test_cmp expect actual
 192'
 193
 194# Test that we don't have to pass --no-prompt to difftool
 195# when $GIT_DIFFTOOL_NO_PROMPT is true
 196test_expect_success PERL 'GIT_DIFFTOOL_NO_PROMPT variable' '
 197        difftool_test_setup &&
 198        echo branch >expect &&
 199        GIT_DIFFTOOL_NO_PROMPT=true git difftool branch >actual &&
 200        test_cmp expect actual
 201'
 202
 203# git-difftool supports the difftool.prompt variable.
 204# Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false
 205test_expect_success PERL 'GIT_DIFFTOOL_PROMPT variable' '
 206        difftool_test_setup &&
 207        test_config difftool.prompt false &&
 208        echo >input &&
 209        GIT_DIFFTOOL_PROMPT=true git difftool branch <input >output &&
 210        prompt=$(tail -1 <output) &&
 211        prompt_given "$prompt"
 212'
 213
 214# Test that we don't have to pass --no-prompt when difftool.prompt is false
 215test_expect_success PERL 'difftool.prompt config variable is false' '
 216        difftool_test_setup &&
 217        test_config difftool.prompt false &&
 218        echo branch >expect &&
 219        git difftool branch >actual &&
 220        test_cmp expect actual
 221'
 222
 223# Test that we don't have to pass --no-prompt when mergetool.prompt is false
 224test_expect_success PERL 'difftool merge.prompt = false' '
 225        difftool_test_setup &&
 226        test_might_fail git config --unset difftool.prompt &&
 227        test_config mergetool.prompt false &&
 228        echo branch >expect &&
 229        git difftool branch >actual &&
 230        test_cmp expect actual
 231'
 232
 233# Test that the -y flag can override difftool.prompt = true
 234test_expect_success PERL 'difftool.prompt can overridden with -y' '
 235        difftool_test_setup &&
 236        test_config difftool.prompt true &&
 237        echo branch >expect &&
 238        git difftool -y branch >actual &&
 239        test_cmp expect actual
 240'
 241
 242# Test that the --prompt flag can override difftool.prompt = false
 243test_expect_success PERL 'difftool.prompt can overridden with --prompt' '
 244        difftool_test_setup &&
 245        test_config difftool.prompt false &&
 246        echo >input &&
 247        git difftool --prompt branch <input >output &&
 248        prompt=$(tail -1 <output) &&
 249        prompt_given "$prompt"
 250'
 251
 252# Test that the last flag passed on the command-line wins
 253test_expect_success PERL 'difftool last flag wins' '
 254        difftool_test_setup &&
 255        echo branch >expect &&
 256        git difftool --prompt --no-prompt branch >actual &&
 257        test_cmp expect actual &&
 258        echo >input &&
 259        git difftool --no-prompt --prompt branch <input >output &&
 260        prompt=$(tail -1 <output) &&
 261        prompt_given "$prompt"
 262'
 263
 264# git-difftool falls back to git-mergetool config variables
 265# so test that behavior here
 266test_expect_success PERL 'difftool + mergetool config variables' '
 267        test_config merge.tool test-tool &&
 268        test_config mergetool.test-tool.cmd "cat \$LOCAL" &&
 269        echo branch >expect &&
 270        git difftool --no-prompt branch >actual &&
 271        test_cmp expect actual &&
 272
 273        # set merge.tool to something bogus, diff.tool to test-tool
 274        test_config merge.tool bogus-tool &&
 275        test_config diff.tool test-tool &&
 276        git difftool --no-prompt branch >actual &&
 277        test_cmp expect actual
 278'
 279
 280test_expect_success PERL 'difftool.<tool>.path' '
 281        test_config difftool.tkdiff.path echo &&
 282        git difftool --tool=tkdiff --no-prompt branch >output &&
 283        lines=$(grep file output | wc -l) &&
 284        test "$lines" -eq 1
 285'
 286
 287test_expect_success PERL 'difftool --extcmd=cat' '
 288        echo branch >expect &&
 289        echo master >>expect &&
 290        git difftool --no-prompt --extcmd=cat branch >actual &&
 291        test_cmp expect actual
 292'
 293
 294test_expect_success PERL 'difftool --extcmd cat' '
 295        echo branch >expect &&
 296        echo master >>expect &&
 297        git difftool --no-prompt --extcmd=cat branch >actual &&
 298        test_cmp expect actual
 299'
 300
 301test_expect_success PERL 'difftool -x cat' '
 302        echo branch >expect &&
 303        echo master >>expect &&
 304        git difftool --no-prompt -x cat branch >actual &&
 305        test_cmp expect actual
 306'
 307
 308test_expect_success PERL 'difftool --extcmd echo arg1' '
 309        echo file >expect &&
 310        git difftool --no-prompt \
 311                --extcmd sh\ -c\ \"echo\ \$1\" branch >actual &&
 312        test_cmp expect actual
 313'
 314
 315test_expect_success PERL 'difftool --extcmd cat arg1' '
 316        echo master >expect &&
 317        git difftool --no-prompt \
 318                --extcmd sh\ -c\ \"cat\ \$1\" branch >actual &&
 319        test_cmp expect actual
 320'
 321
 322test_expect_success PERL 'difftool --extcmd cat arg2' '
 323        echo branch >expect &&
 324        git difftool --no-prompt \
 325                --extcmd sh\ -c\ \"cat\ \$2\" branch >actual &&
 326        test_cmp expect actual
 327'
 328
 329# Create a second file on master and a different version on branch
 330test_expect_success PERL 'setup with 2 files different' '
 331        echo m2 >file2 &&
 332        git add file2 &&
 333        git commit -m "added file2" &&
 334
 335        git checkout branch &&
 336        echo br2 >file2 &&
 337        git add file2 &&
 338        git commit -a -m "branch changed file2" &&
 339        git checkout master
 340'
 341
 342test_expect_success PERL 'say no to the first file' '
 343        (echo n && echo) >input &&
 344        git difftool -x cat branch <input >output &&
 345        grep m2 output &&
 346        grep br2 output &&
 347        ! grep master output &&
 348        ! grep branch output
 349'
 350
 351test_expect_success PERL 'say no to the second file' '
 352        (echo && echo n) >input &&
 353        git difftool -x cat branch <input >output &&
 354        grep master output &&
 355        grep branch output &&
 356        ! grep m2 output &&
 357        ! grep br2 output
 358'
 359
 360test_expect_success PERL 'ending prompt input with EOF' '
 361        git difftool -x cat branch </dev/null >output &&
 362        ! grep master output &&
 363        ! grep branch output &&
 364        ! grep m2 output &&
 365        ! grep br2 output
 366'
 367
 368test_expect_success PERL 'difftool --tool-help' '
 369        git difftool --tool-help >output &&
 370        grep tool output
 371'
 372
 373test_expect_success PERL 'setup change in subdirectory' '
 374        git checkout master &&
 375        mkdir sub &&
 376        echo master >sub/sub &&
 377        git add sub/sub &&
 378        git commit -m "added sub/sub" &&
 379        echo test >>file &&
 380        echo test >>sub/sub &&
 381        git add file sub/sub &&
 382        git commit -m "modified both"
 383'
 384
 385run_dir_diff_test () {
 386        test_expect_success PERL "$1 --no-symlinks" "
 387                symlinks=--no-symlinks &&
 388                $2
 389        "
 390        test_expect_success PERL,SYMLINKS "$1 --symlinks" "
 391                symlinks=--symlinks &&
 392                $2
 393        "
 394}
 395
 396run_dir_diff_test 'difftool -d' '
 397        git difftool -d $symlinks --extcmd ls branch >output &&
 398        grep sub output &&
 399        grep file output
 400'
 401
 402run_dir_diff_test 'difftool --dir-diff' '
 403        git difftool --dir-diff $symlinks --extcmd ls branch >output &&
 404        grep sub output &&
 405        grep file output
 406'
 407
 408run_dir_diff_test 'difftool --dir-diff ignores --prompt' '
 409        git difftool --dir-diff $symlinks --prompt --extcmd ls branch >output &&
 410        grep sub output &&
 411        grep file output
 412'
 413
 414run_dir_diff_test 'difftool --dir-diff from subdirectory' '
 415        (
 416                cd sub &&
 417                git difftool --dir-diff $symlinks --extcmd ls branch >output &&
 418                grep sub output &&
 419                grep file output
 420        )
 421'
 422
 423run_dir_diff_test 'difftool --dir-diff from subdirectory with GIT_DIR set' '
 424        (
 425                GIT_DIR=$(pwd)/.git &&
 426                export GIT_DIR &&
 427                GIT_WORK_TREE=$(pwd) &&
 428                export GIT_WORK_TREE &&
 429                cd sub &&
 430                git difftool --dir-diff $symlinks --extcmd ls \
 431                        branch -- sub >output &&
 432                grep sub output &&
 433                ! grep file output
 434        )
 435'
 436
 437run_dir_diff_test 'difftool --dir-diff when worktree file is missing' '
 438        test_when_finished git reset --hard &&
 439        rm file2 &&
 440        git difftool --dir-diff $symlinks --extcmd ls branch master >output &&
 441        grep file2 output
 442'
 443
 444run_dir_diff_test 'difftool --dir-diff with unmerged files' '
 445        test_when_finished git reset --hard &&
 446        test_config difftool.echo.cmd "echo ok" &&
 447        git checkout -B conflict-a &&
 448        git checkout -B conflict-b &&
 449        git checkout conflict-a &&
 450        echo a >>file &&
 451        git add file &&
 452        git commit -m conflict-a &&
 453        git checkout conflict-b &&
 454        echo b >>file &&
 455        git add file &&
 456        git commit -m conflict-b &&
 457        git checkout master &&
 458        git merge conflict-a &&
 459        test_must_fail git merge conflict-b &&
 460        cat >expect <<-EOF &&
 461                ok
 462        EOF
 463        git difftool --dir-diff $symlinks -t echo >actual &&
 464        test_cmp expect actual
 465'
 466
 467write_script .git/CHECK_SYMLINKS <<\EOF
 468for f in file file2 sub/sub
 469do
 470        echo "$f"
 471        ls -ld "$2/$f" | sed -e 's/.* -> //'
 472done >actual
 473EOF
 474
 475test_expect_success PERL,SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' '
 476        cat >expect <<-EOF &&
 477        file
 478        $PWD/file
 479        file2
 480        $PWD/file2
 481        sub/sub
 482        $PWD/sub/sub
 483        EOF
 484        git difftool --dir-diff --symlink \
 485                --extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
 486        test_cmp actual expect
 487'
 488
 489write_script modify-right-file <<\EOF
 490echo "new content" >"$2/file"
 491EOF
 492
 493run_dir_diff_test 'difftool --dir-diff syncs worktree with unstaged change' '
 494        test_when_finished git reset --hard &&
 495        echo "orig content" >file &&
 496        git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
 497        echo "new content" >expect &&
 498        test_cmp expect file
 499'
 500
 501run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' '
 502        test_when_finished git reset --hard &&
 503        git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
 504        echo "new content" >expect &&
 505        test_cmp expect file
 506'
 507
 508write_script modify-file <<\EOF
 509echo "new content" >file
 510EOF
 511
 512test_expect_success PERL 'difftool --no-symlinks does not overwrite working tree file ' '
 513        echo "orig content" >file &&
 514        git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-file" branch &&
 515        echo "new content" >expect &&
 516        test_cmp expect file
 517'
 518
 519write_script modify-both-files <<\EOF
 520echo "wt content" >file &&
 521echo "tmp content" >"$2/file" &&
 522echo "$2" >tmpdir
 523EOF
 524
 525test_expect_success PERL 'difftool --no-symlinks detects conflict ' '
 526        (
 527                TMPDIR=$TRASH_DIRECTORY &&
 528                export TMPDIR &&
 529                echo "orig content" >file &&
 530                test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-both-files" branch &&
 531                echo "wt content" >expect &&
 532                test_cmp expect file &&
 533                echo "tmp content" >expect &&
 534                test_cmp expect "$(cat tmpdir)/file"
 535        )
 536'
 537
 538test_expect_success PERL 'difftool properly honors gitlink and core.worktree' '
 539        git submodule add ./. submod/ule &&
 540        test_config -C submod/ule diff.tool checktrees &&
 541        test_config -C submod/ule difftool.checktrees.cmd '\''
 542                test -d "$LOCAL" && test -d "$REMOTE" && echo good
 543                '\'' &&
 544        (
 545                cd submod/ule &&
 546                echo good >expect &&
 547                git difftool --tool=checktrees --dir-diff HEAD~ >actual &&
 548                test_cmp expect actual
 549        )
 550'
 551
 552test_expect_success PERL,SYMLINKS 'difftool --dir-diff symlinked directories' '
 553        git init dirlinks &&
 554        (
 555                cd dirlinks &&
 556                git config diff.tool checktrees &&
 557                git config difftool.checktrees.cmd "echo good" &&
 558                mkdir foo &&
 559                : >foo/bar &&
 560                git add foo/bar &&
 561                test_commit symlink-one &&
 562                ln -s foo link &&
 563                git add link &&
 564                test_commit symlink-two &&
 565                echo good >expect &&
 566                git difftool --tool=checktrees --dir-diff HEAD~ >actual &&
 567                test_cmp expect actual
 568        )
 569'
 570
 571test_done