]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'js/builtin-add-i-cmds' into maint
authorJunio C Hamano <gitster@pobox.com>
Tue, 17 Mar 2020 22:02:20 +0000 (15:02 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 17 Mar 2020 22:02:20 +0000 (15:02 -0700)
Minor bugfixes to "git add -i" that has recently been rewritten in C.

* js/builtin-add-i-cmds:
  built-in add -i: accept open-ended ranges again
  built-in add -i: do not try to `patch`/`diff` an empty list of files

1  2 
add-interactive.c
t/t3701-add-interactive.sh

diff --combined add-interactive.c
index 6a5048c83e4d6f08ae3ecfdb6beab125cde10a05,396066e7246da7ddb0284f1f953104cfc04a593d..143e6947242115d75c2225c6771455111349cea7
  #include "dir.h"
  #include "run-command.h"
  
 -struct add_i_state {
 -      struct repository *r;
 -      int use_color;
 -      char header_color[COLOR_MAXLEN];
 -      char help_color[COLOR_MAXLEN];
 -      char prompt_color[COLOR_MAXLEN];
 -      char error_color[COLOR_MAXLEN];
 -      char reset_color[COLOR_MAXLEN];
 -};
 -
  static void init_color(struct repository *r, struct add_i_state *s,
                       const char *slot_name, char *dst,
                       const char *default_color)
@@@ -26,7 -36,7 +26,7 @@@
        free(key);
  }
  
 -static void init_add_i_state(struct add_i_state *s, struct repository *r)
 +void init_add_i_state(struct add_i_state *s, struct repository *r)
  {
        const char *value;
  
        init_color(r, s, "prompt", s->prompt_color, GIT_COLOR_BOLD_BLUE);
        init_color(r, s, "error", s->error_color, GIT_COLOR_BOLD_RED);
        init_color(r, s, "reset", s->reset_color, GIT_COLOR_RESET);
 +      init_color(r, s, "fraginfo", s->fraginfo_color,
 +                 diff_get_color(s->use_color, DIFF_FRAGINFO));
 +      init_color(r, s, "context", s->context_color,
 +              diff_get_color(s->use_color, DIFF_CONTEXT));
 +      init_color(r, s, "old", s->file_old_color,
 +              diff_get_color(s->use_color, DIFF_FILE_OLD));
 +      init_color(r, s, "new", s->file_new_color,
 +              diff_get_color(s->use_color, DIFF_FILE_NEW));
  }
  
  /*
@@@ -326,7 -328,10 +326,10 @@@ static ssize_t list_and_choose(struct a
                                if (endp == p + sep)
                                        to = from + 1;
                                else if (*endp == '-') {
-                                       to = strtoul(++endp, &endp, 10);
+                                       if (isdigit(*(++endp)))
+                                               to = strtoul(endp, &endp, 10);
+                                       else
+                                               to = items->items.nr;
                                        /* extra characters after the range? */
                                        if (endp != p + sep)
                                                from = -1;
