Merge branch 'jk/add-p-commentchar-fix'
authorJunio C Hamano <gitster@pobox.com>
Mon, 26 Jun 2017 21:09:31 +0000 (14:09 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 26 Jun 2017 21:09:31 +0000 (14:09 -0700)
"git add -p" were updated in 2.12 timeframe to cope with custom
core.commentchar but the implementation was buggy and a
metacharacter like $ and * did not work.

* jk/add-p-commentchar-fix:
add--interactive: quote commentChar regex
add--interactive: handle EOF in prompt_yesno

1  2 
git-add--interactive.perl
t/t3701-add-interactive.sh
index 79d675b5b02ee73a025f86acc6cc29e530ee8db6,395dd5eb4b83377f59b486f7b483bf2103efcdec..0e8543c8652f2ec55dd9bc33d7d0a485d33aa9c7
@@@ -46,6 -46,8 +46,6 @@@ my ($diff_new_color) 
  my $normal_color = $repo->get_color("", "reset");
  
  my $diff_algorithm = $repo->config('diff.algorithm');
 -my $diff_indent_heuristic = $repo->config_bool('diff.indentheuristic');
 -my $diff_compaction_heuristic = $repo->config_bool('diff.compactionheuristic');
  my $diff_filter = $repo->config('interactive.difffilter');
  
  my $use_readkey = 0;
@@@ -91,7 -93,7 +91,7 @@@ sub colored 
  }
  
  # command line options
 -my $cmd;
 +my $patch_mode_only;
  my $patch_mode;
  my $patch_mode_revision;
  
