Imported Upstream version 2.25.0
[platform/upstream/git.git] / add-patch.c
1 #include "cache.h"
2 #include "add-interactive.h"
3 #include "strbuf.h"
4 #include "run-command.h"
5 #include "argv-array.h"
6 #include "pathspec.h"
7 #include "color.h"
8 #include "diff.h"
9
10 enum prompt_mode_type {
11         PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK
12 };
13
14 static const char *prompt_mode[] = {
15         N_("Stage mode change [y,n,a,q,d%s,?]? "),
16         N_("Stage deletion [y,n,a,q,d%s,?]? "),
17         N_("Stage this hunk [y,n,a,q,d%s,?]? ")
18 };
19
20 struct hunk_header {
21         unsigned long old_offset, old_count, new_offset, new_count;
22         /*
23          * Start/end offsets to the extra text after the second `@@` in the
24          * hunk header, e.g. the function signature. This is expected to
25          * include the newline.
26          */
27         size_t extra_start, extra_end, colored_extra_start, colored_extra_end;
28 };
29
30 struct hunk {
31         size_t start, end, colored_start, colored_end, splittable_into;
32         ssize_t delta;
33         enum { UNDECIDED_HUNK = 0, SKIP_HUNK, USE_HUNK } use;
34         struct hunk_header header;
35 };
36
37 struct add_p_state {
38         struct add_i_state s;
39         struct strbuf answer, buf;
40
41         /* parsed diff */
42         struct strbuf plain, colored;
43         struct file_diff {
44                 struct hunk head;
45                 struct hunk *hunk;
46                 size_t hunk_nr, hunk_alloc;
47                 unsigned deleted:1, mode_change:1,binary:1;
48         } *file_diff;
49         size_t file_diff_nr;
50 };
51
52 static void err(struct add_p_state *s, const char *fmt, ...)
53 {
54         va_list args;
55
56         va_start(args, fmt);
57         fputs(s->s.error_color, stderr);
58         vfprintf(stderr, fmt, args);
59         fputs(s->s.reset_color, stderr);
60         fputc('\n', stderr);
61         va_end(args);
62 }
63
64 static void setup_child_process(struct add_p_state *s,
65                                 struct child_process *cp, ...)
66 {
67         va_list ap;
68         const char *arg;
69
70         va_start(ap, cp);
71         while ((arg = va_arg(ap, const char *)))
72                 argv_array_push(&cp->args, arg);
73         va_end(ap);
74
75         cp->git_cmd = 1;
76         argv_array_pushf(&cp->env_array,
77                          INDEX_ENVIRONMENT "=%s", s->s.r->index_file);
78 }
79
80 static int parse_range(const char **p,
81                        unsigned long *offset, unsigned long *count)
82 {
83         char *pend;
84
85         *offset = strtoul(*p, &pend, 10);
86         if (pend == *p)
87                 return -1;
88         if (*pend != ',') {
89                 *count = 1;
90                 *p = pend;
91                 return 0;
92         }
93         *count = strtoul(pend + 1, (char **)p, 10);
94         return *p == pend + 1 ? -1 : 0;
95 }
96
97 static int parse_hunk_header(struct add_p_state *s, struct hunk *hunk)
98 {
99         struct hunk_header *header = &hunk->header;
100         const char *line = s->plain.buf + hunk->start, *p = line;
101         char *eol = memchr(p, '\n', s->plain.len - hunk->start);
102
103         if (!eol)
104                 eol = s->plain.buf + s->plain.len;
105
106         if (!skip_prefix(p, "@@ -", &p) ||
107             parse_range(&p, &header->old_offset, &header->old_count) < 0 ||
108             !skip_prefix(p, " +", &p) ||
109             parse_range(&p, &header->new_offset, &header->new_count) < 0 ||
110             !skip_prefix(p, " @@", &p))
111                 return error(_("could not parse hunk header '%.*s'"),
112                              (int)(eol - line), line);
113
114         hunk->start = eol - s->plain.buf + (*eol == '\n');
115         header->extra_start = p - s->plain.buf;
116         header->extra_end = hunk->start;
117
118         if (!s->colored.len) {
119                 header->colored_extra_start = header->colored_extra_end = 0;
120                 return 0;
121         }
122
123         /* Now find the extra text in the colored diff */
124         line = s->colored.buf + hunk->colored_start;
125         eol = memchr(line, '\n', s->colored.len - hunk->colored_start);
126         if (!eol)
127                 eol = s->colored.buf + s->colored.len;
128         p = memmem(line, eol - line, "@@ -", 4);
129         if (!p)
130                 return error(_("could not parse colored hunk header '%.*s'"),
131                              (int)(eol - line), line);
132         p = memmem(p + 4, eol - p - 4, " @@", 3);
133         if (!p)
134                 return error(_("could not parse colored hunk header '%.*s'"),
135                              (int)(eol - line), line);
136         hunk->colored_start = eol - s->colored.buf + (*eol == '\n');
137         header->colored_extra_start = p + 3 - s->colored.buf;
138         header->colored_extra_end = hunk->colored_start;
139
140         return 0;
141 }
142
143 static int is_octal(const char *p, size_t len)
144 {
145         if (!len)
146                 return 0;
147
148         while (len--)
149                 if (*p < '0' || *(p++) > '7')
150                         return 0;
151         return 1;
152 }
153
154 static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
155 {
156         struct argv_array args = ARGV_ARRAY_INIT;
157         struct strbuf *plain = &s->plain, *colored = NULL;
158         struct child_process cp = CHILD_PROCESS_INIT;
159         char *p, *pend, *colored_p = NULL, *colored_pend = NULL, marker = '\0';
160         size_t file_diff_alloc = 0, i, color_arg_index;
161         struct file_diff *file_diff = NULL;
162         struct hunk *hunk = NULL;
163         int res;
164
165         /* Use `--no-color` explicitly, just in case `diff.color = always`. */
166         argv_array_pushl(&args, "diff-files", "-p", "--no-color", "--", NULL);
167         color_arg_index = args.argc - 2;
168         for (i = 0; i < ps->nr; i++)
169                 argv_array_push(&args, ps->items[i].original);
170
171         setup_child_process(s, &cp, NULL);
172         cp.argv = args.argv;
173         res = capture_command(&cp, plain, 0);
174         if (res) {
175                 argv_array_clear(&args);
176                 return error(_("could not parse diff"));
177         }
178         if (!plain->len) {
179                 argv_array_clear(&args);
180                 return 0;
181         }
182         strbuf_complete_line(plain);
183
184         if (want_color_fd(1, -1)) {
185                 struct child_process colored_cp = CHILD_PROCESS_INIT;
186
187                 setup_child_process(s, &colored_cp, NULL);
188                 xsnprintf((char *)args.argv[color_arg_index], 8, "--color");
189                 colored_cp.argv = args.argv;
190                 colored = &s->colored;
191                 res = capture_command(&colored_cp, colored, 0);
192                 argv_array_clear(&args);
193                 if (res)
194                         return error(_("could not parse colored diff"));
195                 strbuf_complete_line(colored);
196                 colored_p = colored->buf;
197                 colored_pend = colored_p + colored->len;
198         }
199         argv_array_clear(&args);
200
201         /* parse files and hunks */
202         p = plain->buf;
203         pend = p + plain->len;
204         while (p != pend) {
205                 char *eol = memchr(p, '\n', pend - p);
206                 const char *deleted = NULL, *mode_change = NULL;
207
208                 if (!eol)
209                         eol = pend;
210
211                 if (starts_with(p, "diff ")) {
212                         s->file_diff_nr++;
213                         ALLOC_GROW(s->file_diff, s->file_diff_nr,
214                                    file_diff_alloc);
215                         file_diff = s->file_diff + s->file_diff_nr - 1;
216                         memset(file_diff, 0, sizeof(*file_diff));
217                         hunk = &file_diff->head;
218                         hunk->start = p - plain->buf;
219                         if (colored_p)
220                                 hunk->colored_start = colored_p - colored->buf;
221                         marker = '\0';
222                 } else if (p == plain->buf)
223                         BUG("diff starts with unexpected line:\n"
224                             "%.*s\n", (int)(eol - p), p);
225                 else if (file_diff->deleted)
226                         ; /* keep the rest of the file in a single "hunk" */
227                 else if (starts_with(p, "@@ ") ||
228                          (hunk == &file_diff->head &&
229                           skip_prefix(p, "deleted file", &deleted))) {
230                         if (marker == '-' || marker == '+')
231                                 /*
232                                  * Should not happen; previous hunk did not end
233                                  * in a context line? Handle it anyway.
234                                  */
235                                 hunk->splittable_into++;
236
237                         file_diff->hunk_nr++;
238                         ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr,
239                                    file_diff->hunk_alloc);
240                         hunk = file_diff->hunk + file_diff->hunk_nr - 1;
241                         memset(hunk, 0, sizeof(*hunk));
242
243                         hunk->start = p - plain->buf;
244                         if (colored)
245                                 hunk->colored_start = colored_p - colored->buf;
246
247                         if (deleted)
248                                 file_diff->deleted = 1;
249                         else if (parse_hunk_header(s, hunk) < 0)
250                                 return -1;
251
252                         /*
253                          * Start counting into how many hunks this one can be
254                          * split
255                          */
256                         marker = *p;
257                 } else if (hunk == &file_diff->head &&
258                            skip_prefix(p, "old mode ", &mode_change) &&
259                            is_octal(mode_change, eol - mode_change)) {
260                         if (file_diff->mode_change)
261                                 BUG("double mode change?\n\n%.*s",
262                                     (int)(eol - plain->buf), plain->buf);
263                         if (file_diff->hunk_nr++)
264                                 BUG("mode change in the middle?\n\n%.*s",
265                                     (int)(eol - plain->buf), plain->buf);
266
267                         /*
268                          * Do *not* change `hunk`: the mode change pseudo-hunk
269                          * is _part of_ the header "hunk".
270                          */
271                         file_diff->mode_change = 1;
272                         ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr,
273                                    file_diff->hunk_alloc);
274                         memset(file_diff->hunk, 0, sizeof(struct hunk));
275                         file_diff->hunk->start = p - plain->buf;
276                         if (colored_p)
277                                 file_diff->hunk->colored_start =
278                                         colored_p - colored->buf;
279                 } else if (hunk == &file_diff->head &&
280                            skip_prefix(p, "new mode ", &mode_change) &&
281                            is_octal(mode_change, eol - mode_change)) {
282
283                         /*
284                          * Extend the "mode change" pseudo-hunk to include also
285                          * the "new mode" line.
286                          */
287                         if (!file_diff->mode_change)
288                                 BUG("'new mode' without 'old mode'?\n\n%.*s",
289                                     (int)(eol - plain->buf), plain->buf);
290                         if (file_diff->hunk_nr != 1)
291                                 BUG("mode change in the middle?\n\n%.*s",
292                                     (int)(eol - plain->buf), plain->buf);
293                         if (p - plain->buf != file_diff->hunk->end)
294                                 BUG("'new mode' does not immediately follow "
295                                     "'old mode'?\n\n%.*s",
296                                     (int)(eol - plain->buf), plain->buf);
297                 } else if (hunk == &file_diff->head &&
298                            starts_with(p, "Binary files "))
299                         file_diff->binary = 1;
300
301                 if (file_diff->deleted && file_diff->mode_change)
302                         BUG("diff contains delete *and* a mode change?!?\n%.*s",
303                             (int)(eol - (plain->buf + file_diff->head.start)),
304                             plain->buf + file_diff->head.start);
305
306                 if ((marker == '-' || marker == '+') && *p == ' ')
307                         hunk->splittable_into++;
308                 if (marker && *p != '\\')
309                         marker = *p;
310
311                 p = eol == pend ? pend : eol + 1;
312                 hunk->end = p - plain->buf;
313
314                 if (colored) {
315                         char *colored_eol = memchr(colored_p, '\n',
316                                                    colored_pend - colored_p);
317                         if (colored_eol)
318                                 colored_p = colored_eol + 1;
319                         else
320                                 colored_p = colored_pend;
321
322                         hunk->colored_end = colored_p - colored->buf;
323                 }
324
325                 if (mode_change) {
326                         if (file_diff->hunk_nr != 1)
327                                 BUG("mode change in hunk #%d???",
328                                     (int)file_diff->hunk_nr);
329                         /* Adjust the end of the "mode change" pseudo-hunk */
330                         file_diff->hunk->end = hunk->end;
331                         if (colored)
332                                 file_diff->hunk->colored_end = hunk->colored_end;
333                 }
334         }
335
336         if (marker == '-' || marker == '+')
337                 /*
338                  * Last hunk ended in non-context line (i.e. it appended lines
339                  * to the file, so there are no trailing context lines).
340                  */
341                 hunk->splittable_into++;
342
343         return 0;
344 }
345
346 static size_t find_next_line(struct strbuf *sb, size_t offset)
347 {
348         char *eol;
349
350         if (offset >= sb->len)
351                 BUG("looking for next line beyond buffer (%d >= %d)\n%s",
352                     (int)offset, (int)sb->len, sb->buf);
353
354         eol = memchr(sb->buf + offset, '\n', sb->len - offset);
355         if (!eol)
356                 return sb->len;
357         return eol - sb->buf + 1;
358 }
359
360 static void render_hunk(struct add_p_state *s, struct hunk *hunk,
361                         ssize_t delta, int colored, struct strbuf *out)
362 {
363         struct hunk_header *header = &hunk->header;
364
365         if (hunk->header.old_offset != 0 || hunk->header.new_offset != 0) {
366                 /*
367                  * Generate the hunk header dynamically, except for special
368                  * hunks (such as the diff header).
369                  */
370                 const char *p;
371                 size_t len;
372                 unsigned long old_offset = header->old_offset;
373                 unsigned long new_offset = header->new_offset;
374
375                 if (!colored) {
376                         p = s->plain.buf + header->extra_start;
377                         len = header->extra_end - header->extra_start;
378                 } else {
379                         strbuf_addstr(out, s->s.fraginfo_color);
380                         p = s->colored.buf + header->colored_extra_start;
381                         len = header->colored_extra_end
382                                 - header->colored_extra_start;
383                 }
384
385                 new_offset += delta;
386
387                 strbuf_addf(out, "@@ -%lu,%lu +%lu,%lu @@",
388                             old_offset, header->old_count,
389                             new_offset, header->new_count);
390                 if (len)
391                         strbuf_add(out, p, len);
392                 else if (colored)
393                         strbuf_addf(out, "%s\n", GIT_COLOR_RESET);
394                 else
395                         strbuf_addch(out, '\n');
396         }
397
398         if (colored)
399                 strbuf_add(out, s->colored.buf + hunk->colored_start,
400                            hunk->colored_end - hunk->colored_start);
401         else
402                 strbuf_add(out, s->plain.buf + hunk->start,
403                            hunk->end - hunk->start);
404 }
405
406 static void render_diff_header(struct add_p_state *s,
407                                struct file_diff *file_diff, int colored,
408                                struct strbuf *out)
409 {
410         /*
411          * If there was a mode change, the first hunk is a pseudo hunk that
412          * corresponds to the mode line in the header. If the user did not want
413          * to stage that "hunk", we actually have to cut it out from the header.
414          */
415         int skip_mode_change =
416                 file_diff->mode_change && file_diff->hunk->use != USE_HUNK;
417         struct hunk *head = &file_diff->head, *first = file_diff->hunk;
418
419         if (!skip_mode_change) {
420                 render_hunk(s, head, 0, colored, out);
421                 return;
422         }
423
424         if (colored) {
425                 const char *p = s->colored.buf;
426
427                 strbuf_add(out, p + head->colored_start,
428                             first->colored_start - head->colored_start);
429                 strbuf_add(out, p + first->colored_end,
430                             head->colored_end - first->colored_end);
431         } else {
432                 const char *p = s->plain.buf;
433
434                 strbuf_add(out, p + head->start, first->start - head->start);
435                 strbuf_add(out, p + first->end, head->end - first->end);
436         }
437 }
438
439 /* Coalesce hunks again that were split */
440 static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
441                        size_t *hunk_index, int use_all, struct hunk *merged)
442 {
443         size_t i = *hunk_index, delta;
444         struct hunk *hunk = file_diff->hunk + i;
445         /* `header` corresponds to the merged hunk */
446         struct hunk_header *header = &merged->header, *next;
447
448         if (!use_all && hunk->use != USE_HUNK)
449                 return 0;
450
451         *merged = *hunk;
452         /* We simply skip the colored part (if any) when merging hunks */
453         merged->colored_start = merged->colored_end = 0;
454
455         for (; i + 1 < file_diff->hunk_nr; i++) {
456                 hunk++;
457                 next = &hunk->header;
458
459                 /*
460                  * Stop merging hunks when:
461                  *
462                  * - the hunk is not selected for use, or
463                  * - the hunk does not overlap with the already-merged hunk(s)
464                  */
465                 if ((!use_all && hunk->use != USE_HUNK) ||
466                     header->new_offset >= next->new_offset + merged->delta ||
467                     header->new_offset + header->new_count
468                     < next->new_offset + merged->delta)
469                         break;
470
471                 /*
472                  * If the hunks were not edited, and overlap, we can simply
473                  * extend the line range.
474                  */
475                 if (merged->start < hunk->start && merged->end > hunk->start) {
476                         merged->end = hunk->end;
477                         merged->colored_end = hunk->colored_end;
478                         delta = 0;
479                 } else {
480                         const char *plain = s->plain.buf;
481                         size_t  overlapping_line_count = header->new_offset
482                                 + header->new_count - merged->delta
483                                 - next->new_offset;
484                         size_t overlap_end = hunk->start;
485                         size_t overlap_start = overlap_end;
486                         size_t overlap_next, len, j;
487
488                         /*
489                          * One of the hunks was edited: the modified hunk was
490                          * appended to the strbuf `s->plain`.
491                          *
492                          * Let's ensure that at least the last context line of
493                          * the first hunk overlaps with the corresponding line
494                          * of the second hunk, and then merge.
495                          */
496                         for (j = 0; j < overlapping_line_count; j++) {
497                                 overlap_next = find_next_line(&s->plain,
498                                                               overlap_end);
499
500                                 if (overlap_next > hunk->end)
501                                         BUG("failed to find %d context lines "
502                                             "in:\n%.*s",
503                                             (int)overlapping_line_count,
504                                             (int)(hunk->end - hunk->start),
505                                             plain + hunk->start);
506
507                                 if (plain[overlap_end] != ' ')
508                                         return error(_("expected context line "
509                                                        "#%d in\n%.*s"),
510                                                      (int)(j + 1),
511                                                      (int)(hunk->end
512                                                            - hunk->start),
513                                                      plain + hunk->start);
514
515                                 overlap_start = overlap_end;
516                                 overlap_end = overlap_next;
517                         }
518                         len = overlap_end - overlap_start;
519
520                         if (len > merged->end - merged->start ||
521                             memcmp(plain + merged->end - len,
522                                    plain + overlap_start, len))
523                                 return error(_("hunks do not overlap:\n%.*s\n"
524                                                "\tdoes not end with:\n%.*s"),
525                                              (int)(merged->end - merged->start),
526                                              plain + merged->start,
527                                              (int)len, plain + overlap_start);
528
529                         /*
530                          * Since the start-end ranges are not adjacent, we
531                          * cannot simply take the union of the ranges. To
532                          * address that, we temporarily append the union of the
533                          * lines to the `plain` strbuf.
534                          */
535                         if (merged->end != s->plain.len) {
536                                 size_t start = s->plain.len;
537
538                                 strbuf_add(&s->plain, plain + merged->start,
539                                            merged->end - merged->start);
540                                 plain = s->plain.buf;
541                                 merged->start = start;
542                                 merged->end = s->plain.len;
543                         }
544
545                         strbuf_add(&s->plain,
546                                    plain + overlap_end,
547                                    hunk->end - overlap_end);
548                         merged->end = s->plain.len;
549                         merged->splittable_into += hunk->splittable_into;
550                         delta = merged->delta;
551                         merged->delta += hunk->delta;
552                 }
553
554                 header->old_count = next->old_offset + next->old_count
555                         - header->old_offset;
556                 header->new_count = next->new_offset + delta
557                         + next->new_count - header->new_offset;
558         }
559
560         if (i == *hunk_index)
561                 return 0;
562
563         *hunk_index = i;
564         return 1;
565 }
566
567 static void reassemble_patch(struct add_p_state *s,
568                              struct file_diff *file_diff, int use_all,
569                              struct strbuf *out)
570 {
571         struct hunk *hunk;
572         size_t save_len = s->plain.len, i;
573         ssize_t delta = 0;
574
575         render_diff_header(s, file_diff, 0, out);
576
577         for (i = file_diff->mode_change; i < file_diff->hunk_nr; i++) {
578                 struct hunk merged = { 0 };
579
580                 hunk = file_diff->hunk + i;
581                 if (!use_all && hunk->use != USE_HUNK)
582                         delta += hunk->header.old_count
583                                 - hunk->header.new_count;
584                 else {
585                         /* merge overlapping hunks into a temporary hunk */
586                         if (merge_hunks(s, file_diff, &i, use_all, &merged))
587                                 hunk = &merged;
588
589                         render_hunk(s, hunk, delta, 0, out);
590
591                         /*
592                          * In case `merge_hunks()` used `plain` as a scratch
593                          * pad (this happens when an edited hunk had to be
594                          * coalesced with another hunk).
595                          */
596                         strbuf_setlen(&s->plain, save_len);
597
598                         delta += hunk->delta;
599                 }
600         }
601 }
602
603 static int split_hunk(struct add_p_state *s, struct file_diff *file_diff,
604                        size_t hunk_index)
605 {
606         int colored = !!s->colored.len, first = 1;
607         struct hunk *hunk = file_diff->hunk + hunk_index;
608         size_t splittable_into;
609         size_t end, colored_end, current, colored_current = 0, context_line_count;
610         struct hunk_header remaining, *header;
611         char marker, ch;
612
613         if (hunk_index >= file_diff->hunk_nr)
614                 BUG("invalid hunk index: %d (must be >= 0 and < %d)",
615                     (int)hunk_index, (int)file_diff->hunk_nr);
616
617         if (hunk->splittable_into < 2)
618                 return 0;
619         splittable_into = hunk->splittable_into;
620
621         end = hunk->end;
622         colored_end = hunk->colored_end;
623
624         remaining = hunk->header;
625
626         file_diff->hunk_nr += splittable_into - 1;
627         ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr, file_diff->hunk_alloc);
628         if (hunk_index + splittable_into < file_diff->hunk_nr)
629                 memmove(file_diff->hunk + hunk_index + splittable_into,
630                         file_diff->hunk + hunk_index + 1,
631                         (file_diff->hunk_nr - hunk_index - splittable_into)
632                         * sizeof(*hunk));
633         hunk = file_diff->hunk + hunk_index;
634         hunk->splittable_into = 1;
635         memset(hunk + 1, 0, (splittable_into - 1) * sizeof(*hunk));
636
637         header = &hunk->header;
638         header->old_count = header->new_count = 0;
639
640         current = hunk->start;
641         if (colored)
642                 colored_current = hunk->colored_start;
643         marker = '\0';
644         context_line_count = 0;
645
646         while (splittable_into > 1) {
647                 ch = s->plain.buf[current];
648
649                 if (!ch)
650                         BUG("buffer overrun while splitting hunks");
651
652                 /*
653                  * Is this the first context line after a chain of +/- lines?
654                  * Then record the start of the next split hunk.
655                  */
656                 if ((marker == '-' || marker == '+') && ch == ' ') {
657                         first = 0;
658                         hunk[1].start = current;
659                         if (colored)
660                                 hunk[1].colored_start = colored_current;
661                         context_line_count = 0;
662                 }
663
664                 /*
665                  * Was the previous line a +/- one? Alternatively, is this the
666                  * first line (and not a +/- one)?
667                  *
668                  * Then just increment the appropriate counter and continue
669                  * with the next line.
670                  */
671                 if (marker != ' ' || (ch != '-' && ch != '+')) {
672 next_hunk_line:
673                         /* Comment lines are attached to the previous line */
674                         if (ch == '\\')
675                                 ch = marker ? marker : ' ';
676
677                         /* current hunk not done yet */
678                         if (ch == ' ')
679                                 context_line_count++;
680                         else if (ch == '-')
681                                 header->old_count++;
682                         else if (ch == '+')
683                                 header->new_count++;
684                         else
685                                 BUG("unhandled diff marker: '%c'", ch);
686                         marker = ch;
687                         current = find_next_line(&s->plain, current);
688                         if (colored)
689                                 colored_current =
690                                         find_next_line(&s->colored,
691                                                        colored_current);
692                         continue;
693                 }
694
695                 /*
696                  * We got us the start of a new hunk!
697                  *
698                  * This is a context line, so it is shared with the previous
699                  * hunk, if any.
700                  */
701
702                 if (first) {
703                         if (header->old_count || header->new_count)
704                                 BUG("counts are off: %d/%d",
705                                     (int)header->old_count,
706                                     (int)header->new_count);
707
708                         header->old_count = context_line_count;
709                         header->new_count = context_line_count;
710                         context_line_count = 0;
711                         first = 0;
712                         goto next_hunk_line;
713                 }
714
715                 remaining.old_offset += header->old_count;
716                 remaining.old_count -= header->old_count;
717                 remaining.new_offset += header->new_count;
718                 remaining.new_count -= header->new_count;
719
720                 /* initialize next hunk header's offsets */
721                 hunk[1].header.old_offset =
722                         header->old_offset + header->old_count;
723                 hunk[1].header.new_offset =
724                         header->new_offset + header->new_count;
725
726                 /* add one split hunk */
727                 header->old_count += context_line_count;
728                 header->new_count += context_line_count;
729
730                 hunk->end = current;
731                 if (colored)
732                         hunk->colored_end = colored_current;
733
734                 hunk++;
735                 hunk->splittable_into = 1;
736                 hunk->use = hunk[-1].use;
737                 header = &hunk->header;
738
739                 header->old_count = header->new_count = context_line_count;
740                 context_line_count = 0;
741
742                 splittable_into--;
743                 marker = ch;
744         }
745
746         /* last hunk simply gets the rest */
747         if (header->old_offset != remaining.old_offset)
748                 BUG("miscounted old_offset: %lu != %lu",
749                     header->old_offset, remaining.old_offset);
750         if (header->new_offset != remaining.new_offset)
751                 BUG("miscounted new_offset: %lu != %lu",
752                     header->new_offset, remaining.new_offset);
753         header->old_count = remaining.old_count;
754         header->new_count = remaining.new_count;
755         hunk->end = end;
756         if (colored)
757                 hunk->colored_end = colored_end;
758
759         return 0;
760 }
761
762 static void recolor_hunk(struct add_p_state *s, struct hunk *hunk)
763 {
764         const char *plain = s->plain.buf;
765         size_t current, eol, next;
766
767         if (!s->colored.len)
768                 return;
769
770         hunk->colored_start = s->colored.len;
771         for (current = hunk->start; current < hunk->end; ) {
772                 for (eol = current; eol < hunk->end; eol++)
773                         if (plain[eol] == '\n')
774                                 break;
775                 next = eol + (eol < hunk->end);
776                 if (eol > current && plain[eol - 1] == '\r')
777                         eol--;
778
779                 strbuf_addstr(&s->colored,
780                               plain[current] == '-' ?
781                               s->s.file_old_color :
782                               plain[current] == '+' ?
783                               s->s.file_new_color :
784                               s->s.context_color);
785                 strbuf_add(&s->colored, plain + current, eol - current);
786                 strbuf_addstr(&s->colored, GIT_COLOR_RESET);
787                 if (next > eol)
788                         strbuf_add(&s->colored, plain + eol, next - eol);
789                 current = next;
790         }
791         hunk->colored_end = s->colored.len;
792 }
793
794 static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
795 {
796         size_t i;
797
798         strbuf_reset(&s->buf);
799         strbuf_commented_addf(&s->buf, _("Manual hunk edit mode -- see bottom for "
800                                       "a quick guide.\n"));
801         render_hunk(s, hunk, 0, 0, &s->buf);
802         strbuf_commented_addf(&s->buf,
803                               _("---\n"
804                                 "To remove '%c' lines, make them ' ' lines "
805                                 "(context).\n"
806                                 "To remove '%c' lines, delete them.\n"
807                                 "Lines starting with %c will be removed.\n"),
808                               '-', '+', comment_line_char);
809         strbuf_commented_addf(&s->buf,
810                               _("If the patch applies cleanly, the edited hunk "
811                                 "will immediately be\n"
812                                 "marked for staging.\n"));
813         /*
814          * TRANSLATORS: 'it' refers to the patch mentioned in the previous
815          * messages.
816          */
817         strbuf_commented_addf(&s->buf,
818                               _("If it does not apply cleanly, you will be "
819                                 "given an opportunity to\n"
820                                 "edit again.  If all lines of the hunk are "
821                                 "removed, then the edit is\n"
822                                 "aborted and the hunk is left unchanged.\n"));
823
824         if (strbuf_edit_interactively(&s->buf, "addp-hunk-edit.diff", NULL) < 0)
825                 return -1;
826
827         /* strip out commented lines */
828         hunk->start = s->plain.len;
829         for (i = 0; i < s->buf.len; ) {
830                 size_t next = find_next_line(&s->buf, i);
831
832                 if (s->buf.buf[i] != comment_line_char)
833                         strbuf_add(&s->plain, s->buf.buf + i, next - i);
834                 i = next;
835         }
836
837         hunk->end = s->plain.len;
838         if (hunk->end == hunk->start)
839                 /* The user aborted editing by deleting everything */
840                 return 0;
841
842         recolor_hunk(s, hunk);
843
844         /*
845          * If the hunk header is intact, parse it, otherwise simply use the
846          * hunk header prior to editing (which will adjust `hunk->start` to
847          * skip the hunk header).
848          */
849         if (s->plain.buf[hunk->start] == '@' &&
850             parse_hunk_header(s, hunk) < 0)
851                 return error(_("could not parse hunk header"));
852
853         return 1;
854 }
855
856 static ssize_t recount_edited_hunk(struct add_p_state *s, struct hunk *hunk,
857                                    size_t orig_old_count, size_t orig_new_count)
858 {
859         struct hunk_header *header = &hunk->header;
860         size_t i;
861
862         header->old_count = header->new_count = 0;
863         for (i = hunk->start; i < hunk->end; ) {
864                 switch (s->plain.buf[i]) {
865                 case '-':
866                         header->old_count++;
867                         break;
868                 case '+':
869                         header->new_count++;
870                         break;
871                 case ' ': case '\r': case '\n':
872                         header->old_count++;
873                         header->new_count++;
874                         break;
875                 }
876
877                 i = find_next_line(&s->plain, i);
878         }
879
880         return orig_old_count - orig_new_count
881                 - header->old_count + header->new_count;
882 }
883
884 static int run_apply_check(struct add_p_state *s,
885                            struct file_diff *file_diff)
886 {
887         struct child_process cp = CHILD_PROCESS_INIT;
888
889         strbuf_reset(&s->buf);
890         reassemble_patch(s, file_diff, 1, &s->buf);
891
892         setup_child_process(s, &cp,
893                             "apply", "--cached", "--check", NULL);
894         if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0))
895                 return error(_("'git apply --cached' failed"));
896
897         return 0;
898 }
899
900 static int prompt_yesno(struct add_p_state *s, const char *prompt)
901 {
902         for (;;) {
903                 color_fprintf(stdout, s->s.prompt_color, "%s", _(prompt));
904                 fflush(stdout);
905                 if (strbuf_getline(&s->answer, stdin) == EOF)
906                         return -1;
907                 strbuf_trim_trailing_newline(&s->answer);
908                 switch (tolower(s->answer.buf[0])) {
909                 case 'n': return 0;
910                 case 'y': return 1;
911                 }
912         }
913 }
914
915 static int edit_hunk_loop(struct add_p_state *s,
916                           struct file_diff *file_diff, struct hunk *hunk)
917 {
918         size_t plain_len = s->plain.len, colored_len = s->colored.len;
919         struct hunk backup;
920
921         backup = *hunk;
922
923         for (;;) {
924                 int res = edit_hunk_manually(s, hunk);
925                 if (res == 0) {
926                         /* abandonded */
927                         *hunk = backup;
928                         return -1;
929                 }
930
931                 if (res > 0) {
932                         hunk->delta +=
933                                 recount_edited_hunk(s, hunk,
934                                                     backup.header.old_count,
935                                                     backup.header.new_count);
936                         if (!run_apply_check(s, file_diff))
937                                 return 0;
938                 }
939
940                 /* Drop edits (they were appended to s->plain) */
941                 strbuf_setlen(&s->plain, plain_len);
942                 strbuf_setlen(&s->colored, colored_len);
943                 *hunk = backup;
944
945                 /*
946                  * TRANSLATORS: do not translate [y/n]
947                  * The program will only accept that input at this point.
948                  * Consider translating (saying "no" discards!) as
949                  * (saying "n" for "no" discards!) if the translation
950                  * of the word "no" does not start with n.
951                  */
952                 res = prompt_yesno(s, _("Your edited hunk does not apply. "
953                                         "Edit again (saying \"no\" discards!) "
954                                         "[y/n]? "));
955                 if (res < 1)
956                         return -1;
957         }
958 }
959
960 #define SUMMARY_HEADER_WIDTH 20
961 #define SUMMARY_LINE_WIDTH 80
962 static void summarize_hunk(struct add_p_state *s, struct hunk *hunk,
963                            struct strbuf *out)
964 {
965         struct hunk_header *header = &hunk->header;
966         struct strbuf *plain = &s->plain;
967         size_t len = out->len, i;
968
969         strbuf_addf(out, " -%lu,%lu +%lu,%lu ",
970                     header->old_offset, header->old_count,
971                     header->new_offset, header->new_count);
972         if (out->len - len < SUMMARY_HEADER_WIDTH)
973                 strbuf_addchars(out, ' ',
974                                 SUMMARY_HEADER_WIDTH + len - out->len);
975         for (i = hunk->start; i < hunk->end; i = find_next_line(plain, i))
976                 if (plain->buf[i] != ' ')
977                         break;
978         if (i < hunk->end)
979                 strbuf_add(out, plain->buf + i, find_next_line(plain, i) - i);
980         if (out->len - len > SUMMARY_LINE_WIDTH)
981                 strbuf_setlen(out, len + SUMMARY_LINE_WIDTH);
982         strbuf_complete_line(out);
983 }
984
985 #define DISPLAY_HUNKS_LINES 20
986 static size_t display_hunks(struct add_p_state *s,
987                             struct file_diff *file_diff, size_t start_index)
988 {
989         size_t end_index = start_index + DISPLAY_HUNKS_LINES;
990
991         if (end_index > file_diff->hunk_nr)
992                 end_index = file_diff->hunk_nr;
993
994         while (start_index < end_index) {
995                 struct hunk *hunk = file_diff->hunk + start_index++;
996
997                 strbuf_reset(&s->buf);
998                 strbuf_addf(&s->buf, "%c%2d: ", hunk->use == USE_HUNK ? '+'
999                             : hunk->use == SKIP_HUNK ? '-' : ' ',
1000                             (int)start_index);
1001                 summarize_hunk(s, hunk, &s->buf);
1002                 fputs(s->buf.buf, stdout);
1003         }
1004
1005         return end_index;
1006 }
1007
1008 static const char help_patch_text[] =
1009 N_("y - stage this hunk\n"
1010    "n - do not stage this hunk\n"
1011    "q - quit; do not stage this hunk or any of the remaining ones\n"
1012    "a - stage this and all the remaining hunks\n"
1013    "d - do not stage this hunk nor any of the remaining hunks\n");
1014
1015 static const char help_patch_remainder[] =
1016 N_("j - leave this hunk undecided, see next undecided hunk\n"
1017    "J - leave this hunk undecided, see next hunk\n"
1018    "k - leave this hunk undecided, see previous undecided hunk\n"
1019    "K - leave this hunk undecided, see previous hunk\n"
1020    "g - select a hunk to go to\n"
1021    "/ - search for a hunk matching the given regex\n"
1022    "s - split the current hunk into smaller hunks\n"
1023    "e - manually edit the current hunk\n"
1024    "? - print help\n");
1025
1026 static int patch_update_file(struct add_p_state *s,
1027                              struct file_diff *file_diff)
1028 {
1029         size_t hunk_index = 0;
1030         ssize_t i, undecided_previous, undecided_next;
1031         struct hunk *hunk;
1032         char ch;
1033         struct child_process cp = CHILD_PROCESS_INIT;
1034         int colored = !!s->colored.len, quit = 0;
1035         enum prompt_mode_type prompt_mode_type;
1036
1037         if (!file_diff->hunk_nr)
1038                 return 0;
1039
1040         strbuf_reset(&s->buf);
1041         render_diff_header(s, file_diff, colored, &s->buf);
1042         fputs(s->buf.buf, stdout);
1043         for (;;) {
1044                 if (hunk_index >= file_diff->hunk_nr)
1045                         hunk_index = 0;
1046                 hunk = file_diff->hunk + hunk_index;
1047
1048                 undecided_previous = -1;
1049                 for (i = hunk_index - 1; i >= 0; i--)
1050                         if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
1051                                 undecided_previous = i;
1052                                 break;
1053                         }
1054
1055                 undecided_next = -1;
1056                 for (i = hunk_index + 1; i < file_diff->hunk_nr; i++)
1057                         if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
1058                                 undecided_next = i;
1059                                 break;
1060                         }
1061
1062                 /* Everything decided? */
1063                 if (undecided_previous < 0 && undecided_next < 0 &&
1064                     hunk->use != UNDECIDED_HUNK)
1065                         break;
1066
1067                 strbuf_reset(&s->buf);
1068                 render_hunk(s, hunk, 0, colored, &s->buf);
1069                 fputs(s->buf.buf, stdout);
1070
1071                 strbuf_reset(&s->buf);
1072                 if (undecided_previous >= 0)
1073                         strbuf_addstr(&s->buf, ",k");
1074                 if (hunk_index)
1075                         strbuf_addstr(&s->buf, ",K");
1076                 if (undecided_next >= 0)
1077                         strbuf_addstr(&s->buf, ",j");
1078                 if (hunk_index + 1 < file_diff->hunk_nr)
1079                         strbuf_addstr(&s->buf, ",J");
1080                 if (file_diff->hunk_nr > 1)
1081                         strbuf_addstr(&s->buf, ",g,/");
1082                 if (hunk->splittable_into > 1)
1083                         strbuf_addstr(&s->buf, ",s");
1084                 if (hunk_index + 1 > file_diff->mode_change &&
1085                     !file_diff->deleted)
1086                         strbuf_addstr(&s->buf, ",e");
1087
1088                 if (file_diff->deleted)
1089                         prompt_mode_type = PROMPT_DELETION;
1090                 else if (file_diff->mode_change && !hunk_index)
1091                         prompt_mode_type = PROMPT_MODE_CHANGE;
1092                 else
1093                         prompt_mode_type = PROMPT_HUNK;
1094
1095                 color_fprintf(stdout, s->s.prompt_color,
1096                               "(%"PRIuMAX"/%"PRIuMAX") ",
1097                               (uintmax_t)hunk_index + 1,
1098                               (uintmax_t)file_diff->hunk_nr);
1099                 color_fprintf(stdout, s->s.prompt_color,
1100                               _(prompt_mode[prompt_mode_type]), s->buf.buf);
1101                 fflush(stdout);
1102                 if (strbuf_getline(&s->answer, stdin) == EOF)
1103                         break;
1104                 strbuf_trim_trailing_newline(&s->answer);
1105
1106                 if (!s->answer.len)
1107                         continue;
1108                 ch = tolower(s->answer.buf[0]);
1109                 if (ch == 'y') {
1110                         hunk->use = USE_HUNK;
1111 soft_increment:
1112                         hunk_index = undecided_next < 0 ?
1113                                 file_diff->hunk_nr : undecided_next;
1114                 } else if (ch == 'n') {
1115                         hunk->use = SKIP_HUNK;
1116                         goto soft_increment;
1117                 } else if (ch == 'a') {
1118                         for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
1119                                 hunk = file_diff->hunk + hunk_index;
1120                                 if (hunk->use == UNDECIDED_HUNK)
1121                                         hunk->use = USE_HUNK;
1122                         }
1123                 } else if (ch == 'd' || ch == 'q') {
1124                         for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
1125                                 hunk = file_diff->hunk + hunk_index;
1126                                 if (hunk->use == UNDECIDED_HUNK)
1127                                         hunk->use = SKIP_HUNK;
1128                         }
1129                         if (ch == 'q') {
1130                                 quit = 1;
1131                                 break;
1132                         }
1133                 } else if (s->answer.buf[0] == 'K') {
1134                         if (hunk_index)
1135                                 hunk_index--;
1136                         else
1137                                 err(s, _("No previous hunk"));
1138                 } else if (s->answer.buf[0] == 'J') {
1139                         if (hunk_index + 1 < file_diff->hunk_nr)
1140                                 hunk_index++;
1141                         else
1142                                 err(s, _("No next hunk"));
1143                 } else if (s->answer.buf[0] == 'k') {
1144                         if (undecided_previous >= 0)
1145                                 hunk_index = undecided_previous;
1146                         else
1147                                 err(s, _("No previous hunk"));
1148                 } else if (s->answer.buf[0] == 'j') {
1149                         if (undecided_next >= 0)
1150                                 hunk_index = undecided_next;
1151                         else
1152                                 err(s, _("No next hunk"));
1153                 } else if (s->answer.buf[0] == 'g') {
1154                         char *pend;
1155                         unsigned long response;
1156
1157                         if (file_diff->hunk_nr < 2) {
1158                                 err(s, _("No other hunks to goto"));
1159                                 continue;
1160                         }
1161                         strbuf_remove(&s->answer, 0, 1);
1162                         strbuf_trim(&s->answer);
1163                         i = hunk_index - DISPLAY_HUNKS_LINES / 2;
1164                         if (i < file_diff->mode_change)
1165                                 i = file_diff->mode_change;
1166                         while (s->answer.len == 0) {
1167                                 i = display_hunks(s, file_diff, i);
1168                                 printf("%s", i < file_diff->hunk_nr ?
1169                                        _("go to which hunk (<ret> to see "
1170                                          "more)? ") : _("go to which hunk? "));
1171                                 fflush(stdout);
1172                                 if (strbuf_getline(&s->answer,
1173                                                    stdin) == EOF)
1174                                         break;
1175                                 strbuf_trim_trailing_newline(&s->answer);
1176                         }
1177
1178                         strbuf_trim(&s->answer);
1179                         response = strtoul(s->answer.buf, &pend, 10);
1180                         if (*pend || pend == s->answer.buf)
1181                                 err(s, _("Invalid number: '%s'"),
1182                                     s->answer.buf);
1183                         else if (0 < response && response <= file_diff->hunk_nr)
1184                                 hunk_index = response - 1;
1185                         else
1186                                 err(s, Q_("Sorry, only %d hunk available.",
1187                                           "Sorry, only %d hunks available.",
1188                                           file_diff->hunk_nr),
1189                                     (int)file_diff->hunk_nr);
1190                 } else if (s->answer.buf[0] == '/') {
1191                         regex_t regex;
1192                         int ret;
1193
1194                         if (file_diff->hunk_nr < 2) {
1195                                 err(s, _("No other hunks to search"));
1196                                 continue;
1197                         }
1198                         strbuf_remove(&s->answer, 0, 1);
1199                         strbuf_trim_trailing_newline(&s->answer);
1200                         if (s->answer.len == 0) {
1201                                 printf("%s", _("search for regex? "));
1202                                 fflush(stdout);
1203                                 if (strbuf_getline(&s->answer,
1204                                                    stdin) == EOF)
1205                                         break;
1206                                 strbuf_trim_trailing_newline(&s->answer);
1207                                 if (s->answer.len == 0)
1208                                         continue;
1209                         }
1210                         ret = regcomp(&regex, s->answer.buf,
1211                                       REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
1212                         if (ret) {
1213                                 char errbuf[1024];
1214
1215                                 regerror(ret, &regex, errbuf, sizeof(errbuf));
1216                                 err(s, _("Malformed search regexp %s: %s"),
1217                                     s->answer.buf, errbuf);
1218                                 continue;
1219                         }
1220                         i = hunk_index;
1221                         for (;;) {
1222                                 /* render the hunk into a scratch buffer */
1223                                 render_hunk(s, file_diff->hunk + i, 0, 0,
1224                                             &s->buf);
1225                                 if (regexec(&regex, s->buf.buf, 0, NULL, 0)
1226                                     != REG_NOMATCH)
1227                                         break;
1228                                 i++;
1229                                 if (i == file_diff->hunk_nr)
1230                                         i = 0;
1231                                 if (i != hunk_index)
1232                                         continue;
1233                                 err(s, _("No hunk matches the given pattern"));
1234                                 break;
1235                         }
1236                         hunk_index = i;
1237                 } else if (s->answer.buf[0] == 's') {
1238                         size_t splittable_into = hunk->splittable_into;
1239                         if (splittable_into < 2)
1240                                 err(s, _("Sorry, cannot split this hunk"));
1241                         else if (!split_hunk(s, file_diff,
1242                                              hunk - file_diff->hunk))
1243                                 color_fprintf_ln(stdout, s->s.header_color,
1244                                                  _("Split into %d hunks."),
1245                                                  (int)splittable_into);
1246                 } else if (s->answer.buf[0] == 'e') {
1247                         if (hunk_index + 1 == file_diff->mode_change)
1248                                 err(s, _("Sorry, cannot edit this hunk"));
1249                         else if (edit_hunk_loop(s, file_diff, hunk) >= 0) {
1250                                 hunk->use = USE_HUNK;
1251                                 goto soft_increment;
1252                         }
1253                 } else {
1254                         const char *p = _(help_patch_remainder), *eol = p;
1255
1256                         color_fprintf(stdout, s->s.help_color, "%s",
1257                                       _(help_patch_text));
1258
1259                         /*
1260                          * Show only those lines of the remainder that are
1261                          * actually applicable with the current hunk.
1262                          */
1263                         for (; *p; p = eol + (*eol == '\n')) {
1264                                 eol = strchrnul(p, '\n');
1265
1266                                 /*
1267                                  * `s->buf` still contains the part of the
1268                                  * commands shown in the prompt that are not
1269                                  * always available.
1270                                  */
1271                                 if (*p != '?' && !strchr(s->buf.buf, *p))
1272                                         continue;
1273
1274                                 color_fprintf_ln(stdout, s->s.help_color,
1275                                                  "%.*s", (int)(eol - p), p);
1276                         }
1277                 }
1278         }
1279
1280         /* Any hunk to be used? */
1281         for (i = 0; i < file_diff->hunk_nr; i++)
1282                 if (file_diff->hunk[i].use == USE_HUNK)
1283                         break;
1284
1285         if (i < file_diff->hunk_nr) {
1286                 /* At least one hunk selected: apply */
1287                 strbuf_reset(&s->buf);
1288                 reassemble_patch(s, file_diff, 0, &s->buf);
1289
1290                 discard_index(s->s.r->index);
1291                 setup_child_process(s, &cp, "apply", "--cached", NULL);
1292                 if (pipe_command(&cp, s->buf.buf, s->buf.len,
1293                                  NULL, 0, NULL, 0))
1294                         error(_("'git apply --cached' failed"));
1295                 if (!repo_read_index(s->s.r))
1296                         repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0,
1297                                                      1, NULL, NULL, NULL);
1298         }
1299
1300         putchar('\n');
1301         return quit;
1302 }
1303
1304 int run_add_p(struct repository *r, const struct pathspec *ps)
1305 {
1306         struct add_p_state s = {
1307                 { r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
1308         };
1309         size_t i, binary_count = 0;
1310
1311         init_add_i_state(&s.s, r);
1312
1313         if (discard_index(r->index) < 0 || repo_read_index(r) < 0 ||
1314             repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
1315                                          NULL, NULL, NULL) < 0 ||
1316             parse_diff(&s, ps) < 0) {
1317                 strbuf_release(&s.plain);
1318                 strbuf_release(&s.colored);
1319                 return -1;
1320         }
1321
1322         for (i = 0; i < s.file_diff_nr; i++)
1323                 if (s.file_diff[i].binary && !s.file_diff[i].hunk_nr)
1324                         binary_count++;
1325                 else if (patch_update_file(&s, s.file_diff + i))
1326                         break;
1327
1328         if (s.file_diff_nr == 0)
1329                 fprintf(stderr, _("No changes.\n"));
1330         else if (binary_count == s.file_diff_nr)
1331                 fprintf(stderr, _("Only binary files changed.\n"));
1332
1333         strbuf_release(&s.answer);
1334         strbuf_release(&s.buf);
1335         strbuf_release(&s.plain);
1336         strbuf_release(&s.colored);
1337         return 0;
1338 }