@@@ -913,20 -918,17 +916,20 @@@ static int run_patch(struct add_i_stat
  
        opts->prompt = N_("Patch update");
        count = list_and_choose(s, files, opts);
-       if (count >= 0) {
+       if (count > 0) {
                struct argv_array args = ARGV_ARRAY_INIT;
 +              struct pathspec ps_selected = { 0 };
  
 -              argv_array_pushl(&args, "git", "add--interactive", "--patch",
 -                               "--", NULL);
                for (i = 0; i < files->items.nr; i++)
                        if (files->selected[i])
                                argv_array_push(&args,
                                                files->items.items[i].string);
 -              res = run_command_v_opt(args.argv, 0);
 +              parse_pathspec(&ps_selected,
 +                             PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
 +                             PATHSPEC_LITERAL_PATH, "", args.argv);
 +              res = run_add_p(s->r, &ps_selected);
                argv_array_clear(&args);
 +              clear_pathspec(&ps_selected);
        }
  
        return res;
@@@ -954,7 -956,7 +957,7 @@@ static int run_diff(struct add_i_state 
        opts->flags = IMMEDIATE;
        count = list_and_choose(s, files, opts);
        opts->flags = 0;
-       if (count >= 0) {
+       if (count > 0) {
                struct argv_array args = ARGV_ARRAY_INIT;
  
                argv_array_pushl(&args, "git", "diff", "-p", "--cached",
index 12ee321707a33bd8455fb30ea24c57d002c13b68,b02fe73631dc9e56827caa7a90e2b38ba4eb7c4c..2182b1c030b81ea45e439510a452d3e74250cae0
@@@ -23,17 -23,6 +23,17 @@@ diff_cmp () 
        test_cmp "$1.filtered" "$2.filtered"
  }
  
 +# This function uses a trick to manipulate the interactive add to use color:
 +# the `want_color()` function special-cases the situation where a pager was
 +# spawned and Git now wants to output colored text: to detect that situation,
 +# the environment variable `GIT_PAGER_IN_USE` is set. However, color is
 +# suppressed despite that environment variable if the `TERM` variable
 +# indicates a dumb terminal, so we set that variable, too.
 +
 +force_color () {
 +      env GIT_PAGER_IN_USE=true TERM=vt100 "$@"
 +}
 +
  test_expect_success 'setup (initial)' '
        echo content >file &&
        git add file &&
@@@ -68,6 -57,15 +68,15 @@@ test_expect_success 'revert works (init
        ! grep . output
  '
  
+ test_expect_success 'add untracked (multiple)' '
+       test_when_finished "git reset && rm [1-9]" &&
+       touch $(test_seq 9) &&
+       test_write_lines a "2-5 8-" | git add -i -- [1-9] &&
+       test_write_lines 2 3 4 5 8 9 >expected &&
+       git ls-files [1-9] >output &&
+       test_cmp expected output
+ '
  test_expect_success 'setup (commit)' '
        echo baseline >file &&
        git add file &&
@@@ -105,6 -103,7 +114,6 @@@ test_expect_success 'revert works (comm
        grep "unchanged *+3/-0 file" output
  '
  
 -
  test_expect_success 'setup expected' '
        cat >expected <<-\EOF
        EOF
@@@ -273,35 -272,6 +282,35 @@@ test_expect_success FILEMODE 'stage mod
  
  # end of tests disabled when filemode is not usable
  
 +test_expect_success 'different prompts for mode change/deleted' '
 +      git reset --hard &&
 +      >file &&
 +      >deleted &&
 +      git add --chmod=+x file deleted &&
 +      echo changed >file &&
 +      rm deleted &&
 +      test_write_lines n n n |
 +      git -c core.filemode=true add -p >actual &&
 +      sed -n "s/^\(([0-9/]*) Stage .*?\).*/\1/p" actual >actual.filtered &&
 +      cat >expect <<-\EOF &&
 +      (1/1) Stage deletion [y,n,q,a,d,?]?
 +      (1/2) Stage mode change [y,n,q,a,d,j,J,g,/,?]?
 +      (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]?
 +      EOF
 +      test_cmp expect actual.filtered
 +'
 +
 +test_expect_success 'correct message when there is nothing to do' '
 +      git reset --hard &&
 +      git add -p 2>err &&
 +      test_i18ngrep "No changes" err &&
 +      printf "\\0123" >binary &&
 +      git add binary &&
 +      printf "\\0abc" >binary &&
 +      git add -p 2>err &&
 +      test_i18ngrep "Only binary files changed" err
 +'
 +
  test_expect_success 'setup again' '
        git reset --hard &&
        test_chmod +x file &&
@@@ -413,36 -383,6 +422,36 @@@ test_expect_success 'split hunk setup' 
        test_write_lines 10 15 20 21 22 23 24 30 40 50 60 >test
  '
  
 +test_expect_success 'goto hunk' '
 +      test_when_finished "git reset" &&
 +      tr _ " " >expect <<-EOF &&
 +      (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? + 1:  -1,2 +1,3          +15
 +      _ 2:  -2,4 +3,8          +21
 +      go to which hunk? @@ -1,2 +1,3 @@
 +      _10
 +      +15
 +      _20
 +      (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?_
 +      EOF
 +      test_write_lines s y g 1 | git add -p >actual &&
 +      tail -n 7 <actual >actual.trimmed &&
 +      test_cmp expect actual.trimmed
 +'
 +
 +test_expect_success 'navigate to hunk via regex' '
 +      test_when_finished "git reset" &&
 +      tr _ " " >expect <<-EOF &&
 +      (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? @@ -1,2 +1,3 @@
 +      _10
 +      +15
 +      _20
 +      (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?_
 +      EOF
 +      test_write_lines s y /1,2 | git add -p >actual &&
 +      tail -n 5 <actual >actual.trimmed &&
 +      test_cmp expect actual.trimmed
 +'
 +
  test_expect_success 'split hunk "add -p (edit)"' '
        # Split, say Edit and do nothing.  Then:
        #
@@@ -472,40 -412,6 +481,40 @@@ test_expect_failure 'split hunk "add -
        ! grep "^+31" actual
  '
  
 +test_expect_success 'split hunk with incomplete line at end' '
 +      git reset --hard &&
 +      printf "missing LF" >>test &&
 +      git add test &&
 +      test_write_lines before 10 20 30 40 50 60 70 >test &&
 +      git grep --cached missing &&
 +      test_write_lines s n y q | git add -p &&
 +      test_must_fail git grep --cached missing &&
 +      git grep before &&
 +      test_must_fail git grep --cached before
 +'
 +
 +test_expect_failure 'edit, adding lines to the first hunk' '
 +      test_write_lines 10 11 20 30 40 50 51 60 >test &&
 +      git reset &&
 +      tr _ " " >patch <<-EOF &&
 +      @@ -1,5 +1,6 @@
 +      _10
 +      +11
 +      +12
 +      _20
 +      +21
 +      +22
 +      _30
 +      EOF
 +      # test sequence is s(plit), e(dit), n(o)
 +      # q n q q is there to make sure we exit at the end.
 +      printf "%s\n" s e n   q n q q |
 +      EDITOR=./fake_editor.sh git add -p 2>error &&
 +      test_must_be_empty error &&
 +      git diff --cached >actual &&
 +      grep "^+22" actual
 +'
 +
  test_expect_success 'patch mode ignores unmerged entries' '
        git reset --hard &&
        test_commit conflict &&
        diff_cmp expected diff
  '
  
 -test_expect_success TTY 'diffs can be colorized' '
 +test_expect_success 'diffs can be colorized' '
        git reset --hard &&
  
        echo content >test &&
 -      printf y | test_terminal git add -p >output 2>&1 &&
 +      printf y >y &&
 +      force_color git add -p >output 2>&1 <y &&
  
        # 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 TTY 'diffFilter filters diff' '
 +test_expect_success 'diffFilter filters diff' '
        git reset --hard &&
  
        echo content >test &&
        test_config interactive.diffFilter "sed s/^/foo:/" &&
 -      printf y | test_terminal git add -p >output 2>&1 &&
 +      printf y >y &&
 +      force_color git add -p >output 2>&1 <y &&
  
        # avoid depending on the exact coloring or content of the prompts,
        # and just make sure we saw our diff prefixed
        grep foo:.*content output
  '
  
 -test_expect_success TTY 'detect bogus diffFilter output' '
 +test_expect_success 'detect bogus diffFilter output' '
        git reset --hard &&
  
        echo content >test &&
        test_config interactive.diffFilter "echo too-short" &&
 -      printf y | test_must_fail test_terminal git add -p
 +      printf y >y &&
 +      test_must_fail force_color git add -p <y
 +'
 +
 +test_expect_success 'diff.algorithm is passed to `git diff-files`' '
 +      git reset --hard &&
 +
 +      >file &&
 +      git add file &&
 +      echo changed >file &&
 +      test_must_fail git -c diff.algorithm=bogus add -p 2>err &&
 +      test_i18ngrep "error: option diff-algorithm accepts " err
  '
  
  test_expect_success 'patch-mode via -i prompts for files' '
@@@ -783,7 -676,7 +792,7 @@@ test_expect_success 'show help from add
        <BOLD;BLUE>What now<RESET>>$SP
        Bye.
        EOF
 -      test_write_lines h | GIT_PAGER_IN_USE=true TERM=vt100 git add -i >actual.colored &&
 +      test_write_lines h | force_color git add -i >actual.colored &&
        test_decode_color <actual.colored >actual &&
        test_i18ncmp expect actual
  '