diff options
| author | Junio C Hamano <gitster@pobox.com> | 2026-03-03 11:08:13 -0800 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2026-03-03 11:08:13 -0800 |
| commit | a751e79acaf5a02cc24fa6b0b2656e13c57ad803 (patch) | |
| tree | 3bf8a7611463cb61ce1723b569119a22a2ea3039 /add-patch.c | |
| parent | f19f1b6cf37d22cf317b5c3b52a11eede1abe267 (diff) | |
| parent | 417b181f99ce53f50dea6541430cfe1f1f359a6a (diff) | |
| download | git-a751e79acaf5a02cc24fa6b0b2656e13c57ad803.tar.xz | |
Merge branch 'aa/add-p-no-auto-advance'
"git add -p" learned a new mode that allows the user to revisit a
file that was already dealt with.
* aa/add-p-no-auto-advance:
add-patch: allow interfile navigation when selecting hunks
add-patch: allow all-or-none application of patches
add-patch: modify patch_update_file() signature
interactive -p: add new `--auto-advance` flag
Diffstat (limited to 'add-patch.c')
| -rw-r--r-- | add-patch.c | 154 |
1 files changed, 112 insertions, 42 deletions
diff --git a/add-patch.c b/add-patch.c index 49d6911a32..8c03f710d3 100644 --- a/add-patch.c +++ b/add-patch.c @@ -1418,7 +1418,44 @@ N_("j - go to the next undecided hunk, roll over at the bottom\n" "e - manually edit the current hunk\n" "p - print the current hunk\n" "P - print the current hunk using the pager\n" - "? - print help\n"); + "> - go to the next file, roll over at the bottom\n" + "< - go to the previous file, roll over at the top\n" + "? - print help\n" + "HUNKS SUMMARY - Hunks: %d, USE: %d, SKIP: %d\n"); + +static void apply_patch(struct add_p_state *s, struct file_diff *file_diff) +{ + struct child_process cp = CHILD_PROCESS_INIT; + size_t j; + + /* Any hunk to be used? */ + for (j = 0; j < file_diff->hunk_nr; j++) + if (file_diff->hunk[j].use == USE_HUNK) + break; + + if (j < file_diff->hunk_nr || + (!file_diff->hunk_nr && file_diff->head.use == USE_HUNK)) { + /* At least one hunk selected: apply */ + strbuf_reset(&s->buf); + reassemble_patch(s, file_diff, 0, &s->buf); + + discard_index(s->s.r->index); + if (s->mode->apply_for_checkout) + apply_for_checkout(s, &s->buf, + s->mode->is_reverse); + else { + setup_child_process(s, &cp, "apply", NULL); + strvec_pushv(&cp.args, s->mode->apply_args); + if (pipe_command(&cp, s->buf.buf, s->buf.len, + NULL, 0, NULL, 0)) + error(_("'git apply' failed")); + } + if (repo_read_index(s->s.r) >= 0) + repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0, + 1, NULL, NULL, NULL); + } + +} static size_t dec_mod(size_t a, size_t m) { @@ -1441,20 +1478,21 @@ static bool get_first_undecided(const struct file_diff *file_diff, size_t *idx) return false; } -static int patch_update_file(struct add_p_state *s, - struct file_diff *file_diff) +static size_t patch_update_file(struct add_p_state *s, size_t idx) { size_t hunk_index = 0; ssize_t i, undecided_previous, undecided_next, rendered_hunk_index = -1; struct hunk *hunk; char ch; - struct child_process cp = CHILD_PROCESS_INIT; - int colored = !!s->colored.len, quit = 0, use_pager = 0; + int colored = !!s->colored.len, use_pager = 0; enum prompt_mode_type prompt_mode_type; + int all_decided = 0; + struct file_diff *file_diff = s->file_diff + idx; + size_t patch_update_resp = idx; /* Empty added files have no hunks */ if (!file_diff->hunk_nr && !file_diff->added) - return 0; + return patch_update_resp + 1; strbuf_reset(&s->buf); render_diff_header(s, file_diff, colored, &s->buf); @@ -1468,7 +1506,9 @@ static int patch_update_file(struct add_p_state *s, ALLOW_GOTO_NEXT_UNDECIDED_HUNK = 1 << 3, ALLOW_SEARCH_AND_GOTO = 1 << 4, ALLOW_SPLIT = 1 << 5, - ALLOW_EDIT = 1 << 6 + ALLOW_EDIT = 1 << 6, + ALLOW_GOTO_PREVIOUS_FILE = 1 << 7, + ALLOW_GOTO_NEXT_FILE = 1 << 8 } permitted = 0; if (hunk_index >= file_diff->hunk_nr) @@ -1499,9 +1539,14 @@ static int patch_update_file(struct add_p_state *s, /* Everything decided? */ if (undecided_previous < 0 && undecided_next < 0 && - hunk->use != UNDECIDED_HUNK) - break; - + hunk->use != UNDECIDED_HUNK) { + if (!s->s.auto_advance) + all_decided = 1; + else { + patch_update_resp++; + break; + } + } strbuf_reset(&s->buf); if (file_diff->hunk_nr) { if (rendered_hunk_index != hunk_index) { @@ -1549,6 +1594,14 @@ static int patch_update_file(struct add_p_state *s, permitted |= ALLOW_EDIT; strbuf_addstr(&s->buf, ",e"); } + if (!s->s.auto_advance && s->file_diff_nr > 1) { + permitted |= ALLOW_GOTO_NEXT_FILE; + strbuf_addstr(&s->buf, ",>"); + } + if (!s->s.auto_advance && s->file_diff_nr > 1) { + permitted |= ALLOW_GOTO_PREVIOUS_FILE; + strbuf_addstr(&s->buf, ",<"); + } strbuf_addstr(&s->buf, ",p,P"); } if (file_diff->deleted) @@ -1577,7 +1630,7 @@ static int patch_update_file(struct add_p_state *s, fputs(s->s.reset_color_interactive, stdout); fflush(stdout); if (read_single_character(s) == EOF) { - quit = 1; + patch_update_resp = s->file_diff_nr; break; } @@ -1623,8 +1676,30 @@ soft_increment: hunk->use = SKIP_HUNK; } } else if (ch == 'q') { - quit = 1; + patch_update_resp = s->file_diff_nr; break; + } else if (!s->s.auto_advance && s->answer.buf[0] == '>') { + if (permitted & ALLOW_GOTO_NEXT_FILE) { + if (patch_update_resp == s->file_diff_nr - 1) + patch_update_resp = 0; + else + patch_update_resp++; + break; + } else { + err(s, _("No next file")); + continue; + } + } else if (!s->s.auto_advance && s->answer.buf[0] == '<') { + if (permitted & ALLOW_GOTO_PREVIOUS_FILE) { + if (patch_update_resp == 0) + patch_update_resp = s->file_diff_nr - 1; + else + patch_update_resp--; + break; + } else { + err(s, _("No previous file")); + continue; + } } else if (s->answer.buf[0] == 'K') { if (permitted & ALLOW_GOTO_PREVIOUS_HUNK) hunk_index = dec_mod(hunk_index, @@ -1770,6 +1845,18 @@ soft_increment: * commands shown in the prompt that are not * always available. */ + if (all_decided && !strncmp(p, "HUNKS SUMMARY", 13)) { + int total = file_diff->hunk_nr, used = 0, skipped = 0; + + for (i = 0; i < file_diff->hunk_nr; i++) { + if (file_diff->hunk[i].use == USE_HUNK) + used += 1; + if (file_diff->hunk[i].use == SKIP_HUNK) + skipped += 1; + } + color_fprintf_ln(stdout, s->s.help_color, _(p), + total, used, skipped); + } if (*p != '?' && !strchr(s->buf.buf, *p)) continue; @@ -1782,35 +1869,11 @@ soft_increment: } } - /* Any hunk to be used? */ - for (i = 0; i < file_diff->hunk_nr; i++) - if (file_diff->hunk[i].use == USE_HUNK) - break; - - if (i < file_diff->hunk_nr || - (!file_diff->hunk_nr && file_diff->head.use == USE_HUNK)) { - /* At least one hunk selected: apply */ - strbuf_reset(&s->buf); - reassemble_patch(s, file_diff, 0, &s->buf); - - discard_index(s->s.r->index); - if (s->mode->apply_for_checkout) - apply_for_checkout(s, &s->buf, - s->mode->is_reverse); - else { - setup_child_process(s, &cp, "apply", NULL); - strvec_pushv(&cp.args, s->mode->apply_args); - if (pipe_command(&cp, s->buf.buf, s->buf.len, - NULL, 0, NULL, 0)) - error(_("'git apply' failed")); - } - if (repo_read_index(s->s.r) >= 0) - repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0, - 1, NULL, NULL, NULL); - } + if (s->s.auto_advance) + apply_patch(s, file_diff); putchar('\n'); - return quit; + return patch_update_resp; } int run_add_p(struct repository *r, enum add_p_mode mode, @@ -1859,11 +1922,18 @@ int run_add_p(struct repository *r, enum add_p_mode mode, return -1; } - for (i = 0; i < s.file_diff_nr; i++) - if (s.file_diff[i].binary && !s.file_diff[i].hunk_nr) + for (i = 0; i < s.file_diff_nr;) { + if (s.file_diff[i].binary && !s.file_diff[i].hunk_nr) { binary_count++; - else if (patch_update_file(&s, s.file_diff + i)) + i++; + continue; + } + if ((i = patch_update_file(&s, i)) == s.file_diff_nr) break; + } + if (!s.s.auto_advance) + for (i = 0; i < s.file_diff_nr; i++) + apply_patch(&s, s.file_diff + i); if (s.file_diff_nr == 0) err(&s, _("No changes.")); |