@@@ -274,11 -276,20 +274,11 @@@ sub list_modified 
        my ($only) = @_;
        my (%data, @return);
        my ($add, $del, $adddel, $file);
 -      my @tracked = ();
 -
 -      if (@ARGV) {
 -              @tracked = map {
 -                      chomp $_;
 -                      unquote_path($_);
 -              } run_cmd_pipe(qw(git ls-files --), @ARGV);
 -              return if (!@tracked);
 -      }
  
        my $reference = get_diff_reference($patch_mode_revision);
        for (run_cmd_pipe(qw(git diff-index --cached
                             --numstat --summary), $reference,
 -                           '--', @tracked)) {
 +                           '--', @ARGV)) {
                if (($add, $del, $file) =
                    /^([-\d]+)  ([-\d]+)        (.*)/) {
                        my ($change, $bin);
                }
        }
  
 -      for (run_cmd_pipe(qw(git diff-files --numstat --summary --raw --), @tracked)) {
 +      for (run_cmd_pipe(qw(git diff-files --numstat --summary --raw --), @ARGV)) {
                if (($add, $del, $file) =
                    /^([-\d]+)  ([-\d]+)        (.*)/) {
                        $file = unquote_path($file);
@@@ -729,6 -740,11 +729,6 @@@ sub parse_diff 
        if (defined $diff_algorithm) {
                splice @diff_cmd, 1, 0, "--diff-algorithm=${diff_algorithm}";
        }
 -      if ($diff_indent_heuristic) {
 -              splice @diff_cmd, 1, 0, "--indent-heuristic";
 -      } elsif ($diff_compaction_heuristic) {
 -              splice @diff_cmd, 1, 0, "--compaction-heuristic";
 -      }
        if (defined $patch_mode_revision) {
                push @diff_cmd, get_diff_reference($patch_mode_revision);
        }
@@@ -1036,7 -1052,7 +1036,7 @@@ marked for unstaging.")
  marked for applying."),
        checkout_index => N__(
  "If the patch applies cleanly, the edited hunk will immediately be
 -marked for discarding"),
 +marked for discarding."),
        checkout_head => N__(
  "If the patch applies cleanly, the edited hunk will immediately be
  marked for discarding."),
@@@ -1081,7 -1097,7 +1081,7 @@@ EOF
  
        open $fh, '<', $hunkfile
                or die sprintf(__("failed to open hunk edit file for reading: %s"), $!);
-       my @newtext = grep { !/^$comment_line_char/ } <$fh>;
+       my @newtext = grep { !/^\Q$comment_line_char\E/ } <$fh>;
        close $fh;
        unlink $hunkfile;
  
@@@ -1136,6 -1152,7 +1136,7 @@@ sub prompt_yesno 
        while (1) {
                print colored $prompt_color, $prompt;
                my $line = prompt_single_character;
+               return undef unless defined $line;
                return 0 if $line =~ /^n/i;
                return 1 if $line =~ /^y/i;
        }
@@@ -1286,7 -1303,7 +1287,7 @@@ sub patch_update_cmd 
                }
                return 0;
        }
 -      if ($patch_mode) {
 +      if ($patch_mode_only) {
                @them = @mods;
        }
        else {
@@@ -1665,7 -1682,7 +1666,7 @@@ status        - show paths with change
  update        - add working tree state to the staged set of changes
  revert        - revert staged set of changes back to the HEAD version
  patch         - pick hunks and update selectively
 -diff        - view diff between HEAD and index
 +diff          - view diff between HEAD and index
  add untracked - add contents of untracked files to the staged set of changes
  EOF
  }
@@@ -1708,7 -1725,7 +1709,7 @@@ sub process_args 
                die sprintf(__("invalid argument %s, expecting --"),
                               $arg) unless $arg eq "--";
                %patch_mode_flavour = %{$patch_modes{$patch_mode}};
 -              $cmd = 1;
 +              $patch_mode_only = 1;
        }
        elsif ($arg ne "--") {
                die sprintf(__("invalid argument %s, expecting --"), $arg);
@@@ -1745,7 -1762,7 +1746,7 @@@ sub main_loop 
  
  process_args();
  refresh();
 -if ($cmd) {
 +if ($patch_mode_only) {
        patch_update_cmd();
  }
  else {
index 2ecb43a61652032862d5a264ede8af473ef345e1,2bfd41f06e4435607760dbe6d78ec72633e46aba..2f3e7cea64e897299d87196135032de22050354b
@@@ -380,101 -380,12 +380,109 @@@ test_expect_success 'patch mode ignore
        test_cmp expected diff
  '
  
 +test_expect_success 'diffs can be colorized' '
 +      git reset --hard &&
 +
 +      # force color even though the test script has no terminal
 +      test_config color.ui always &&
 +
 +      echo content >test &&
 +      printf y | git add -p >output 2>&1 &&
 +
 +      # We do not want to depend on the exact coloring scheme
 +      # git uses for diffs, so just check that we saw some kind of color.
 +      grep "$(printf "\\033")" output
 +'
 +
 +test_expect_success 'patch-mode via -i prompts for files' '
 +      git reset --hard &&
 +
 +      echo one >file &&
 +      echo two >test &&
 +      git add -i <<-\EOF &&
 +      patch
 +      test
 +
 +      y
 +      quit
 +      EOF
 +
 +      echo test >expect &&
 +      git diff --cached --name-only >actual &&
 +      test_cmp expect actual
 +'
 +
 +test_expect_success 'add -p handles globs' '
 +      git reset --hard &&
 +
 +      mkdir -p subdir &&
 +      echo base >one.c &&
 +      echo base >subdir/two.c &&
 +      git add "*.c" &&
 +      git commit -m base &&
 +
 +      echo change >one.c &&
 +      echo change >subdir/two.c &&
 +      git add -p "*.c" <<-\EOF &&
 +      y
 +      y
 +      EOF
 +
 +      cat >expect <<-\EOF &&
 +      one.c
 +      subdir/two.c
 +      EOF
 +      git diff --cached --name-only >actual &&
 +      test_cmp expect actual
 +'
 +
 +test_expect_success 'add -p handles relative paths' '
 +      git reset --hard &&
 +
 +      echo base >relpath.c &&
 +      git add "*.c" &&
 +      git commit -m relpath &&
 +
 +      echo change >relpath.c &&
 +      mkdir -p subdir &&
 +      git -C subdir add -p .. 2>error <<-\EOF &&
 +      y
 +      EOF
 +
 +      test_must_be_empty error &&
 +
 +      cat >expect <<-\EOF &&
 +      relpath.c
 +      EOF
 +      git diff --cached --name-only >actual &&
 +      test_cmp expect actual
 +'
 +
 +test_expect_success 'add -p does not expand argument lists' '
 +      git reset --hard &&
 +
 +      echo content >not-changed &&
 +      git add not-changed &&
 +      git commit -m "add not-changed file" &&
 +
 +      echo change >file &&
 +      GIT_TRACE=$(pwd)/trace.out git add -p . <<-\EOF &&
 +      y
 +      EOF
 +
 +      # we know that "file" must be mentioned since we actually
 +      # update it, but we want to be sure that our "." pathspec
 +      # was not expanded into the argument list of any command.
 +      # So look only for "not-changed".
 +      ! grep not-changed trace.out
 +'
 +
+ test_expect_success 'hunk-editing handles custom comment char' '
+       git reset --hard &&
+       echo change >>file &&
+       test_config core.commentChar "\$" &&
+       echo e | GIT_EDITOR=true git add -p &&
+       git diff --exit-code
+ '
  test_done