add -p: show user's hunk decision when selecting hunks
When a user is interactively deciding which hunks to use or skip for staging, unstaging, stashing etc, there is no way to know the decision previously chosen for a hunk when navigating through the previous and next hunks using K/J respectively. Improve the UI to explicitly show if a user has previously decided to use a hunk (by pressing 'y') or skip the hunk (by pressing 'n'). This will improve clarity when and aid the navigation process for the user. Reported-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Abraham Samuel Adekunle <abrahamadekunle50@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Abraham Samuel Adekunle committed
Jan 8, 2026 at 16:07 UTC
8cafc305e22a59efb92472d4132616e24d3184c6
2 files changed
+53
-46
add-patch.c
+44
-37
@@ -42,10 +42,10 @@ static struct patch_mode patch_mode_add = {
42
.apply_args = { "--cached", NULL },
43
.apply_check_args = { "--cached", NULL },
44
.prompt_mode = {
45
- N_("Stage mode change [y,n,q,a,d%s,?]? "),
46
- N_("Stage deletion [y,n,q,a,d%s,?]? "),
47
- N_("Stage addition [y,n,q,a,d%s,?]? "),
48
- N_("Stage this hunk [y,n,q,a,d%s,?]? ")
45
+ N_("Stage mode change%s [y,n,q,a,d%s,?]? "),
46
+ N_("Stage deletion%s [y,n,q,a,d%s,?]? "),
47
+ N_("Stage addition%s [y,n,q,a,d%s,?]? "),
48
+ N_("Stage this hunk%s [y,n,q,a,d%s,?]? ")
49
},
50
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
51
"will immediately be marked for staging."),
@@ -64,10 +64,10 @@ static struct patch_mode patch_mode_stash = {
64
.apply_args = { "--cached", NULL },
65
.apply_check_args = { "--cached", NULL },
66
.prompt_mode = {
67
- N_("Stash mode change [y,n,q,a,d%s,?]? "),
68
- N_("Stash deletion [y,n,q,a,d%s,?]? "),
69
- N_("Stash addition [y,n,q,a,d%s,?]? "),
70
- N_("Stash this hunk [y,n,q,a,d%s,?]? "),
67
+ N_("Stash mode change%s [y,n,q,a,d%s,?]? "),
68
+ N_("Stash deletion%s [y,n,q,a,d%s,?]? "),
69
+ N_("Stash addition%s [y,n,q,a,d%s,?]? "),
70
+ N_("Stash this hunk%s [y,n,q,a,d%s,?]? "),
71
},
72
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
73
"will immediately be marked for stashing."),
@@ -88,10 +88,10 @@ static struct patch_mode patch_mode_reset_head = {
88
.is_reverse = 1,
89
.index_only = 1,
90
.prompt_mode = {
91
- N_("Unstage mode change [y,n,q,a,d%s,?]? "),
92
- N_("Unstage deletion [y,n,q,a,d%s,?]? "),
93
- N_("Unstage addition [y,n,q,a,d%s,?]? "),
94
- N_("Unstage this hunk [y,n,q,a,d%s,?]? "),
91
+ N_("Unstage mode change%s [y,n,q,a,d%s,?]? "),
92
+ N_("Unstage deletion%s [y,n,q,a,d%s,?]? "),
93
+ N_("Unstage addition%s [y,n,q,a,d%s,?]? "),
94
+ N_("Unstage this hunk%s [y,n,q,a,d%s,?]? "),
95
},
96
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
97
"will immediately be marked for unstaging."),
@@ -111,10 +111,10 @@ static struct patch_mode patch_mode_reset_nothead = {
111
.apply_check_args = { "--cached", NULL },
112
.index_only = 1,
113
.prompt_mode = {
114
- N_("Apply mode change to index [y,n,q,a,d%s,?]? "),
115
- N_("Apply deletion to index [y,n,q,a,d%s,?]? "),
116
- N_("Apply addition to index [y,n,q,a,d%s,?]? "),
117
- N_("Apply this hunk to index [y,n,q,a,d%s,?]? "),
114
+ N_("Apply mode change to index%s [y,n,q,a,d%s,?]? "),
115
+ N_("Apply deletion to index%s [y,n,q,a,d%s,?]? "),
116
+ N_("Apply addition to index%s [y,n,q,a,d%s,?]? "),
117
+ N_("Apply this hunk to index%s [y,n,q,a,d%s,?]? "),
118
},
119
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
120
"will immediately be marked for applying."),
@@ -134,10 +134,10 @@ static struct patch_mode patch_mode_checkout_index = {
134
.apply_check_args = { "-R", NULL },
135
.is_reverse = 1,
136
.prompt_mode = {
137
- N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
138
- N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
139
- N_("Discard addition from worktree [y,n,q,a,d%s,?]? "),
140
- N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
137
+ N_("Discard mode change from worktree%s [y,n,q,a,d%s,?]? "),
138
+ N_("Discard deletion from worktree%s [y,n,q,a,d%s,?]? "),
139
+ N_("Discard addition from worktree%s [y,n,q,a,d%s,?]? "),
140
+ N_("Discard this hunk from worktree%s [y,n,q,a,d%s,?]? "),
141
},
142
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
143
"will immediately be marked for discarding."),
@@ -157,10 +157,10 @@ static struct patch_mode patch_mode_checkout_head = {
157
.apply_check_args = { "-R", NULL },
158
.is_reverse = 1,
159
.prompt_mode = {
160
- N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
161
- N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
162
- N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
163
- N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
160
+ N_("Discard mode change from index and worktree%s [y,n,q,a,d%s,?]? "),
161
+ N_("Discard deletion from index and worktree%s [y,n,q,a,d%s,?]? "),
162
+ N_("Discard addition from index and worktree%s [y,n,q,a,d%s,?]? "),
163
+ N_("Discard this hunk from index and worktree%s [y,n,q,a,d%s,?]? "),
164
},
165
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
166
"will immediately be marked for discarding."),
@@ -179,10 +179,10 @@ static struct patch_mode patch_mode_checkout_nothead = {
179
.apply_for_checkout = 1,
180
.apply_check_args = { NULL },
181
.prompt_mode = {
182
- N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
183
- N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
184
- N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
185
- N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
182
+ N_("Apply mode change to index and worktree%s [y,n,q,a,d%s,?]? "),
183
+ N_("Apply deletion to index and worktree%s [y,n,q,a,d%s,?]? "),
184
+ N_("Apply addition to index and worktree%s [y,n,q,a,d%s,?]? "),
185
+ N_("Apply this hunk to index and worktree%s [y,n,q,a,d%s,?]? "),
186
},
187
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
188
"will immediately be marked for applying."),
@@ -202,10 +202,10 @@ static struct patch_mode patch_mode_worktree_head = {
202
.apply_check_args = { "-R", NULL },
203
.is_reverse = 1,
204
.prompt_mode = {
205
- N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
206
- N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
207
- N_("Discard addition from worktree [y,n,q,a,d%s,?]? "),
208
- N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
205
+ N_("Discard mode change from worktree%s [y,n,q,a,d%s,?]? "),
206
+ N_("Discard deletion from worktree%s [y,n,q,a,d%s,?]? "),
207
+ N_("Discard addition from worktree%s [y,n,q,a,d%s,?]? "),
208
+ N_("Discard this hunk from worktree%s [y,n,q,a,d%s,?]? "),
209
},
210
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
211
"will immediately be marked for discarding."),
@@ -224,10 +224,10 @@ static struct patch_mode patch_mode_worktree_nothead = {
224
.apply_args = { NULL },
225
.apply_check_args = { NULL },
226
.prompt_mode = {
227
- N_("Apply mode change to worktree [y,n,q,a,d%s,?]? "),
228
- N_("Apply deletion to worktree [y,n,q,a,d%s,?]? "),
229
- N_("Apply addition to worktree [y,n,q,a,d%s,?]? "),
230
- N_("Apply this hunk to worktree [y,n,q,a,d%s,?]? "),
227
+ N_("Apply mode change to worktree%s [y,n,q,a,d%s,?]? "),
228
+ N_("Apply deletion to worktree%s [y,n,q,a,d%s,?]? "),
229
+ N_("Apply addition to worktree%s [y,n,q,a,d%s,?]? "),
230
+ N_("Apply this hunk to worktree%s [y,n,q,a,d%s,?]? "),
231
},
232
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
233
"will immediately be marked for applying."),
@@ -1460,6 +1460,7 @@ static int patch_update_file(struct add_p_state *s,
1460
render_diff_header(s, file_diff, colored, &s->buf);
1461
fputs(s->buf.buf, stdout);
1462
for (;;) {
1463
+ const char *hunk_use_decision = "";
1464
enum {
1465
ALLOW_GOTO_PREVIOUS_HUNK = 1 << 0,
1466
ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK = 1 << 1,
@@ -1564,8 +1565,14 @@ static int patch_update_file(struct add_p_state *s,
1565
(uintmax_t)(file_diff->hunk_nr
1566
? file_diff->hunk_nr
1567
: 1));
1568
+ if (hunk->use != UNDECIDED_HUNK) {
1569
+ if (hunk->use == USE_HUNK)
1570
+ hunk_use_decision = _(" (was: y)");
1571
+ else
1572
+ hunk_use_decision = _(" (was: n)");
1573
+ }
1574
printf(_(s->mode->prompt_mode[prompt_mode_type]),
1568
- s->buf.buf);
1575
+ hunk_use_decision, s->buf.buf);
1576
if (*s->s.reset_color_interactive)
1577
fputs(s->s.reset_color_interactive, stdout);
1578
fflush(stdout);
t/t3701-add-interactive.sh
+9
-9
@@ -527,7 +527,7 @@ test_expect_success 'goto hunk 1 with "g 1"' '
527
_10
528
+15
529
_20
530
- (1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]?_
530
+ (1/2) Stage this hunk (was: y) [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]?_
531
EOF
532
test_write_lines s y g 1 | git add -p >actual &&
533
tail -n 7 <actual >actual.trimmed &&
@@ -540,7 +540,7 @@ test_expect_success 'goto hunk 1 with "g1"' '
540
_10
541
+15
542
_20
543
- (1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]?_
543
+ (1/2) Stage this hunk (was: y) [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]?_
544
EOF
545
test_write_lines s y g1 | git add -p >actual &&
546
tail -n 4 <actual >actual.trimmed &&
@@ -554,7 +554,7 @@ test_expect_success 'navigate to hunk via regex /pattern' '
554
_10
555
+15
556
_20
557
- (1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]?_
557
+ (1/2) Stage this hunk (was: y) [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]?_
558
EOF
559
test_write_lines s y /1,2 | git add -p >actual &&
560
tail -n 5 <actual >actual.trimmed &&
@@ -567,7 +567,7 @@ test_expect_success 'navigate to hunk via regex / pattern' '
567
_10
568
+15
569
_20
570
- (1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]?_
570
+ (1/2) Stage this hunk (was: y) [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]?_
571
EOF
572
test_write_lines s y / 1,2 | git add -p >actual &&
573
tail -n 4 <actual >actual.trimmed &&
@@ -579,11 +579,11 @@ test_expect_success 'print again the hunk' '
579
tr _ " " >expect <<-EOF &&
580
+15
581
20
582
- (1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]? @@ -1,2 +1,3 @@
582
+ (1/2) Stage this hunk (was: y) [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]? @@ -1,2 +1,3 @@
583
10
584
+15
585
20
586
- (1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]?_
586
+ (1/2) Stage this hunk (was: y) [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]?_
587
EOF
588
test_write_lines s y g 1 p | git add -p >actual &&
589
tail -n 7 <actual >actual.trimmed &&
@@ -595,11 +595,11 @@ test_expect_success TTY 'print again the hunk (PAGER)' '
595
cat >expect <<-EOF &&
596
<GREEN>+<RESET><GREEN>15<RESET>
597
20<RESET>
598
- <BOLD;BLUE>(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]? <RESET>PAGER <CYAN>@@ -1,2 +1,3 @@<RESET>
598
+ <BOLD;BLUE>(1/2) Stage this hunk (was: y) [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]? <RESET>PAGER <CYAN>@@ -1,2 +1,3 @@<RESET>
599
PAGER 10<RESET>
600
PAGER <GREEN>+<RESET><GREEN>15<RESET>
601
PAGER 20<RESET>
602
- <BOLD;BLUE>(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]? <RESET>
602
+ <BOLD;BLUE>(1/2) Stage this hunk (was: y) [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]? <RESET>
603
EOF
604
test_write_lines s y g 1 P |
605
(
@@ -810,7 +810,7 @@ test_expect_success 'colors can be overridden' '
810
<BOLD>-old<RESET>
811
<BLUE>+new<RESET>
812
<CYAN> more-context<RESET>
813
- <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]? <RESET>
813
+ <YELLOW>(1/2) Stage this hunk (was: y) [y,n,q,a,d,k,K,j,J,g,/,e,p,P,?]? <RESET>
814
EOF
815
test_cmp expect actual
816
'