зеркало из https://github.com/microsoft/git.git
built-in add -p: implement the 'g' ("goto") command
With this patch, it is now possible to see a summary of the available hunks and to navigate between them (by number). A test is added to verify that this behavior matches the one of the Perl version of `git add -p`. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
bcdd297b78
Коммит
9254bdfb4f
88
add-patch.c
88
add-patch.c
|
@ -955,6 +955,54 @@ static int edit_hunk_loop(struct add_p_state *s,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SUMMARY_HEADER_WIDTH 20
|
||||||
|
#define SUMMARY_LINE_WIDTH 80
|
||||||
|
static void summarize_hunk(struct add_p_state *s, struct hunk *hunk,
|
||||||
|
struct strbuf *out)
|
||||||
|
{
|
||||||
|
struct hunk_header *header = &hunk->header;
|
||||||
|
struct strbuf *plain = &s->plain;
|
||||||
|
size_t len = out->len, i;
|
||||||
|
|
||||||
|
strbuf_addf(out, " -%lu,%lu +%lu,%lu ",
|
||||||
|
header->old_offset, header->old_count,
|
||||||
|
header->new_offset, header->new_count);
|
||||||
|
if (out->len - len < SUMMARY_HEADER_WIDTH)
|
||||||
|
strbuf_addchars(out, ' ',
|
||||||
|
SUMMARY_HEADER_WIDTH + len - out->len);
|
||||||
|
for (i = hunk->start; i < hunk->end; i = find_next_line(plain, i))
|
||||||
|
if (plain->buf[i] != ' ')
|
||||||
|
break;
|
||||||
|
if (i < hunk->end)
|
||||||
|
strbuf_add(out, plain->buf + i, find_next_line(plain, i) - i);
|
||||||
|
if (out->len - len > SUMMARY_LINE_WIDTH)
|
||||||
|
strbuf_setlen(out, len + SUMMARY_LINE_WIDTH);
|
||||||
|
strbuf_complete_line(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DISPLAY_HUNKS_LINES 20
|
||||||
|
static size_t display_hunks(struct add_p_state *s,
|
||||||
|
struct file_diff *file_diff, size_t start_index)
|
||||||
|
{
|
||||||
|
size_t end_index = start_index + DISPLAY_HUNKS_LINES;
|
||||||
|
|
||||||
|
if (end_index > file_diff->hunk_nr)
|
||||||
|
end_index = file_diff->hunk_nr;
|
||||||
|
|
||||||
|
while (start_index < end_index) {
|
||||||
|
struct hunk *hunk = file_diff->hunk + start_index++;
|
||||||
|
|
||||||
|
strbuf_reset(&s->buf);
|
||||||
|
strbuf_addf(&s->buf, "%c%2d: ", hunk->use == USE_HUNK ? '+'
|
||||||
|
: hunk->use == SKIP_HUNK ? '-' : ' ',
|
||||||
|
(int)start_index);
|
||||||
|
summarize_hunk(s, hunk, &s->buf);
|
||||||
|
fputs(s->buf.buf, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
return end_index;
|
||||||
|
}
|
||||||
|
|
||||||
static const char help_patch_text[] =
|
static const char help_patch_text[] =
|
||||||
N_("y - stage this hunk\n"
|
N_("y - stage this hunk\n"
|
||||||
"n - do not stage this hunk\n"
|
"n - do not stage this hunk\n"
|
||||||
|
@ -964,6 +1012,7 @@ N_("y - stage this hunk\n"
|
||||||
"J - leave this hunk undecided, see next hunk\n"
|
"J - leave this hunk undecided, see next hunk\n"
|
||||||
"k - leave this hunk undecided, see previous undecided hunk\n"
|
"k - leave this hunk undecided, see previous undecided hunk\n"
|
||||||
"K - leave this hunk undecided, see previous hunk\n"
|
"K - leave this hunk undecided, see previous hunk\n"
|
||||||
|
"g - select a hunk to go to\n"
|
||||||
"s - split the current hunk into smaller hunks\n"
|
"s - split the current hunk into smaller hunks\n"
|
||||||
"e - manually edit the current hunk\n"
|
"e - manually edit the current hunk\n"
|
||||||
"? - print help\n");
|
"? - print help\n");
|
||||||
|
@ -1022,6 +1071,8 @@ static int patch_update_file(struct add_p_state *s,
|
||||||
strbuf_addstr(&s->buf, ",j");
|
strbuf_addstr(&s->buf, ",j");
|
||||||
if (hunk_index + 1 < file_diff->hunk_nr)
|
if (hunk_index + 1 < file_diff->hunk_nr)
|
||||||
strbuf_addstr(&s->buf, ",J");
|
strbuf_addstr(&s->buf, ",J");
|
||||||
|
if (file_diff->hunk_nr > 1)
|
||||||
|
strbuf_addstr(&s->buf, ",g");
|
||||||
if (hunk->splittable_into > 1)
|
if (hunk->splittable_into > 1)
|
||||||
strbuf_addstr(&s->buf, ",s");
|
strbuf_addstr(&s->buf, ",s");
|
||||||
if (hunk_index + 1 > file_diff->mode_change &&
|
if (hunk_index + 1 > file_diff->mode_change &&
|
||||||
|
@ -1089,6 +1140,43 @@ soft_increment:
|
||||||
hunk_index = undecided_next;
|
hunk_index = undecided_next;
|
||||||
else
|
else
|
||||||
err(s, _("No next hunk"));
|
err(s, _("No next hunk"));
|
||||||
|
} else if (s->answer.buf[0] == 'g') {
|
||||||
|
char *pend;
|
||||||
|
unsigned long response;
|
||||||
|
|
||||||
|
if (file_diff->hunk_nr < 2) {
|
||||||
|
err(s, _("No other hunks to goto"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
strbuf_remove(&s->answer, 0, 1);
|
||||||
|
strbuf_trim(&s->answer);
|
||||||
|
i = hunk_index - DISPLAY_HUNKS_LINES / 2;
|
||||||
|
if (i < file_diff->mode_change)
|
||||||
|
i = file_diff->mode_change;
|
||||||
|
while (s->answer.len == 0) {
|
||||||
|
i = display_hunks(s, file_diff, i);
|
||||||
|
printf("%s", i < file_diff->hunk_nr ?
|
||||||
|
_("go to which hunk (<ret> to see "
|
||||||
|
"more)? ") : _("go to which hunk? "));
|
||||||
|
fflush(stdout);
|
||||||
|
if (strbuf_getline(&s->answer,
|
||||||
|
stdin) == EOF)
|
||||||
|
break;
|
||||||
|
strbuf_trim_trailing_newline(&s->answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
strbuf_trim(&s->answer);
|
||||||
|
response = strtoul(s->answer.buf, &pend, 10);
|
||||||
|
if (*pend || pend == s->answer.buf)
|
||||||
|
err(s, _("Invalid number: '%s'"),
|
||||||
|
s->answer.buf);
|
||||||
|
else if (0 < response && response <= file_diff->hunk_nr)
|
||||||
|
hunk_index = response - 1;
|
||||||
|
else
|
||||||
|
err(s, Q_("Sorry, only %d hunk available.",
|
||||||
|
"Sorry, only %d hunks available.",
|
||||||
|
file_diff->hunk_nr),
|
||||||
|
(int)file_diff->hunk_nr);
|
||||||
} else if (s->answer.buf[0] == 's') {
|
} else if (s->answer.buf[0] == 's') {
|
||||||
size_t splittable_into = hunk->splittable_into;
|
size_t splittable_into = hunk->splittable_into;
|
||||||
if (splittable_into < 2)
|
if (splittable_into < 2)
|
||||||
|
|
|
@ -413,6 +413,22 @@ test_expect_success 'split hunk setup' '
|
||||||
test_write_lines 10 15 20 21 22 23 24 30 40 50 60 >test
|
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 'split hunk "add -p (edit)"' '
|
test_expect_success 'split hunk "add -p (edit)"' '
|
||||||
# Split, say Edit and do nothing. Then:
|
# Split, say Edit and do nothing. Then:
|
||||||
#
|
#
|
||||||
|
|
Загрузка…
Ссылка в новой задаче