Merge branch 'add-p-in-c'

Out of all the patch series on the journey to provide `git add
--interactive` and `git add --patch` in a built-in versions, this is the
big one, as can be expected from the fact that the `git add --patch`
functionality makes up over half of the 1,800+ lines of
`git-add--interactive.perl`.

The two patches that stick out are of course the ones to implement hunk
splitting and hunk editing: these operations are fundamentally more
complicated, and less obvious, than the rest of the operations.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin
2019-03-28 13:49:54 +01:00
6 changed files with 1361 additions and 16 deletions

View File

@@ -850,6 +850,7 @@ LIB_H = $(shell $(FIND) . \
LIB_OBJS += abspath.o
LIB_OBJS += add-interactive.o
LIB_OBJS += add-patch.o
LIB_OBJS += advice.o
LIB_OBJS += alias.o
LIB_OBJS += alloc.o

View File

@@ -12,16 +12,6 @@
#include "argv-array.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)
@@ -38,7 +28,7 @@ static void init_color(struct repository *r, struct add_i_state *s,
free(key);
}
static int init_add_i_state(struct repository *r, struct add_i_state *s)
int init_add_i_state(struct repository *r, struct add_i_state *s)
{
const char *value;
@@ -57,6 +47,16 @@ static int init_add_i_state(struct repository *r, struct add_i_state *s)
init_color(r, s, "error", s->error_color, GIT_COLOR_BOLD_RED);
init_color(r, s, "reset", s->reset_color, GIT_COLOR_RESET);
strlcpy(s->fraginfo_color,
diff_get_color(s->use_color, DIFF_FRAGINFO), COLOR_MAXLEN);
strlcpy(s->context_color,
diff_get_color(s->use_color, DIFF_CONTEXT), COLOR_MAXLEN);
strlcpy(s->file_old_color,
diff_get_color(s->use_color, DIFF_FILE_OLD), COLOR_MAXLEN);
strlcpy(s->file_new_color,
diff_get_color(s->use_color, DIFF_FILE_NEW), COLOR_MAXLEN);
return 0;
}
@@ -831,14 +831,17 @@ static int run_patch(struct add_i_state *s, const struct pathspec *ps,
count = list_and_choose(items, selected, files->nr, s, opts);
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->nr; i++)
if (selected[i])
argv_array_push(&args, items[i]->name);
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);
}
free(selected);

View File

@@ -1,8 +1,36 @@
#ifndef ADD_INTERACTIVE_H
#define ADD_INTERACTIVE_H
#include "color.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];
char fraginfo_color[COLOR_MAXLEN];
char context_color[COLOR_MAXLEN];
char file_old_color[COLOR_MAXLEN];
char file_new_color[COLOR_MAXLEN];
};
int init_add_i_state(struct repository *r, struct add_i_state *s);
enum color_add_i {
COLOR_HEADER = 0,
COLOR_HELP,
COLOR_PROMPT,
COLOR_ERROR,
COLOR_RESET,
};
const char *get_add_i_color(enum color_add_i ix);
struct repository;
struct pathspec;
int run_add_i(struct repository *r, const struct pathspec *ps);
int run_add_p(struct repository *r, const struct pathspec *ps);
#endif

1277
add-patch.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -192,8 +192,14 @@ int run_add_interactive(const char *revision, const char *patch_mode,
git_config_get_bool("add.interactive.usebuiltin",
&use_builtin_add_i);
if (use_builtin_add_i == 1 && !patch_mode)
return !!run_add_i(the_repository, pathspec);
if (use_builtin_add_i == 1) {
if (!patch_mode)
return !!run_add_i(the_repository, pathspec);
if (strcmp(patch_mode, "--patch"))
die("'%s' not yet supported in the built-in add -p",
patch_mode);
return !!run_add_p(the_repository, pathspec);
}
argv_array_push(&argv, "add--interactive");
if (patch_mode)

View File

@@ -413,6 +413,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 &&
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
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 &&
Stage this hunk [y,n,q,a,d,K,g,/,e,?]? @@ -1,2 +1,3 @@
_10
+15
_20
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:
#