pu bca46e3060e7375827de0056eab64cad9e556b76 jch 0c7f8a73bddc98b1aeac27d2e8bf3e3109eab9b4 next 64cd5c46229f533beb7b49a8dfd1c5104da25b00 master b02fd2accad4d48078671adf38fe5b5976d77304 master@{1} 083378cc35c4dbcc607e4cdd24a5fca440163d17 Uncovered code in 'pu' not in 'jch' -------------------------------------------------------- add-interactive.c 25ea47af 29) void init_add_i_state(struct add_i_state *s, struct repository *r) 25ea47af 47) init_color(r, s, "fraginfo", s->fraginfo_color, bcdd297b 49) init_color(r, s, "context", s->context_color, bcdd297b 51) init_color(r, s, "old", s->file_old_color, bcdd297b 53) init_color(r, s, "new", s->file_new_color, 1942ee44 918) struct pathspec ps_selected = { 0 }; 1942ee44 924) parse_pathspec(&ps_selected, 572bdc3a 927) res = run_add_p(s->r, ADD_P_STAGE, NULL, &ps_selected); 1942ee44 929) clear_pathspec(&ps_selected); add-patch.c 7584dd3c 257) static void err(struct add_p_state *s, const char *fmt, ...) 7584dd3c 261) va_start(args, fmt); 7584dd3c 262) fputs(s->s.error_color, stderr); 7584dd3c 263) vfprintf(stderr, fmt, args); 7584dd3c 264) fputs(s->s.reset_color, stderr); 7584dd3c 265) fputc('\n', stderr); 7584dd3c 266) va_end(args); 7584dd3c 267) } f6aa7ecc 269) static void setup_child_process(struct add_p_state *s, f6aa7ecc 275) va_start(ap, cp); f6aa7ecc 276) while ((arg = va_arg(ap, const char *))) f6aa7ecc 277) argv_array_push(&cp->args, arg); f6aa7ecc 278) va_end(ap); f6aa7ecc 280) cp->git_cmd = 1; f6aa7ecc 281) argv_array_pushf(&cp->env_array, 25ea47af 282) INDEX_ENVIRONMENT "=%s", s->s.r->index_file); 25ea47af 283) } 25ea47af 285) static int parse_range(const char **p, 25ea47af 290) *offset = strtoul(*p, &pend, 10); 25ea47af 291) if (pend == *p) 25ea47af 292) return -1; 25ea47af 293) if (*pend != ',') { 25ea47af 294) *count = 1; 25ea47af 295) *p = pend; 25ea47af 296) return 0; 25ea47af 298) *count = strtoul(pend + 1, (char **)p, 10); 25ea47af 299) return *p == pend + 1 ? -1 : 0; 25ea47af 302) static int parse_hunk_header(struct add_p_state *s, struct hunk *hunk) 25ea47af 304) struct hunk_header *header = &hunk->header; 25ea47af 305) const char *line = s->plain.buf + hunk->start, *p = line; 25ea47af 306) char *eol = memchr(p, '\n', s->plain.len - hunk->start); 25ea47af 308) if (!eol) 25ea47af 309) eol = s->plain.buf + s->plain.len; 25ea47af 311) if (!skip_prefix(p, "@@ -", &p) || 25ea47af 312) parse_range(&p, &header->old_offset, &header->old_count) < 0 || 25ea47af 313) !skip_prefix(p, " +", &p) || 25ea47af 314) parse_range(&p, &header->new_offset, &header->new_count) < 0 || 25ea47af 315) !skip_prefix(p, " @@", &p)) 25ea47af 319) hunk->start = eol - s->plain.buf + (*eol == '\n'); 25ea47af 320) header->extra_start = p - s->plain.buf; 25ea47af 321) header->extra_end = hunk->start; 25ea47af 323) if (!s->colored.len) { 25ea47af 324) header->colored_extra_start = header->colored_extra_end = 0; 25ea47af 325) return 0; 25ea47af 329) line = s->colored.buf + hunk->colored_start; 25ea47af 330) eol = memchr(line, '\n', s->colored.len - hunk->colored_start); 25ea47af 331) if (!eol) 25ea47af 332) eol = s->colored.buf + s->colored.len; 25ea47af 333) p = memmem(line, eol - line, "@@ -", 4); 25ea47af 334) if (!p) 25ea47af 337) p = memmem(p + 4, eol - p - 4, " @@", 3); 25ea47af 338) if (!p) 25ea47af 341) hunk->colored_start = eol - s->colored.buf + (*eol == '\n'); 25ea47af 342) header->colored_extra_start = p + 3 - s->colored.buf; 25ea47af 343) header->colored_extra_end = hunk->colored_start; 25ea47af 345) return 0; 5906d5de 348) static int is_octal(const char *p, size_t len) 5906d5de 350) if (!len) 5906d5de 351) return 0; 5906d5de 353) while (len--) 5906d5de 354) if (*p < '0' || *(p++) > '7') 5906d5de 355) return 0; 5906d5de 356) return 1; f6aa7ecc 359) static int parse_diff(struct add_p_state *s, const struct pathspec *ps) e3bd11b4 361) struct argv_array args = ARGV_ARRAY_INIT; e3bd11b4 362) struct strbuf *plain = &s->plain, *colored = NULL; f6aa7ecc 363) struct child_process cp = CHILD_PROCESS_INIT; 510aeca1 364) char *p, *pend, *colored_p = NULL, *colored_pend = NULL, marker = '\0'; 80399aec 365) size_t file_diff_alloc = 0, i, color_arg_index; 80399aec 366) struct file_diff *file_diff = NULL; f6aa7ecc 367) struct hunk *hunk = NULL; 572bdc3a 370) argv_array_pushv(&args, s->mode->diff); 572bdc3a 371) if (s->revision) { 572bdc3a 373) argv_array_push(&args, 572bdc3a 375) !strcmp("HEAD", s->revision) && 572bdc3a 376) get_oid("HEAD", &oid) ? 572bdc3a 379) color_arg_index = args.argc; 572bdc3a 381) argv_array_pushl(&args, "--no-color", "-p", "--", NULL); f6aa7ecc 382) for (i = 0; i < ps->nr; i++) e3bd11b4 383) argv_array_push(&args, ps->items[i].original); e3bd11b4 385) setup_child_process(s, &cp, NULL); e3bd11b4 386) cp.argv = args.argv; f6aa7ecc 387) res = capture_command(&cp, plain, 0); e3bd11b4 388) if (res) { e3bd11b4 389) argv_array_clear(&args); e3bd11b4 392) if (!plain->len) { e3bd11b4 393) argv_array_clear(&args); f6aa7ecc 394) return 0; f6aa7ecc 396) strbuf_complete_line(plain); e3bd11b4 398) if (want_color_fd(1, -1)) { e3bd11b4 399) struct child_process colored_cp = CHILD_PROCESS_INIT; e3bd11b4 401) setup_child_process(s, &colored_cp, NULL); e3bd11b4 402) xsnprintf((char *)args.argv[color_arg_index], 8, "--color"); e3bd11b4 403) colored_cp.argv = args.argv; e3bd11b4 404) colored = &s->colored; e3bd11b4 405) res = capture_command(&colored_cp, colored, 0); e3bd11b4 406) argv_array_clear(&args); e3bd11b4 407) if (res) e3bd11b4 409) strbuf_complete_line(colored); e3bd11b4 410) colored_p = colored->buf; e3bd11b4 411) colored_pend = colored_p + colored->len; e3bd11b4 413) argv_array_clear(&args); f6aa7ecc 416) p = plain->buf; f6aa7ecc 417) pend = p + plain->len; f6aa7ecc 418) while (p != pend) { f6aa7ecc 419) char *eol = memchr(p, '\n', pend - p); 5906d5de 420) const char *deleted = NULL, *mode_change = NULL; f6aa7ecc 422) if (!eol) f6aa7ecc 423) eol = pend; f6aa7ecc 425) if (starts_with(p, "diff ")) { 80399aec 426) s->file_diff_nr++; 80399aec 427) ALLOC_GROW(s->file_diff, s->file_diff_nr, 80399aec 429) file_diff = s->file_diff + s->file_diff_nr - 1; 80399aec 430) memset(file_diff, 0, sizeof(*file_diff)); 80399aec 431) hunk = &file_diff->head; 80399aec 432) hunk->start = p - plain->buf; 80399aec 433) if (colored_p) 80399aec 434) hunk->colored_start = colored_p - colored->buf; 510aeca1 435) marker = '\0'; f6aa7ecc 436) } else if (p == plain->buf) 47dc4fd5 439) else if (file_diff->deleted) 47dc4fd5 441) else if (starts_with(p, "@@ ") || 47dc4fd5 442) (hunk == &file_diff->head && 47dc4fd5 443) skip_prefix(p, "deleted file", &deleted))) { 510aeca1 444) if (marker == '-' || marker == '+') 510aeca1 449) hunk->splittable_into++; 80399aec 451) file_diff->hunk_nr++; 80399aec 452) ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr, 80399aec 454) hunk = file_diff->hunk + file_diff->hunk_nr - 1; f6aa7ecc 455) memset(hunk, 0, sizeof(*hunk)); f6aa7ecc 457) hunk->start = p - plain->buf; e3bd11b4 458) if (colored) e3bd11b4 459) hunk->colored_start = colored_p - colored->buf; 47dc4fd5 461) if (deleted) 47dc4fd5 462) file_diff->deleted = 1; 47dc4fd5 463) else if (parse_hunk_header(s, hunk) < 0) 25ea47af 464) return -1; 510aeca1 470) marker = *p; 5906d5de 471) } else if (hunk == &file_diff->head && 5906d5de 472) skip_prefix(p, "old mode ", &mode_change) && 5906d5de 473) is_octal(mode_change, eol - mode_change)) { 5906d5de 474) if (file_diff->mode_change) 5906d5de 477) if (file_diff->hunk_nr++) 5906d5de 485) file_diff->mode_change = 1; 5906d5de 486) ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr, 5906d5de 488) memset(file_diff->hunk, 0, sizeof(struct hunk)); 5906d5de 489) file_diff->hunk->start = p - plain->buf; 5906d5de 490) if (colored_p) 5906d5de 491) file_diff->hunk->colored_start = 5906d5de 492) colored_p - colored->buf; 5906d5de 493) } else if (hunk == &file_diff->head && 5906d5de 494) skip_prefix(p, "new mode ", &mode_change) && 5906d5de 495) is_octal(mode_change, eol - mode_change)) { 5906d5de 501) if (!file_diff->mode_change) 5906d5de 504) if (file_diff->hunk_nr != 1) 5906d5de 507) if (p - plain->buf != file_diff->hunk->end) 2e408319 511) } else if (hunk == &file_diff->head && 2e408319 512) starts_with(p, "Binary files ")) 2e408319 513) file_diff->binary = 1; 5906d5de 515) if (file_diff->deleted && file_diff->mode_change) 510aeca1 520) if ((marker == '-' || marker == '+') && *p == ' ') 510aeca1 521) hunk->splittable_into++; 510aeca1 522) if (marker && *p != '\\') 510aeca1 523) marker = *p; f6aa7ecc 525) p = eol == pend ? pend : eol + 1; f6aa7ecc 526) hunk->end = p - plain->buf; e3bd11b4 528) if (colored) { e3bd11b4 529) char *colored_eol = memchr(colored_p, '\n', e3bd11b4 530) colored_pend - colored_p); e3bd11b4 531) if (colored_eol) e3bd11b4 532) colored_p = colored_eol + 1; e3bd11b4 534) colored_p = colored_pend; e3bd11b4 536) hunk->colored_end = colored_p - colored->buf; 5906d5de 539) if (mode_change) { 5906d5de 540) if (file_diff->hunk_nr != 1) 5906d5de 544) file_diff->hunk->end = hunk->end; 5906d5de 545) if (colored) 5906d5de 546) file_diff->hunk->colored_end = hunk->colored_end; 510aeca1 550) if (marker == '-' || marker == '+') 510aeca1 555) hunk->splittable_into++; f6aa7ecc 557) return 0; 510aeca1 560) static size_t find_next_line(struct strbuf *sb, size_t offset) 510aeca1 564) if (offset >= sb->len) 510aeca1 568) eol = memchr(sb->buf + offset, '\n', sb->len - offset); 510aeca1 569) if (!eol) 510aeca1 570) return sb->len; 510aeca1 571) return eol - sb->buf + 1; f6aa7ecc 574) static void render_hunk(struct add_p_state *s, struct hunk *hunk, 25ea47af 577) struct hunk_header *header = &hunk->header; 25ea47af 579) if (hunk->header.old_offset != 0 || hunk->header.new_offset != 0) { 25ea47af 586) unsigned long old_offset = header->old_offset; 25ea47af 587) unsigned long new_offset = header->new_offset; 25ea47af 589) if (!colored) { 25ea47af 590) p = s->plain.buf + header->extra_start; 25ea47af 591) len = header->extra_end - header->extra_start; 25ea47af 593) strbuf_addstr(out, s->s.fraginfo_color); 25ea47af 594) p = s->colored.buf + header->colored_extra_start; 25ea47af 595) len = header->colored_extra_end 25ea47af 596) - header->colored_extra_start; 572bdc3a 599) if (s->mode->is_reverse) 572bdc3a 600) old_offset -= delta; 572bdc3a 602) new_offset += delta; 25ea47af 604) strbuf_addf(out, "@@ -%lu,%lu +%lu,%lu @@", 25ea47af 607) if (len) 25ea47af 608) strbuf_add(out, p, len); 25ea47af 609) else if (colored) 25ea47af 610) strbuf_addf(out, "%s\n", GIT_COLOR_RESET); 25ea47af 612) strbuf_addch(out, '\n'); e3bd11b4 615) if (colored) e3bd11b4 616) strbuf_add(out, s->colored.buf + hunk->colored_start, e3bd11b4 617) hunk->colored_end - hunk->colored_start); e3bd11b4 619) strbuf_add(out, s->plain.buf + hunk->start, e3bd11b4 620) hunk->end - hunk->start); f6aa7ecc 621) } 5906d5de 623) static void render_diff_header(struct add_p_state *s, 5906d5de 632) int skip_mode_change = 5906d5de 633) file_diff->mode_change && file_diff->hunk->use != USE_HUNK; 5906d5de 634) struct hunk *head = &file_diff->head, *first = file_diff->hunk; 5906d5de 636) if (!skip_mode_change) { 5906d5de 637) render_hunk(s, head, 0, colored, out); 5906d5de 638) return; 5906d5de 641) if (colored) { 5906d5de 642) const char *p = s->colored.buf; 5906d5de 644) strbuf_add(out, p + head->colored_start, 5906d5de 645) first->colored_start - head->colored_start); 5906d5de 646) strbuf_add(out, p + first->colored_end, 5906d5de 647) head->colored_end - first->colored_end); 5906d5de 649) const char *p = s->plain.buf; 5906d5de 651) strbuf_add(out, p + head->start, first->start - head->start); 5906d5de 652) strbuf_add(out, p + first->end, head->end - first->end); 11f2c0da 657) static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff, bcdd297b 660) size_t i = *hunk_index, delta; 11f2c0da 661) struct hunk *hunk = file_diff->hunk + i; 11f2c0da 663) struct hunk_header *header = &merged->header, *next; bcdd297b 665) if (!use_all && hunk->use != USE_HUNK) 11f2c0da 666) return 0; 11f2c0da 668) *merged = *hunk; 11f2c0da 670) merged->colored_start = merged->colored_end = 0; 11f2c0da 672) for (; i + 1 < file_diff->hunk_nr; i++) { 11f2c0da 673) hunk++; 11f2c0da 674) next = &hunk->header; bcdd297b 682) if ((!use_all && hunk->use != USE_HUNK) || bcdd297b 683) header->new_offset >= next->new_offset + merged->delta || bcdd297b 684) header->new_offset + header->new_count bcdd297b 685) < next->new_offset + merged->delta) bcdd297b 692) if (merged->start < hunk->start && merged->end > hunk->start) { bcdd297b 693) merged->end = hunk->end; bcdd297b 694) merged->colored_end = hunk->colored_end; bcdd297b 695) delta = 0; bcdd297b 697) const char *plain = s->plain.buf; bcdd297b 698) size_t overlapping_line_count = header->new_offset bcdd297b 699) + header->new_count - merged->delta bcdd297b 700) - next->new_offset; bcdd297b 701) size_t overlap_end = hunk->start; bcdd297b 702) size_t overlap_start = overlap_end; bcdd297b 713) for (j = 0; j < overlapping_line_count; j++) { bcdd297b 714) overlap_next = find_next_line(&s->plain, bcdd297b 717) if (overlap_next > hunk->end) bcdd297b 724) if (plain[overlap_end] != ' ') bcdd297b 732) overlap_start = overlap_end; bcdd297b 733) overlap_end = overlap_next; bcdd297b 735) len = overlap_end - overlap_start; bcdd297b 737) if (len > merged->end - merged->start || bcdd297b 738) memcmp(plain + merged->end - len, bcdd297b 752) if (merged->end != s->plain.len) { bcdd297b 753) size_t start = s->plain.len; bcdd297b 755) strbuf_add(&s->plain, plain + merged->start, bcdd297b 756) merged->end - merged->start); bcdd297b 757) plain = s->plain.buf; bcdd297b 758) merged->start = start; bcdd297b 759) merged->end = s->plain.len; bcdd297b 762) strbuf_add(&s->plain, bcdd297b 764) hunk->end - overlap_end); bcdd297b 765) merged->end = s->plain.len; bcdd297b 766) merged->splittable_into += hunk->splittable_into; bcdd297b 767) delta = merged->delta; bcdd297b 768) merged->delta += hunk->delta; 11f2c0da 771) header->old_count = next->old_offset + next->old_count 11f2c0da 772) - header->old_offset; bcdd297b 773) header->new_count = next->new_offset + delta bcdd297b 774) + next->new_count - header->new_offset; 11f2c0da 777) if (i == *hunk_index) 11f2c0da 778) return 0; 11f2c0da 780) *hunk_index = i; 11f2c0da 781) return 1; 80399aec 784) static void reassemble_patch(struct add_p_state *s, bcdd297b 789) size_t save_len = s->plain.len, i; 25ea47af 790) ssize_t delta = 0; 5906d5de 792) render_diff_header(s, file_diff, 0, out); 5906d5de 794) for (i = file_diff->mode_change; i < file_diff->hunk_nr; i++) { 11f2c0da 795) struct hunk merged = { 0 }; 80399aec 797) hunk = file_diff->hunk + i; bcdd297b 798) if (!use_all && hunk->use != USE_HUNK) 25ea47af 799) delta += hunk->header.old_count 25ea47af 800) - hunk->header.new_count; bcdd297b 803) if (merge_hunks(s, file_diff, &i, use_all, &merged)) 11f2c0da 804) hunk = &merged; 25ea47af 806) render_hunk(s, hunk, delta, 0, out); bcdd297b 813) strbuf_setlen(&s->plain, save_len); bcdd297b 815) delta += hunk->delta; f6aa7ecc 818) } 510aeca1 820) static int split_hunk(struct add_p_state *s, struct file_diff *file_diff, 510aeca1 823) int colored = !!s->colored.len, first = 1; 510aeca1 824) struct hunk *hunk = file_diff->hunk + hunk_index; 510aeca1 826) size_t end, colored_end, current, colored_current = 0, context_line_count; 510aeca1 830) if (hunk_index >= file_diff->hunk_nr) 510aeca1 834) if (hunk->splittable_into < 2) 510aeca1 835) return 0; 510aeca1 836) splittable_into = hunk->splittable_into; 510aeca1 838) end = hunk->end; 510aeca1 839) colored_end = hunk->colored_end; 510aeca1 841) remaining = hunk->header; 510aeca1 843) file_diff->hunk_nr += splittable_into - 1; 510aeca1 844) ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr, file_diff->hunk_alloc); 510aeca1 845) if (hunk_index + splittable_into < file_diff->hunk_nr) 510aeca1 846) memmove(file_diff->hunk + hunk_index + splittable_into, 510aeca1 847) file_diff->hunk + hunk_index + 1, 510aeca1 848) (file_diff->hunk_nr - hunk_index - splittable_into) 510aeca1 850) hunk = file_diff->hunk + hunk_index; 510aeca1 851) hunk->splittable_into = 1; 510aeca1 852) memset(hunk + 1, 0, (splittable_into - 1) * sizeof(*hunk)); 510aeca1 854) header = &hunk->header; 510aeca1 855) header->old_count = header->new_count = 0; 510aeca1 857) current = hunk->start; 510aeca1 858) if (colored) 510aeca1 859) colored_current = hunk->colored_start; 510aeca1 860) marker = '\0'; 510aeca1 861) context_line_count = 0; 510aeca1 863) while (splittable_into > 1) { 510aeca1 864) ch = s->plain.buf[current]; 510aeca1 866) if (!ch) 510aeca1 873) if ((marker == '-' || marker == '+') && ch == ' ') { 510aeca1 874) first = 0; 510aeca1 875) hunk[1].start = current; 510aeca1 876) if (colored) 510aeca1 877) hunk[1].colored_start = colored_current; 510aeca1 878) context_line_count = 0; 510aeca1 888) if (marker != ' ' || (ch != '-' && ch != '+')) { 510aeca1 891) if (ch == '\\') 510aeca1 892) ch = marker ? marker : ' '; 510aeca1 895) if (ch == ' ') 510aeca1 896) context_line_count++; 510aeca1 897) else if (ch == '-') 510aeca1 898) header->old_count++; 510aeca1 899) else if (ch == '+') 510aeca1 900) header->new_count++; 510aeca1 903) marker = ch; 510aeca1 904) current = find_next_line(&s->plain, current); 510aeca1 905) if (colored) 510aeca1 906) colored_current = 510aeca1 907) find_next_line(&s->colored, 510aeca1 909) continue; 510aeca1 919) if (first) { 510aeca1 920) if (header->old_count || header->new_count) 510aeca1 925) header->old_count = context_line_count; 510aeca1 926) header->new_count = context_line_count; 510aeca1 927) context_line_count = 0; 510aeca1 928) first = 0; 510aeca1 929) goto next_hunk_line; 510aeca1 932) remaining.old_offset += header->old_count; 510aeca1 933) remaining.old_count -= header->old_count; 510aeca1 934) remaining.new_offset += header->new_count; 510aeca1 935) remaining.new_count -= header->new_count; 510aeca1 938) hunk[1].header.old_offset = 510aeca1 939) header->old_offset + header->old_count; 510aeca1 940) hunk[1].header.new_offset = 510aeca1 941) header->new_offset + header->new_count; 510aeca1 944) header->old_count += context_line_count; 510aeca1 945) header->new_count += context_line_count; 510aeca1 947) hunk->end = current; 510aeca1 948) if (colored) 510aeca1 949) hunk->colored_end = colored_current; 510aeca1 951) hunk++; 510aeca1 952) hunk->splittable_into = 1; 510aeca1 953) hunk->use = hunk[-1].use; 510aeca1 954) header = &hunk->header; 510aeca1 956) header->old_count = header->new_count = context_line_count; 510aeca1 957) context_line_count = 0; 510aeca1 959) splittable_into--; 510aeca1 960) marker = ch; 510aeca1 964) if (header->old_offset != remaining.old_offset) 510aeca1 967) if (header->new_offset != remaining.new_offset) 510aeca1 970) header->old_count = remaining.old_count; 510aeca1 971) header->new_count = remaining.new_count; 510aeca1 972) hunk->end = end; 510aeca1 973) if (colored) 510aeca1 974) hunk->colored_end = colored_end; 510aeca1 976) return 0; bcdd297b 979) static void recolor_hunk(struct add_p_state *s, struct hunk *hunk) bcdd297b 981) const char *plain = s->plain.buf; bcdd297b 984) if (!s->colored.len) bcdd297b 985) return; bcdd297b 987) hunk->colored_start = s->colored.len; bcdd297b 988) for (current = hunk->start; current < hunk->end; ) { bcdd297b 989) for (eol = current; eol < hunk->end; eol++) bcdd297b 990) if (plain[eol] == '\n') bcdd297b 991) break; bcdd297b 992) next = eol + (eol < hunk->end); bcdd297b 993) if (eol > current && plain[eol - 1] == '\r') bcdd297b 994) eol--; bcdd297b 996) strbuf_addstr(&s->colored, bcdd297b 997) plain[current] == '-' ? bcdd297b 999) plain[current] == '+' ? bcdd297b 1002) strbuf_add(&s->colored, plain + current, eol - current); bcdd297b 1003) strbuf_addstr(&s->colored, GIT_COLOR_RESET); bcdd297b 1004) if (next > eol) bcdd297b 1005) strbuf_add(&s->colored, plain + eol, next - eol); bcdd297b 1006) current = next; bcdd297b 1008) hunk->colored_end = s->colored.len; bcdd297b 1011) static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk) bcdd297b 1015) strbuf_reset(&s->buf); bcdd297b 1016) strbuf_commented_addf(&s->buf, _("Manual hunk edit mode -- see bottom for " bcdd297b 1018) render_hunk(s, hunk, 0, 0, &s->buf); bcdd297b 1019) strbuf_commented_addf(&s->buf, 572bdc3a 1025) s->mode->is_reverse ? '+' : '-', 572bdc3a 1026) s->mode->is_reverse ? '-' : '+', 572bdc3a 1028) strbuf_commented_addf(&s->buf, "%s", _(s->mode->edit_hunk_hint)); bcdd297b 1033) strbuf_commented_addf(&s->buf, bcdd297b 1040) if (strbuf_edit_interactively(&s->buf, "addp-hunk-edit.diff", NULL) < 0) bcdd297b 1041) return -1; bcdd297b 1044) hunk->start = s->plain.len; bcdd297b 1045) for (i = 0; i < s->buf.len; ) { bcdd297b 1046) size_t next = find_next_line(&s->buf, i); bcdd297b 1048) if (s->buf.buf[i] != comment_line_char) bcdd297b 1049) strbuf_add(&s->plain, s->buf.buf + i, next - i); bcdd297b 1050) i = next; bcdd297b 1053) hunk->end = s->plain.len; bcdd297b 1054) if (hunk->end == hunk->start) bcdd297b 1056) return 0; bcdd297b 1058) recolor_hunk(s, hunk); bcdd297b 1065) if (s->plain.buf[hunk->start] == '@' && bcdd297b 1066) parse_hunk_header(s, hunk) < 0) bcdd297b 1069) return 1; bcdd297b 1072) static ssize_t recount_edited_hunk(struct add_p_state *s, struct hunk *hunk, bcdd297b 1075) struct hunk_header *header = &hunk->header; bcdd297b 1078) header->old_count = header->new_count = 0; bcdd297b 1079) for (i = hunk->start; i < hunk->end; ) { bcdd297b 1080) switch (s->plain.buf[i]) { bcdd297b 1082) header->old_count++; bcdd297b 1083) break; bcdd297b 1085) header->new_count++; bcdd297b 1086) break; bcdd297b 1088) header->old_count++; bcdd297b 1089) header->new_count++; bcdd297b 1090) break; bcdd297b 1093) i = find_next_line(&s->plain, i); bcdd297b 1096) return orig_old_count - orig_new_count bcdd297b 1097) - header->old_count + header->new_count; bcdd297b 1100) static int run_apply_check(struct add_p_state *s, bcdd297b 1103) struct child_process cp = CHILD_PROCESS_INIT; bcdd297b 1105) strbuf_reset(&s->buf); bcdd297b 1106) reassemble_patch(s, file_diff, 1, &s->buf); bcdd297b 1108) setup_child_process(s, &cp, 572bdc3a 1110) argv_array_pushv(&cp.args, s->mode->apply_check); bcdd297b 1111) if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0)) bcdd297b 1114) return 0; bcdd297b 1117) static int prompt_yesno(struct add_p_state *s, const char *prompt) bcdd297b 1120) color_fprintf(stdout, s->s.prompt_color, "%s", _(prompt)); bcdd297b 1121) fflush(stdout); bcdd297b 1122) if (strbuf_getline(&s->answer, stdin) == EOF) bcdd297b 1123) return -1; bcdd297b 1124) strbuf_trim_trailing_newline(&s->answer); bcdd297b 1125) switch (tolower(s->answer.buf[0])) { bcdd297b 1126) case 'n': return 0; bcdd297b 1127) case 'y': return 1; bcdd297b 1129) } bcdd297b 1132) static int edit_hunk_loop(struct add_p_state *s, bcdd297b 1135) size_t plain_len = s->plain.len, colored_len = s->colored.len; bcdd297b 1138) backup = *hunk; bcdd297b 1141) int res = edit_hunk_manually(s, hunk); bcdd297b 1142) if (res == 0) { bcdd297b 1144) *hunk = backup; bcdd297b 1145) return -1; bcdd297b 1148) if (res > 0) { bcdd297b 1149) hunk->delta += bcdd297b 1150) recount_edited_hunk(s, hunk, bcdd297b 1153) if (!run_apply_check(s, file_diff)) bcdd297b 1154) return 0; bcdd297b 1158) strbuf_setlen(&s->plain, plain_len); bcdd297b 1159) strbuf_setlen(&s->colored, colored_len); bcdd297b 1160) *hunk = backup; bcdd297b 1169) res = prompt_yesno(s, _("Your edited hunk does not apply. " bcdd297b 1172) if (res < 1) bcdd297b 1173) return -1; bcdd297b 1174) } ae4780e8 1177) static int apply_for_checkout(struct add_p_state *s, struct strbuf *diff, ae4780e8 1180) const char *reverse = is_reverse ? "-R" : NULL; ae4780e8 1181) struct child_process check_index = CHILD_PROCESS_INIT; ae4780e8 1182) struct child_process check_worktree = CHILD_PROCESS_INIT; ae4780e8 1183) struct child_process apply_index = CHILD_PROCESS_INIT; ae4780e8 1184) struct child_process apply_worktree = CHILD_PROCESS_INIT; ae4780e8 1187) setup_child_process(s, &check_index, ae4780e8 1189) applies_index = !pipe_command(&check_index, diff->buf, diff->len, ae4780e8 1192) setup_child_process(s, &check_worktree, ae4780e8 1194) applies_worktree = !pipe_command(&check_worktree, diff->buf, diff->len, ae4780e8 1197) if (applies_worktree && applies_index) { ae4780e8 1198) setup_child_process(s, &apply_index, ae4780e8 1200) pipe_command(&apply_index, diff->buf, diff->len, ae4780e8 1203) setup_child_process(s, &apply_worktree, ae4780e8 1205) pipe_command(&apply_worktree, diff->buf, diff->len, ae4780e8 1208) return 1; ae4780e8 1211) if (!applies_index) { ae4780e8 1212) err(s, _("The selected hunks do not apply to the index!")); ae4780e8 1213) if (prompt_yesno(s, _("Apply them to the worktree " ae4780e8 1215) setup_child_process(s, &apply_worktree, ae4780e8 1217) return pipe_command(&apply_worktree, diff->buf, ae4780e8 1220) err(s, _("Nothing was applied.\n")); ae4780e8 1223) fwrite(diff->buf, diff->len, 1, stderr); ae4780e8 1225) return 0; 9254bdfb 1230) static void summarize_hunk(struct add_p_state *s, struct hunk *hunk, 9254bdfb 1233) struct hunk_header *header = &hunk->header; 9254bdfb 1234) struct strbuf *plain = &s->plain; 9254bdfb 1235) size_t len = out->len, i; 9254bdfb 1237) strbuf_addf(out, " -%lu,%lu +%lu,%lu ", 9254bdfb 1240) if (out->len - len < SUMMARY_HEADER_WIDTH) 9254bdfb 1241) strbuf_addchars(out, ' ', 9254bdfb 1242) SUMMARY_HEADER_WIDTH + len - out->len); 9254bdfb 1243) for (i = hunk->start; i < hunk->end; i = find_next_line(plain, i)) 9254bdfb 1244) if (plain->buf[i] != ' ') 9254bdfb 1245) break; 9254bdfb 1246) if (i < hunk->end) 9254bdfb 1247) strbuf_add(out, plain->buf + i, find_next_line(plain, i) - i); 9254bdfb 1248) if (out->len - len > SUMMARY_LINE_WIDTH) 9254bdfb 1249) strbuf_setlen(out, len + SUMMARY_LINE_WIDTH); 9254bdfb 1250) strbuf_complete_line(out); 9254bdfb 1251) } 9254bdfb 1254) static size_t display_hunks(struct add_p_state *s, 9254bdfb 1257) size_t end_index = start_index + DISPLAY_HUNKS_LINES; 9254bdfb 1259) if (end_index > file_diff->hunk_nr) 9254bdfb 1260) end_index = file_diff->hunk_nr; 9254bdfb 1262) while (start_index < end_index) { 9254bdfb 1263) struct hunk *hunk = file_diff->hunk + start_index++; 9254bdfb 1265) strbuf_reset(&s->buf); 9254bdfb 1266) strbuf_addf(&s->buf, "%c%2d: ", hunk->use == USE_HUNK ? '+' 9254bdfb 1267) : hunk->use == SKIP_HUNK ? '-' : ' ', 9254bdfb 1269) summarize_hunk(s, hunk, &s->buf); 9254bdfb 1270) fputs(s->buf.buf, stdout); 9254bdfb 1273) return end_index; 80399aec 1287) static int patch_update_file(struct add_p_state *s, f6aa7ecc 1290) size_t hunk_index = 0; f6aa7ecc 1294) struct child_process cp = CHILD_PROCESS_INIT; ade246ef 1295) int colored = !!s->colored.len, quit = 0; 80399aec 1298) if (!file_diff->hunk_nr) f6aa7ecc 1299) return 0; f6aa7ecc 1301) strbuf_reset(&s->buf); 5906d5de 1302) render_diff_header(s, file_diff, colored, &s->buf); f6aa7ecc 1303) fputs(s->buf.buf, stdout); 80399aec 1305) if (hunk_index >= file_diff->hunk_nr) f6aa7ecc 1306) hunk_index = 0; 80399aec 1307) hunk = file_diff->hunk + hunk_index; f6aa7ecc 1309) undecided_previous = -1; f6aa7ecc 1310) for (i = hunk_index - 1; i >= 0; i--) 80399aec 1311) if (file_diff->hunk[i].use == UNDECIDED_HUNK) { f6aa7ecc 1312) undecided_previous = i; f6aa7ecc 1313) break; f6aa7ecc 1316) undecided_next = -1; 80399aec 1317) for (i = hunk_index + 1; i < file_diff->hunk_nr; i++) 80399aec 1318) if (file_diff->hunk[i].use == UNDECIDED_HUNK) { f6aa7ecc 1319) undecided_next = i; f6aa7ecc 1320) break; f6aa7ecc 1324) if (undecided_previous < 0 && undecided_next < 0 && f6aa7ecc 1325) hunk->use != UNDECIDED_HUNK) f6aa7ecc 1326) break; f6aa7ecc 1328) strbuf_reset(&s->buf); 25ea47af 1329) render_hunk(s, hunk, 0, colored, &s->buf); f6aa7ecc 1330) fputs(s->buf.buf, stdout); f6aa7ecc 1332) strbuf_reset(&s->buf); f6aa7ecc 1333) if (undecided_previous >= 0) f6aa7ecc 1334) strbuf_addstr(&s->buf, ",k"); f6aa7ecc 1335) if (hunk_index) f6aa7ecc 1336) strbuf_addstr(&s->buf, ",K"); f6aa7ecc 1337) if (undecided_next >= 0) f6aa7ecc 1338) strbuf_addstr(&s->buf, ",j"); 80399aec 1339) if (hunk_index + 1 < file_diff->hunk_nr) f6aa7ecc 1340) strbuf_addstr(&s->buf, ",J"); 9254bdfb 1341) if (file_diff->hunk_nr > 1) d6cf8733 1342) strbuf_addstr(&s->buf, ",g,/"); 510aeca1 1343) if (hunk->splittable_into > 1) 510aeca1 1344) strbuf_addstr(&s->buf, ",s"); bcdd297b 1345) if (hunk_index + 1 > file_diff->mode_change && bcdd297b 1346) !file_diff->deleted) bcdd297b 1347) strbuf_addstr(&s->buf, ",e"); 0ecd9d27 1349) if (file_diff->deleted) 0ecd9d27 1350) prompt_mode_type = PROMPT_DELETION; 0ecd9d27 1351) else if (file_diff->mode_change && !hunk_index) 0ecd9d27 1352) prompt_mode_type = PROMPT_MODE_CHANGE; 0ecd9d27 1354) prompt_mode_type = PROMPT_HUNK; 12c24cf8 1356) color_fprintf(stdout, s->s.prompt_color, 80399aec 1359) (uintmax_t)file_diff->hunk_nr); 12c24cf8 1360) color_fprintf(stdout, s->s.prompt_color, 572bdc3a 1361) _(s->mode->prompt_mode[prompt_mode_type]), f6aa7ecc 1363) fflush(stdout); f6aa7ecc 1364) if (strbuf_getline(&s->answer, stdin) == EOF) f6aa7ecc 1365) break; f6aa7ecc 1366) strbuf_trim_trailing_newline(&s->answer); f6aa7ecc 1368) if (!s->answer.len) f6aa7ecc 1369) continue; f6aa7ecc 1370) ch = tolower(s->answer.buf[0]); f6aa7ecc 1371) if (ch == 'y') { f6aa7ecc 1372) hunk->use = USE_HUNK; f6aa7ecc 1374) hunk_index = undecided_next < 0 ? 80399aec 1375) file_diff->hunk_nr : undecided_next; f6aa7ecc 1376) } else if (ch == 'n') { f6aa7ecc 1377) hunk->use = SKIP_HUNK; f6aa7ecc 1378) goto soft_increment; f6aa7ecc 1379) } else if (ch == 'a') { 80399aec 1380) for (; hunk_index < file_diff->hunk_nr; hunk_index++) { 80399aec 1381) hunk = file_diff->hunk + hunk_index; f6aa7ecc 1382) if (hunk->use == UNDECIDED_HUNK) f6aa7ecc 1383) hunk->use = USE_HUNK; ade246ef 1385) } else if (ch == 'd' || ch == 'q') { 80399aec 1386) for (; hunk_index < file_diff->hunk_nr; hunk_index++) { 80399aec 1387) hunk = file_diff->hunk + hunk_index; f6aa7ecc 1388) if (hunk->use == UNDECIDED_HUNK) f6aa7ecc 1389) hunk->use = SKIP_HUNK; ade246ef 1391) if (ch == 'q') { ade246ef 1392) quit = 1; ade246ef 1393) break; 7584dd3c 1395) } else if (s->answer.buf[0] == 'K') { 7584dd3c 1396) if (hunk_index) 7584dd3c 1397) hunk_index--; 7584dd3c 1399) err(s, _("No previous hunk")); 7584dd3c 1400) } else if (s->answer.buf[0] == 'J') { 80399aec 1401) if (hunk_index + 1 < file_diff->hunk_nr) 7584dd3c 1402) hunk_index++; 7584dd3c 1404) err(s, _("No next hunk")); 7584dd3c 1405) } else if (s->answer.buf[0] == 'k') { 7584dd3c 1406) if (undecided_previous >= 0) 7584dd3c 1407) hunk_index = undecided_previous; 7584dd3c 1409) err(s, _("No previous hunk")); 7584dd3c 1410) } else if (s->answer.buf[0] == 'j') { 7584dd3c 1411) if (undecided_next >= 0) 7584dd3c 1412) hunk_index = undecided_next; 7584dd3c 1414) err(s, _("No next hunk")); 9254bdfb 1415) } else if (s->answer.buf[0] == 'g') { 9254bdfb 1419) if (file_diff->hunk_nr < 2) { 9254bdfb 1420) err(s, _("No other hunks to goto")); 9254bdfb 1421) continue; 9254bdfb 1423) strbuf_remove(&s->answer, 0, 1); 9254bdfb 1424) strbuf_trim(&s->answer); 9254bdfb 1425) i = hunk_index - DISPLAY_HUNKS_LINES / 2; 9254bdfb 1426) if (i < file_diff->mode_change) 9254bdfb 1427) i = file_diff->mode_change; 9254bdfb 1428) while (s->answer.len == 0) { 9254bdfb 1429) i = display_hunks(s, file_diff, i); 9254bdfb 1430) printf("%s", i < file_diff->hunk_nr ? 9254bdfb 1433) fflush(stdout); 9254bdfb 1434) if (strbuf_getline(&s->answer, 9254bdfb 1436) break; 9254bdfb 1437) strbuf_trim_trailing_newline(&s->answer); 9254bdfb 1440) strbuf_trim(&s->answer); 9254bdfb 1441) response = strtoul(s->answer.buf, &pend, 10); 9254bdfb 1442) if (*pend || pend == s->answer.buf) 9254bdfb 1443) err(s, _("Invalid number: '%s'"), 9254bdfb 1445) else if (0 < response && response <= file_diff->hunk_nr) 9254bdfb 1446) hunk_index = response - 1; 9254bdfb 1448) err(s, Q_("Sorry, only %d hunk available.", 9254bdfb 1451) (int)file_diff->hunk_nr); d6cf8733 1452) } else if (s->answer.buf[0] == '/') { d6cf8733 1456) if (file_diff->hunk_nr < 2) { d6cf8733 1457) err(s, _("No other hunks to search")); d6cf8733 1458) continue; d6cf8733 1460) strbuf_remove(&s->answer, 0, 1); d6cf8733 1461) strbuf_trim_trailing_newline(&s->answer); d6cf8733 1462) if (s->answer.len == 0) { d6cf8733 1463) printf("%s", _("search for regex? ")); d6cf8733 1464) fflush(stdout); d6cf8733 1465) if (strbuf_getline(&s->answer, d6cf8733 1467) break; d6cf8733 1468) strbuf_trim_trailing_newline(&s->answer); d6cf8733 1469) if (s->answer.len == 0) d6cf8733 1470) continue; d6cf8733 1472) ret = regcomp(®ex, s->answer.buf, d6cf8733 1474) if (ret) { d6cf8733 1478) err(s, _("Malformed search regexp %s: %s"), d6cf8733 1480) continue; d6cf8733 1482) i = hunk_index; d6cf8733 1485) render_hunk(s, file_diff->hunk + i, 0, 0, d6cf8733 1487) if (regexec(®ex, s->buf.buf, 0, NULL, 0) d6cf8733 1489) break; d6cf8733 1490) i++; d6cf8733 1491) if (i == file_diff->hunk_nr) d6cf8733 1492) i = 0; d6cf8733 1493) if (i != hunk_index) d6cf8733 1494) continue; d6cf8733 1495) err(s, _("No hunk matches the given pattern")); d6cf8733 1496) break; d6cf8733 1497) } d6cf8733 1498) hunk_index = i; 510aeca1 1499) } else if (s->answer.buf[0] == 's') { 510aeca1 1500) size_t splittable_into = hunk->splittable_into; 510aeca1 1501) if (splittable_into < 2) 510aeca1 1502) err(s, _("Sorry, cannot split this hunk")); 510aeca1 1503) else if (!split_hunk(s, file_diff, 510aeca1 1504) hunk - file_diff->hunk)) 510aeca1 1505) color_fprintf_ln(stdout, s->s.header_color, bcdd297b 1508) } else if (s->answer.buf[0] == 'e') { bcdd297b 1509) if (hunk_index + 1 == file_diff->mode_change) bcdd297b 1510) err(s, _("Sorry, cannot edit this hunk")); bcdd297b 1511) else if (edit_hunk_loop(s, file_diff, hunk) >= 0) { bcdd297b 1512) hunk->use = USE_HUNK; bcdd297b 1513) goto soft_increment; 54d9d9b2 1516) const char *p = _(help_patch_remainder), *eol = p; 54d9d9b2 1518) color_fprintf(stdout, s->s.help_color, "%s", 572bdc3a 1519) _(s->mode->help_patch_text)); 54d9d9b2 1525) for (; *p; p = eol + (*eol == '\n')) { 54d9d9b2 1526) eol = strchrnul(p, '\n'); 54d9d9b2 1533) if (*p != '?' && !strchr(s->buf.buf, *p)) 54d9d9b2 1534) continue; 54d9d9b2 1536) color_fprintf_ln(stdout, s->s.help_color, 54d9d9b2 1537) "%.*s", (int)(eol - p), p); f6aa7ecc 1540) } 80399aec 1543) for (i = 0; i < file_diff->hunk_nr; i++) 80399aec 1544) if (file_diff->hunk[i].use == USE_HUNK) f6aa7ecc 1545) break; 80399aec 1547) if (i < file_diff->hunk_nr) { f6aa7ecc 1549) strbuf_reset(&s->buf); bcdd297b 1550) reassemble_patch(s, file_diff, 0, &s->buf); 25ea47af 1552) discard_index(s->s.r->index); ae4780e8 1553) if (s->mode->apply_for_checkout) ae4780e8 1554) apply_for_checkout(s, &s->buf, ae4780e8 1555) s->mode->is_reverse); ae4780e8 1557) setup_child_process(s, &cp, "apply", NULL); ae4780e8 1558) argv_array_pushv(&cp.args, s->mode->apply); ae4780e8 1559) if (pipe_command(&cp, s->buf.buf, s->buf.len, 25ea47af 1563) if (!repo_read_index(s->s.r)) 25ea47af 1564) repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0, f6aa7ecc 1568) putchar('\n'); ade246ef 1569) return quit; 572bdc3a 1572) int run_add_p(struct repository *r, enum add_p_mode mode, 25ea47af 1575) struct add_p_state s = { 2e408319 1578) size_t i, binary_count = 0; 25ea47af 1580) init_add_i_state(&s.s, r); 169205be 1582) if (mode == ADD_P_STASH) 169205be 1583) s.mode = &patch_mode_stash; 169205be 1584) else if (mode == ADD_P_RESET) { 169205be 1585) if (!revision || !strcmp(revision, "HEAD")) 169205be 1586) s.mode = &patch_mode_reset_head; 169205be 1588) s.mode = &patch_mode_reset_nothead; ae4780e8 1589) } else if (mode == ADD_P_CHECKOUT) { ae4780e8 1590) if (!revision) ae4780e8 1591) s.mode = &patch_mode_checkout_index; ae4780e8 1592) else if (!strcmp(revision, "HEAD")) ae4780e8 1593) s.mode = &patch_mode_checkout_head; ae4780e8 1595) s.mode = &patch_mode_checkout_nothead; 1c6d07b9 1596) } else if (mode == ADD_P_WORKTREE) { 1c6d07b9 1597) if (!revision) 1c6d07b9 1598) s.mode = &patch_mode_checkout_index; 1c6d07b9 1599) else if (!strcmp(revision, "HEAD")) 1c6d07b9 1600) s.mode = &patch_mode_worktree_head; 1c6d07b9 1602) s.mode = &patch_mode_worktree_nothead; 169205be 1604) s.mode = &patch_mode_stage; 572bdc3a 1605) s.revision = revision; f6aa7ecc 1607) if (discard_index(r->index) < 0 || repo_read_index(r) < 0 || 169205be 1608) (!s.mode->index_only && 169205be 1609) repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1, 169205be 1610) NULL, NULL, NULL) < 0) || f6aa7ecc 1611) parse_diff(&s, ps) < 0) { f6aa7ecc 1612) strbuf_release(&s.plain); e3bd11b4 1613) strbuf_release(&s.colored); f6aa7ecc 1614) return -1; 80399aec 1617) for (i = 0; i < s.file_diff_nr; i++) 2e408319 1618) if (s.file_diff[i].binary && !s.file_diff[i].hunk_nr) 2e408319 1619) binary_count++; 2e408319 1620) else if (patch_update_file(&s, s.file_diff + i)) 80399aec 1621) break; 2e408319 1623) if (s.file_diff_nr == 0) 2e408319 1624) fprintf(stderr, _("No changes.\n")); 2e408319 1625) else if (binary_count == s.file_diff_nr) 2e408319 1626) fprintf(stderr, _("Only binary files changed.\n")); f6aa7ecc 1628) strbuf_release(&s.answer); f6aa7ecc 1629) strbuf_release(&s.buf); f6aa7ecc 1630) strbuf_release(&s.plain); e3bd11b4 1631) strbuf_release(&s.colored); f6aa7ecc 1632) return 0; builtin/add.c f6aa7ecc 202) if (!patch_mode) 572bdc3a 205) if (!strcmp(patch_mode, "--patch")) 572bdc3a 206) mode = ADD_P_STAGE; 169205be 207) else if (!strcmp(patch_mode, "--patch=stash")) 169205be 208) mode = ADD_P_STASH; 169205be 209) else if (!strcmp(patch_mode, "--patch=reset")) 169205be 210) mode = ADD_P_RESET; ae4780e8 211) else if (!strcmp(patch_mode, "--patch=checkout")) ae4780e8 212) mode = ADD_P_CHECKOUT; 1c6d07b9 213) else if (!strcmp(patch_mode, "--patch=worktree")) 1c6d07b9 214) mode = ADD_P_WORKTREE; 572bdc3a 218) return !!run_add_p(the_repository, mode, revision, pathspec); 09032028 450) parse_pathspec(&pathspec, 0, 09032028 456) return run_add_interactive(NULL, "--patch=stash", &pathspec); builtin/commit.c builtin/grep.c builtin/stash.c c1f1a9b0 1026) setenv(INDEX_ENVIRONMENT, old_index_env, 1); packfile.c beebb9d2 1465) return; protocol.c read-cache.c ee70c128 1756) if (advice_unknown_index_extension) { remote-curl.c 6da1f1a9 354) return 0; sequencer.c 430b75f7 1583) return -1; sha1-file.c beebb9d2 1431) return; beebb9d2 1440) return; strbuf.c b38dd9e7 1129) int strbuf_edit_interactively(struct strbuf *buffer, const char *path, b38dd9e7 1132) char *path2 = NULL; b38dd9e7 1133) int fd, res = 0; b38dd9e7 1135) if (!is_absolute_path(path)) b38dd9e7 1136) path = path2 = xstrdup(git_path("%s", path)); b38dd9e7 1138) fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666); b38dd9e7 1139) if (fd < 0) b38dd9e7 1140) res = error_errno(_("could not open '%s' for writing"), path); b38dd9e7 1141) else if (write_in_full(fd, buffer->buf, buffer->len) < 0) { b38dd9e7 1142) res = error_errno(_("could not write to '%s'"), path); b38dd9e7 1143) close(fd); b38dd9e7 1144) } else if (close(fd) < 0) b38dd9e7 1145) res = error_errno(_("could not close '%s'"), path); b38dd9e7 1147) strbuf_reset(buffer); b38dd9e7 1148) if (launch_editor(path, buffer, env) < 0) b38dd9e7 1149) res = error_errno(_("could not edit '%s'"), path); b38dd9e7 1150) unlink(path); b38dd9e7 1153) free(path2); b38dd9e7 1154) return res; Commits introducing uncovered code: Emily Shaffer fae9bc5a grep: support the --pathspec-from-file option Johannes Schindelin 25ea47af built-in add -p: adjust hunk headers as needed Johannes Schindelin c1f1a9b0 built-in stash: use the built-in `git add -p` if so configured Johannes Schindelin 09032028 legacy stash -p: respect the add.interactive.usebuiltin setting Johannes Schindelin 1c6d07b9 built-in add -p: implement the "worktree" patch modes Johannes Schindelin 169205be built-in add -p: implement the "stash" and "reset" patch modes Johannes Schindelin 54d9d9b2 built-in add -p: only show the applicable parts of the help text Johannes Schindelin 12c24cf8 built-in add -p: color the prompt and the help text Johannes Schindelin 0ecd9d27 built-in add -p: show different prompts for mode changes and deletions Johannes Schindelin d6cf8733 built-in add -p: implement the '/' ("search regex") command Johannes Schindelin b38dd9e7 strbuf: add a helper function to call the editor "on an strbuf" Johannes Schindelin 9254bdfb built-in add -p: implement the 'g' ("goto") command Johannes Schindelin ae4780e8 built-in add -p: implement the "checkout" patch modes Johannes Schindelin ade246ef built-in add -p: implement the 'q' ("quit") command Johannes Schindelin 2e408319 built-in add -p: show helpful hint when nothing can be staged Johannes Schindelin bcdd297b built-in add -p: implement hunk editing Johannes Schindelin 1942ee44 built-in add -i: wire up the new C code for the `patch` command Johannes Schindelin 11f2c0da built-in add -p: coalesce hunks after splitting them Johannes Schindelin 7584dd3c built-in add -p: offer a helpful error message when hunk navigation failed Johannes Schindelin f6aa7ecc built-in add -i: start implementing the `patch` functionality in C Johannes Schindelin 572bdc3a built-in add -p: prepare for patch modes other than "stage" Johannes Schindelin e3bd11b4 built-in add -p: show colored hunks by default Johannes Schindelin 510aeca1 built-in add -p: implement the hunk splitting feature Johannes Schindelin 80399aec built-in add -p: support multi-file diffs Johannes Schindelin 47dc4fd5 built-in add -p: handle deleted empty files Johannes Schindelin 5906d5de built-in app -p: allow selecting a mode change as a "hunk" Jonathan Nieder ee70c128 index: offer advice for unknown index extensions Josh Steadmon 6da1f1a9 protocol: advertise multiple supported versions Matheus Tavares beebb9d2 object-store: allow threaded access to object reading Phillip Wood 430b75f7 commit: give correct advice for empty commit during a rebase Uncovered code in 'jch' not in 'next' -------------------------------------------------------- builtin/config.c 3bf986d6 329) FREE_AND_NULL(cmd_line_value.regexp); 3bcdd852 330) return CONFIG_INVALID_PATTERN; 3bcdd852 375) goto free_strings; builtin/merge-base.c fed842f0 128) return 1; rebase-interactive.c 0d50cf5e 210) goto out; 0d50cf5e 215) goto out; 0d50cf5e 224) fprintf(stderr, _(edit_todo_list_advice)); refs.c Commits introducing uncovered code: Alban Gruin 5ef50d63 rebase-interactive: warn if commit is dropped with `rebase --edit-todo' Alban Gruin 0d50cf5e sequencer: move check_todo_list_from_file() to rebase-interactive.c Alex Torok fed842f0 rebase: fix --fork-point with short refname Martin Ågren 3bf986d6 builtin/config: collect "value_regexp" data in a struct Martin Ågren 3bcdd852 builtin/config: extract `handle_value_regex()` from `get_value()` Uncovered code in 'next' not in 'master' -------------------------------------------------------- builtin/add.c builtin/bisect--helper.c 51a0a4ed 177) return -1; builtin/checkout.c builtin/clone.c d89f09c8 753) result = 1; d89f09c8 1132) return 1; builtin/pack-objects.c 4f0bd8b9 1124) return 1; 4f0bd8b9 2681) (reuse_packfile_bitmap && 4f0bd8b9 2682) bitmap_walk_contains(bitmap_git, reuse_packfile_bitmap, oid)); 7cb9754e 2834) allow_pack_reuse = git_config_bool(k, v); 7cb9754e 2835) return 0; builtin/sparse-checkout.c e091228e 85) return 0; bab3c359 221) return 1; bab3c359 275) return 1; 190a65f9 337) strihash(e->pattern) : af09ce24 352) return; dir.c 96cc8ab5 656) pl->use_cone_patterns = 0; 96cc8ab5 658) goto clear_hashmaps; 190a65f9 669) strihash(translated->pattern) : 96cc8ab5 682) hashmap_add(&pl->parent_hashmap, &translated->ent); 96cc8ab5 683) hashmap_remove(&pl->recursive_hashmap, &translated->ent, &data); 96cc8ab5 684) free(data); 96cc8ab5 685) return; 96cc8ab5 691) goto clear_hashmaps; 190a65f9 700) strihash(translated->pattern) : 96cc8ab5 709) hashmap_remove(&pl->parent_hashmap, &translated->ent, &data); 96cc8ab5 710) free(data); 96cc8ab5 711) free(translated); 96cc8ab5 1273) return MATCHED; pack-bitmap.c 4f0bd8b9 808) return; 4f0bd8b9 811) return; 4f0bd8b9 823) return; 4f0bd8b9 861) i = bitmap_git->pack->num_objects / BITS_IN_EWORD; 7b143c16 903) return 0; Commits introducing uncovered code: Alexandr Miloslavskiy bebb5d6d add: support the --pathspec-from-file option Derrick Stolee d89f09c8 clone: add --sparse mode Derrick Stolee e091228e sparse-checkout: update working directory in-process Derrick Stolee bab3c359 sparse-checkout: create 'init' subcommand Derrick Stolee 416adc87 sparse-checkout: update working directory in-process for 'init' Derrick Stolee 190a65f9 sparse-checkout: respect core.ignoreCase in cone mode Derrick Stolee af09ce24 sparse-checkout: init and set in cone mode Derrick Stolee 72918c1a sparse-checkout: create 'disable' subcommand Derrick Stolee 94c0956b sparse-checkout: create builtin with 'list' subcommand Derrick Stolee 96cc8ab5 sparse-checkout: use hashmaps for cone patterns Jeff King 4f0bd8b9 pack-objects: improve partial packfile reuse Jeff King 7cb9754e pack-objects: introduce pack.allowPackReuse Jeff King 7b143c16 pack-bitmap: introduce bitmap_walk_contains() Tanushree Tumane 51a0a4ed bisect--helper: avoid use-after-free Uncovered code in 'master' not in 'master@{1}' -------------------------------------------------------- add-interactive.c f37c2264 88) FREE_AND_NULL(list->selected); f37c2264 195) static void list(struct add_i_state *s, struct string_list *list, int *selected, f37c2264 208) opts->print_item(i, selected ? selected[i] : 0, list->items + i, f37c2264 249) int singleton = opts->flags & SINGLETON; f37c2264 250) int immediate = opts->flags & IMMEDIATE; f37c2264 253) ssize_t res = singleton ? LIST_AND_CHOOSE_ERROR : 0; f37c2264 255) if (!singleton) { f37c2264 256) free(items->selected); f37c2264 257) CALLOC_ARRAY(items->selected, items->items.nr); f37c2264 260) if (singleton && !immediate) f37c2264 270) list(s, &items->items, items->selected, &opts->list_opts); f37c2264 273) fputs(singleton ? "> " : ">> ", stdout); f37c2264 278) if (immediate) f37c2264 279) res = LIST_AND_CHOOSE_QUIT; f37c2264 295) int choose = 1; f37c2264 297) ssize_t from = -1, to = -1; f37c2264 307) if (*p == '-') { f37c2264 308) choose = 0; f37c2264 309) p++; f37c2264 310) sep--; f37c2264 313) if (sep == 1 && *p == '*') { f37c2264 314) from = 0; f37c2264 315) to = items->items.nr; f37c2264 316) } else if (isdigit(*p)) { f37c2264 327) from = strtoul(p, &endp, 10) - 1; f37c2264 328) if (endp == p + sep) f37c2264 329) to = from + 1; f37c2264 330) else if (*endp == '-') { f37c2264 331) to = strtoul(++endp, &endp, 10); f37c2264 333) if (endp != p + sep) f37c2264 334) from = -1; f37c2264 340) if (from < 0) { f37c2264 341) from = find_unique(p, items); f37c2264 342) if (from >= 0) f37c2264 343) to = from + 1; f37c2264 346) if (from < 0 || from >= items->items.nr || f37c2264 347) (singleton && from + 1 != to)) { f37c2264 350) break; f37c2264 351) } else if (singleton) { f37c2264 352) res = from; f37c2264 356) if (to > items->items.nr) f37c2264 357) to = items->items.nr; f37c2264 359) for (; from < to; from++) f37c2264 360) if (items->selected[from] != choose) { f37c2264 361) items->selected[from] = choose; f37c2264 362) res += choose ? +1 : -1; f37c2264 368) if ((immediate && res != LIST_AND_CHOOSE_ERROR) || f37c2264 369) !strcmp(input.buf, "*")) c08171d1 447) if (s->skip_unseen) c08171d1 448) continue; c08171d1 460) adddel = s->mode == FROM_INDEX ? 8746e072 462) other_adddel = s->mode == FROM_INDEX ? 8746e072 463) &file_item->worktree : &file_item->index; 8746e072 467) if (stat.files[i]->is_binary) { 8746e072 468) if (!other_adddel->binary) 8746e072 469) s->binary_count++; 8746e072 472) if (stat.files[i]->is_unmerged) { 8746e072 473) if (!other_adddel->unmerged) 8746e072 474) s->unmerged_count++; 8746e072 475) adddel->unmerged = 1; c08171d1 487) static int get_modified_files(struct repository *r, c08171d1 497) struct collection_status s = { 0 }; a8c45be9 504) prefix_item_list_clear(files); a8c45be9 505) s.files = &files->items; c08171d1 508) for (i = 0; i < 2; i++) { c08171d1 512) if (filter == INDEX_ONLY) c08171d1 513) s.mode = (i == 0) ? FROM_INDEX : FROM_WORKTREE; c08171d1 515) s.mode = (i == 0) ? FROM_WORKTREE : FROM_INDEX; c08171d1 516) s.skip_unseen = filter && i; c08171d1 531) if (s.mode == FROM_INDEX) 0c3944a6 538) if (ps) 0c3944a6 539) clear_pathspec(&rev.prune_data); 8746e072 542) if (unmerged_count) 8746e072 543) *unmerged_count = s.unmerged_count; 8746e072 544) if (binary_count) 8746e072 545) *binary_count = s.binary_count; a8c45be9 548) string_list_sort(&files->items); f37c2264 588) static void print_file_item(int i, int selected, struct string_list_item *item, a8c45be9 593) const char *highlighted = NULL; a8c45be9 600) if (c->prefix_length > 0 && a8c45be9 601) is_valid_prefix(item->string, c->prefix_length)) { a8c45be9 602) strbuf_reset(&d->name); a8c45be9 603) strbuf_addf(&d->name, "%s%.*s%s%s", d->color, a8c45be9 604) (int)c->prefix_length, item->string, d->reset, a8c45be9 605) item->string + c->prefix_length); a8c45be9 606) highlighted = d->name.buf; ab1e1ccc 609) if (d->only_names) { ab1e1ccc 610) printf("%c%2d: %s", selected ? '*' : ' ', i + 1, ab1e1ccc 612) return; a8c45be9 618) strbuf_addf(&d->buf, d->modified_fmt, d->index.buf, d->worktree.buf, f37c2264 621) printf("%c%2d: %s", selected ? '*' : ' ', i + 1, d->buf.buf); 8746e072 628) if (get_modified_files(s->r, NO_FILTER, files, ps, NULL, NULL) < 0) 5e82b9e4 629) return -1; a8c45be9 631) list(s, &files->items, NULL, &opts->list_opts); 5e82b9e4 632) putchar('\n'); 5e82b9e4 634) return 0; a8c45be9 637) static int run_update(struct add_i_state *s, const struct pathspec *ps, a8c45be9 641) int res = 0, fd; 8746e072 645) if (get_modified_files(s->r, WORKTREE_ONLY, files, ps, NULL, NULL) < 0) a8c45be9 648) if (!files->items.nr) { a8c45be9 649) putchar('\n'); a8c45be9 650) return 0; a8c45be9 653) opts->prompt = N_("Update"); a8c45be9 654) count = list_and_choose(s, files, opts); a8c45be9 655) if (count <= 0) { a8c45be9 656) putchar('\n'); a8c45be9 657) return 0; a8c45be9 660) fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR); a8c45be9 661) if (fd < 0) { a8c45be9 662) putchar('\n'); a8c45be9 663) return -1; a8c45be9 666) for (i = 0; i < files->items.nr; i++) { a8c45be9 667) const char *name = files->items.items[i].string; a8c45be9 668) if (files->selected[i] && a8c45be9 669) add_file_to_index(s->r->index, name, 0) < 0) { a8c45be9 671) break; a8c45be9 675) if (!res && write_locked_index(s->r->index, &index_lock, COMMIT_LOCK) < 0) a8c45be9 678) if (!res) a8c45be9 679) printf(Q_("updated %d path\n", a8c45be9 682) putchar('\n'); a8c45be9 683) return res; c54ef5e4 686) static void revert_from_diff(struct diff_queue_struct *q, c54ef5e4 689) int i, add_flags = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE; c54ef5e4 691) for (i = 0; i < q->nr; i++) { c54ef5e4 692) struct diff_filespec *one = q->queue[i]->one; c54ef5e4 695) if (!(one->mode && !is_null_oid(&one->oid))) { c54ef5e4 696) remove_file_from_index(opt->repo->index, one->path); c54ef5e4 697) printf(_("note: %s is untracked now.\n"), one->path); c54ef5e4 699) ce = make_cache_entry(opt->repo->index, one->mode, c54ef5e4 700) &one->oid, one->path, 0, 0); c54ef5e4 701) if (!ce) c54ef5e4 704) add_index_entry(opt->repo->index, ce, add_flags); c54ef5e4 707) } c54ef5e4 709) static int run_revert(struct add_i_state *s, const struct pathspec *ps, c54ef5e4 713) int res = 0, fd; c54ef5e4 717) int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid, c54ef5e4 722) struct diff_options diffopt = { NULL }; 8746e072 724) if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0) c54ef5e4 725) return -1; c54ef5e4 727) if (!files->items.nr) { c54ef5e4 728) putchar('\n'); c54ef5e4 729) return 0; c54ef5e4 732) opts->prompt = N_("Revert"); c54ef5e4 733) count = list_and_choose(s, files, opts); c54ef5e4 734) if (count <= 0) c54ef5e4 735) goto finish_revert; c54ef5e4 737) fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR); c54ef5e4 738) if (fd < 0) { c54ef5e4 739) res = -1; c54ef5e4 740) goto finish_revert; c54ef5e4 743) if (is_initial) c54ef5e4 744) oidcpy(&oid, s->r->hash_algo->empty_tree); c54ef5e4 746) tree = parse_tree_indirect(&oid); c54ef5e4 747) if (!tree) { c54ef5e4 749) goto finish_revert; c54ef5e4 751) oidcpy(&oid, &tree->object.oid); c54ef5e4 754) ALLOC_ARRAY(paths, count + 1); c54ef5e4 755) for (i = j = 0; i < files->items.nr; i++) c54ef5e4 756) if (files->selected[i]) c54ef5e4 757) paths[j++] = files->items.items[i].string; c54ef5e4 758) paths[j] = NULL; c54ef5e4 760) parse_pathspec(&diffopt.pathspec, 0, c54ef5e4 764) diffopt.output_format = DIFF_FORMAT_CALLBACK; c54ef5e4 765) diffopt.format_callback = revert_from_diff; c54ef5e4 766) diffopt.flags.override_submodule_config = 1; c54ef5e4 767) diffopt.repo = s->r; c54ef5e4 769) if (do_diff_cache(&oid, &diffopt)) c54ef5e4 770) res = -1; c54ef5e4 772) diffcore_std(&diffopt); c54ef5e4 773) diff_flush(&diffopt); c54ef5e4 775) free(paths); c54ef5e4 776) clear_pathspec(&diffopt.pathspec); c54ef5e4 778) if (!res && write_locked_index(s->r->index, &index_lock, c54ef5e4 780) res = -1; c54ef5e4 782) res = repo_refresh_and_write_index(s->r, REFRESH_QUIET, 0, 1, c54ef5e4 785) if (!res) c54ef5e4 786) printf(Q_("reverted %d path\n", c54ef5e4 791) return res; ab1e1ccc 794) static int get_untracked_files(struct repository *r, ab1e1ccc 798) struct dir_struct dir = { 0 }; ab1e1ccc 800) struct strbuf buf = STRBUF_INIT; ab1e1ccc 802) if (repo_read_index(r) < 0) ab1e1ccc 805) prefix_item_list_clear(files); ab1e1ccc 806) setup_standard_excludes(&dir); ab1e1ccc 807) add_pattern_list(&dir, EXC_CMDL, "--exclude option"); ab1e1ccc 808) fill_directory(&dir, r->index, ps); ab1e1ccc 810) for (i = 0; i < dir.nr; i++) { ab1e1ccc 811) struct dir_entry *ent = dir.entries[i]; ab1e1ccc 813) if (index_name_is_other(r->index, ent->name, ent->len)) { ab1e1ccc 814) strbuf_reset(&buf); ab1e1ccc 815) strbuf_add(&buf, ent->name, ent->len); ab1e1ccc 816) add_file_item(&files->items, buf.buf); ab1e1ccc 820) strbuf_release(&buf); ab1e1ccc 824) static int run_add_untracked(struct add_i_state *s, const struct pathspec *ps, ab1e1ccc 828) struct print_file_item_data *d = opts->list_opts.print_item_data; ab1e1ccc 829) int res = 0, fd; ab1e1ccc 833) if (get_untracked_files(s->r, files, ps) < 0) ab1e1ccc 834) return -1; ab1e1ccc 836) if (!files->items.nr) { ab1e1ccc 837) printf(_("No untracked files.\n")); ab1e1ccc 838) goto finish_add_untracked; ab1e1ccc 841) opts->prompt = N_("Add untracked"); ab1e1ccc 842) d->only_names = 1; ab1e1ccc 843) count = list_and_choose(s, files, opts); ab1e1ccc 844) d->only_names = 0; ab1e1ccc 845) if (count <= 0) ab1e1ccc 846) goto finish_add_untracked; ab1e1ccc 848) fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR); ab1e1ccc 849) if (fd < 0) { ab1e1ccc 850) res = -1; ab1e1ccc 851) goto finish_add_untracked; ab1e1ccc 854) for (i = 0; i < files->items.nr; i++) { ab1e1ccc 855) const char *name = files->items.items[i].string; ab1e1ccc 856) if (files->selected[i] && ab1e1ccc 857) add_file_to_index(s->r->index, name, 0) < 0) { ab1e1ccc 859) break; ab1e1ccc 863) if (!res && ab1e1ccc 864) write_locked_index(s->r->index, &index_lock, COMMIT_LOCK) < 0) ab1e1ccc 867) if (!res) ab1e1ccc 868) printf(Q_("added %d path\n", ab1e1ccc 872) putchar('\n'); ab1e1ccc 873) return res; 8746e072 876) static int run_patch(struct add_i_state *s, const struct pathspec *ps, 8746e072 880) int res = 0; 8746e072 882) size_t unmerged_count = 0, binary_count = 0; 8746e072 884) if (get_modified_files(s->r, WORKTREE_ONLY, files, ps, 8746e072 886) return -1; 8746e072 888) if (unmerged_count || binary_count) { 8746e072 889) for (i = j = 0; i < files->items.nr; i++) { 8746e072 890) struct file_item *item = files->items.items[i].util; 8746e072 892) if (item->index.binary || item->worktree.binary) { 8746e072 893) free(item); 8746e072 894) free(files->items.items[i].string); 8746e072 895) } else if (item->index.unmerged || 8746e072 897) color_fprintf_ln(stderr, s->error_color, 8746e072 899) files->items.items[i].string); 8746e072 900) free(item); 8746e072 901) free(files->items.items[i].string); 8746e072 903) files->items.items[j++] = files->items.items[i]; 8746e072 905) files->items.nr = j; 8746e072 908) if (!files->items.nr) { 8746e072 909) if (binary_count) 8746e072 910) fprintf(stderr, _("Only binary files changed.\n")); 8746e072 912) fprintf(stderr, _("No changes.\n")); 8746e072 913) return 0; 8746e072 916) opts->prompt = N_("Patch update"); 8746e072 917) count = list_and_choose(s, files, opts); 8746e072 918) if (count >= 0) { 8746e072 919) struct argv_array args = ARGV_ARRAY_INIT; 8746e072 921) argv_array_pushl(&args, "git", "add--interactive", "--patch", 8746e072 923) for (i = 0; i < files->items.nr; i++) 8746e072 924) if (files->selected[i]) 8746e072 925) argv_array_push(&args, 8746e072 926) files->items.items[i].string); 8746e072 927) res = run_command_v_opt(args.argv, 0); 8746e072 928) argv_array_clear(&args); 8746e072 931) return res; d7633578 934) static int run_diff(struct add_i_state *s, const struct pathspec *ps, d7633578 938) int res = 0; d7633578 942) int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid, d7633578 944) if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0) d7633578 945) return -1; d7633578 947) if (!files->items.nr) { d7633578 948) putchar('\n'); d7633578 949) return 0; d7633578 952) opts->prompt = N_("Review diff"); d7633578 953) opts->flags = IMMEDIATE; d7633578 954) count = list_and_choose(s, files, opts); d7633578 955) opts->flags = 0; d7633578 956) if (count >= 0) { d7633578 957) struct argv_array args = ARGV_ARRAY_INIT; d7633578 959) argv_array_pushl(&args, "git", "diff", "-p", "--cached", d7633578 961) s->r->hash_algo->empty_tree), d7633578 963) for (i = 0; i < files->items.nr; i++) d7633578 964) if (files->selected[i]) d7633578 965) argv_array_push(&args, d7633578 966) files->items.items[i].string); d7633578 967) res = run_command_v_opt(args.argv, 0); d7633578 968) argv_array_clear(&args); d7633578 971) putchar('\n'); d7633578 972) return res; a8c45be9 995) static void choose_prompt_help(struct add_i_state *s) a8c45be9 997) color_fprintf_ln(stdout, s->help_color, "%s", a8c45be9 999) color_fprintf_ln(stdout, s->help_color, "1 - %s", a8c45be9 1001) color_fprintf_ln(stdout, s->help_color, "3-5 - %s", a8c45be9 1003) color_fprintf_ln(stdout, s->help_color, "2-3,6-9 - %s", a8c45be9 1005) color_fprintf_ln(stdout, s->help_color, "foo - %s", a8c45be9 1007) color_fprintf_ln(stdout, s->help_color, "-... - %s", a8c45be9 1009) color_fprintf_ln(stdout, s->help_color, "* - %s", a8c45be9 1011) color_fprintf_ln(stdout, s->help_color, " - %s", a8c45be9 1013) } f37c2264 1028) static void print_command_item(int i, int selected, a8c45be9 1083) struct list_and_choose_options opts = { a8c45be9 1088) struct prefix_item_list files = PREFIX_ITEM_LIST_INIT; a8c45be9 1109) print_file_item_data.color = data.color; a8c45be9 1110) print_file_item_data.reset = data.reset; a8c45be9 1115) opts.list_opts.header = header.buf; 2e697ced 1129) if (i < 0 || i >= commands.items.nr) 2e697ced 1130) util = NULL; 2e697ced 1132) util = commands.items.items[i].util; 2e697ced 1134) if (i == LIST_AND_CHOOSE_QUIT || (util && !util->command)) { 2e697ced 1140) if (util) a8c45be9 1144) prefix_item_list_clear(&files); a8c45be9 1146) strbuf_release(&print_file_item_data.name); apply.c b4bbbbd5 2672) match_beginning = 0; builtin/commit.c builtin/fmt-merge-msg.c 72b006f4 511) strbuf_addstr(&sig, "gpg verification failed.\n"); builtin/reset.c builtin/submodule--helper.c c1547450 1501) if (sub->update_strategy.type == SM_UPDATE_COMMAND) fast-import.c 01968302 1687) failure |= error_errno("unable to create leading directories of %s", 01968302 1689) return; fsck.c bdfef049 627) if (!S_ISLNK(mode)) bdfef049 628) oidset_insert(&gitmodules_found, oid); 7034cd09 630) retval += report(options, oid, OBJ_TREE, gpg-interface.c 72b006f4 223) return error_errno(_("could not create temporary file")); 72b006f4 226) error_errno(_("failed writing detached signature to '%s'"), 72b006f4 228) delete_tempfile(&temp); 72b006f4 229) return -1; 72b006f4 244) gpg_status = &buf; log-tree.c 72b006f4 461) show_sig_lines(opt, status, "No signature\n"); 72b006f4 535) } else if (verify_message.len <= gpg_message_offset) pathspec.c progress.c 44a4693b 308) return start_progress_delay(title, total, get_default_delay(), 1); read-cache.c 288a74bc 1001) if (is_ntfs_dotgitmodules(path)) 288a74bc 1002) return 0; sequencer.c c068bcc5 840) free(kv.items[date_i].util); cbd8db17 890) return NULL; 08187b4c 903) return NULL; 08187b4c 920) argv_array_pushf(&child->env_array, "GIT_COMMITTER_DATE=%s", date.buf); cbd8db17 989) return -1; cbd8db17 1428) goto out; cbd8db17 1432) goto out; 08187b4c 1508) res = -1; 08187b4c 1509) goto out; cbd8db17 2603) opts->allow_ff = 0; cbd8db17 2604) opts->committer_date_is_author_date = 1; 08187b4c 2608) opts->allow_ff = 0; 08187b4c 2609) opts->ignore_date = 1; 08187b4c 3639) push_dates(&cmd, opts->committer_date_is_author_date); 393adf7a 5272) goto cleanup; submodule.c t/helper/test-path-utils.c a62f9d1a 194) static uint64_t my_random(void) a62f9d1a 196) my_random_value = my_random_value * 1103515245 + 12345; a62f9d1a 197) return my_random_value; a62f9d1a 205) static double my_sqrt(double value) a62f9d1a 207) const double epsilon = 1e-6; a62f9d1a 208) double x = value; a62f9d1a 210) if (value == 0) a62f9d1a 211) return 0; a62f9d1a 214) double delta = (value / x - x) / 2; a62f9d1a 215) if (delta < epsilon && delta > -epsilon) a62f9d1a 216) return x + delta; a62f9d1a 217) x += delta; a62f9d1a 218) } a62f9d1a 221) static int protect_ntfs_hfs_benchmark(int argc, const char **argv) a62f9d1a 223) size_t i, j, nr, min_len = 3, max_len = 20; a62f9d1a 225) int repetitions = 15, file_mode = 0100644; a62f9d1a 231) if (argc > 1 && !strcmp(argv[1], "--with-symlink-mode")) { a62f9d1a 232) file_mode = 0120000; a62f9d1a 233) argc--; a62f9d1a 234) argv++; a62f9d1a 237) nr = argc > 1 ? strtoul(argv[1], NULL, 0) : 1000000; a62f9d1a 238) ALLOC_ARRAY(names, nr); a62f9d1a 240) if (argc > 2) { a62f9d1a 241) min_len = strtoul(argv[2], NULL, 0); a62f9d1a 242) if (argc > 3) a62f9d1a 243) max_len = strtoul(argv[3], NULL, 0); a62f9d1a 244) if (min_len > max_len) a62f9d1a 248) for (i = 0; i < nr; i++) { a62f9d1a 249) size_t len = min_len + (my_random() % (max_len + 1 - min_len)); a62f9d1a 251) names[i] = xmallocz(len); a62f9d1a 252) while (len > 0) a62f9d1a 253) names[i][--len] = (char)(' ' + (my_random() % ('\x7f' - ' '))); a62f9d1a 256) for (protect_ntfs = 0; protect_ntfs < 2; protect_ntfs++) a62f9d1a 257) for (protect_hfs = 0; protect_hfs < 2; protect_hfs++) { a62f9d1a 258) cumul = 0; a62f9d1a 259) cumul2 = 0; a62f9d1a 260) for (i = 0; i < repetitions; i++) { a62f9d1a 261) begin = getnanotime(); a62f9d1a 262) for (j = 0; j < nr; j++) a62f9d1a 263) verify_path(names[j], file_mode); a62f9d1a 264) end = getnanotime(); a62f9d1a 265) printf("protect_ntfs = %d, protect_hfs = %d: %lfms\n", protect_ntfs, protect_hfs, (end-begin) / (double)1e6); a62f9d1a 266) cumul += end - begin; a62f9d1a 267) cumul2 += (end - begin) * (end - begin); a62f9d1a 269) m[protect_ntfs][protect_hfs] = cumul / (double)repetitions; a62f9d1a 270) v[protect_ntfs][protect_hfs] = my_sqrt(cumul2 / (double)repetitions - m[protect_ntfs][protect_hfs] * m[protect_ntfs][protect_hfs]); a62f9d1a 271) printf("mean: %lfms, stddev: %lfms\n", m[protect_ntfs][protect_hfs] / (double)1e6, v[protect_ntfs][protect_hfs] / (double)1e6); a62f9d1a 274) for (protect_ntfs = 0; protect_ntfs < 2; protect_ntfs++) a62f9d1a 275) for (protect_hfs = 0; protect_hfs < 2; protect_hfs++) a62f9d1a 276) printf("ntfs=%d/hfs=%d: %lf%% slower\n", protect_ntfs, protect_hfs, (m[protect_ntfs][protect_hfs] - m[0][0]) * 100 / m[0][0]); a62f9d1a 278) return 0; a62f9d1a 451) if (argc > 1 && !strcmp(argv[1], "protect_ntfs_hfs")) a62f9d1a 452) return !!protect_ntfs_hfs_benchmark(argc - 1, argv + 1); d2c84dad 454) if (argc > 1 && !strcmp(argv[1], "is_valid_path")) { d2c84dad 455) int res = 0, expect = 1, i; d2c84dad 457) for (i = 2; i < argc; i++) d2c84dad 458) if (!strcmp("--not", argv[i])) d2c84dad 459) expect = 0; d2c84dad 460) else if (expect != is_valid_path(argv[i])) d2c84dad 464) fprintf(stderr, d2c84dad 466) argv[i], expect ? "" : " not"); d2c84dad 468) return !!res; t/helper/test-run-command.c ad155925 205) static uint64_t my_random(void) ad155925 207) uint64_t res = my_random_next; ad155925 208) my_random_next = my_random_next * 1103515245 + 12345; ad155925 209) return res; ad155925 212) static int quote_stress_test(int argc, const char **argv) ad155925 220) char special[] = ".?*\\^_\"'`{}()[]<>@~&+:;$%"; // \t\r\n\a"; 379e51d1 221) int i, j, k, trials = 100, skip = 0, msys2 = 0; ad155925 222) struct strbuf out = STRBUF_INIT; ad155925 223) struct argv_array args = ARGV_ARRAY_INIT; ad155925 224) struct option options[] = { ad155925 230) const char * const usage[] = { ad155925 235) argc = parse_options(argc, argv, NULL, options, usage, 0); 379e51d1 237) setenv("MSYS_NO_PATHCONV", "1", 0); ad155925 239) for (i = 0; i < trials; i++) { ad155925 240) struct child_process cp = CHILD_PROCESS_INIT; ad155925 242) int ret = 0; ad155925 244) argv_array_clear(&args); 379e51d1 245) if (msys2) 379e51d1 246) argv_array_pushl(&args, "sh", "-c", 14af7ed5 249) argv_array_pushl(&args, "test-tool", "run-command", ad155925 251) arg_offset = args.argc; 55953c77 253) if (argc > 0) { 55953c77 254) trials = 1; 55953c77 255) arg_count = argc; 55953c77 256) for (j = 0; j < arg_count; j++) 55953c77 257) argv_array_push(&args, argv[j]); 55953c77 259) arg_count = 1 + (my_random() % 5); 55953c77 260) for (j = 0; j < arg_count; j++) { 55953c77 262) size_t min_len = 1; 55953c77 263) size_t arg_len = min_len + 55953c77 264) (my_random() % (ARRAY_SIZE(buf) - min_len)); 55953c77 266) for (k = 0; k < arg_len; k++) 55953c77 267) buf[k] = special[my_random() % 55953c77 269) buf[arg_len] = '\0'; 55953c77 271) argv_array_push(&args, buf); 7530a628 275) if (i < skip) 7530a628 276) continue; ad155925 278) cp.argv = args.argv; ad155925 279) strbuf_reset(&out); ad155925 280) if (pipe_command(&cp, NULL, 0, &out, 0, NULL, 0) < 0) ad155925 283) for (j = 0, k = 0; j < arg_count; j++) { ad155925 284) const char *arg = args.argv[j + arg_offset]; ad155925 286) if (strcmp(arg, out.buf + k)) ad155925 290) k += strlen(out.buf + k) + 1; ad155925 293) if (k != out.len) ad155925 297) if (ret) { ad155925 298) fprintf(stderr, "Trial #%d failed. Arguments:\n", i); ad155925 299) for (j = 0; j < arg_count; j++) ad155925 300) fprintf(stderr, "arg #%d: '%s'\n", ad155925 301) (int)j, args.argv[j + arg_offset]); ad155925 303) strbuf_release(&out); ad155925 304) argv_array_clear(&args); ad155925 306) return ret; ad155925 309) if (i && (i % 100) == 0) ad155925 310) fprintf(stderr, "Trials completed: %d\n", (int)i); ad155925 313) strbuf_release(&out); ad155925 314) argv_array_clear(&args); ad155925 316) return 0; ad155925 319) static int quote_echo(int argc, const char **argv) ad155925 321) while (argc > 1) { ad155925 322) fwrite(argv[1], strlen(argv[1]), 1, stdout); ad155925 323) fputc('\0', stdout); ad155925 324) argv++; ad155925 325) argc--; ad155925 328) return 0; eea4a7f4 331) static int inherit_handle(const char *argv0) eea4a7f4 333) struct child_process cp = CHILD_PROCESS_INIT; eea4a7f4 338) xsnprintf(path, sizeof(path), "out-XXXXXX"); eea4a7f4 339) tmp = xmkstemp(path); eea4a7f4 341) argv_array_pushl(&cp.args, eea4a7f4 343) cp.in = -1; eea4a7f4 344) cp.no_stdout = cp.no_stderr = 1; eea4a7f4 345) if (start_command(&cp) < 0) eea4a7f4 349) close(tmp); eea4a7f4 350) if (unlink(path)) eea4a7f4 353) if (close(cp.in) < 0 || finish_command(&cp) < 0) eea4a7f4 356) return 0; eea4a7f4 359) static int inherit_handle_child(void) eea4a7f4 361) struct strbuf buf = STRBUF_INIT; eea4a7f4 363) if (strbuf_read(&buf, 0, 0) < 0) eea4a7f4 365) printf("Received %s\n", buf.buf); eea4a7f4 366) strbuf_release(&buf); eea4a7f4 368) return 0; eea4a7f4 379) exit(inherit_handle(argv[0])); eea4a7f4 381) exit(inherit_handle_child()); ad155925 384) return !!quote_stress_test(argc - 1, argv + 1); ad155925 387) return !!quote_echo(argc - 1, argv + 1); unpack-trees.c cc756edd 2067) return -1; xdiff/xemit.c 0bb313a5 223) xchp->i1 + xchp->chg1 <= s1 && 0bb313a5 224) xchp->i2 + xchp->chg2 <= s2) 0bb313a5 225) xchp = xchp->next; Commits introducing uncovered code: Alban Gruin 393adf7a sequencer: directly call pick_commits() from complete_action() Alexandr Miloslavskiy 24e4750c pathspec: add new function to parse file Alexandr Miloslavskiy 64bac8df reset: support the `--pathspec-from-file` option Daniel Ferreira 5e82b9e4 built-in add -i: implement the `status` command Derrick Stolee 44a4693b progress: create GIT_PROGRESS_DELAY Garima Singh a62f9d1a test-path-utils: offer to run a protectNTFS/protectHFS benchmark Garima Singh ad155925 tests: add a helper to stress test argument quoting Hans Jerry Illikainen 72b006f4 gpg-interface: prefer check_signature() for GPG verification Jeff King 01968302 fast-import: delay creating leading directories for export-marks Johannes Schindelin 55953c77 quote-stress-test: accept arguments to test via the command-line Johannes Schindelin 14af7ed5 Sync with 2.17.3 Johannes Schindelin 379e51d1 quote-stress-test: offer to test quoting arguments for MSYS2 sh Johannes Schindelin d2c84dad mingw: refuse to access paths with trailing spaces or periods Johannes Schindelin eea4a7f4 mingw: demonstrate that all file handles are inherited by child processes Johannes Schindelin cc756edd unpack-trees: let merged_entry() pass through do_add_entry()'s errors Johannes Schindelin 288a74bc is_ntfs_dotgit(): only verify the leading segment Johannes Schindelin 7530a628 quote-stress-test: allow skipping some trials Johannes Schindelin f37c2264 built-in add -i: prepare for multi-selection commands Johannes Schindelin bdfef049 Sync with 2.16.6 Johannes Schindelin c08171d1 built-in add -i: allow filtering the modified files list Johannes Schindelin 8746e072 built-in add -i: implement the `patch` command Johannes Schindelin a8c45be9 built-in add -i: implement the `update` command Johannes Schindelin 0c3944a6 add-interactive: make sure to release `rev.prune_data` Johannes Schindelin ab1e1ccc built-in add -i: re-implement `add-untracked` in C Johannes Schindelin c54ef5e4 built-in add -i: re-implement `revert` in C Johannes Schindelin d7633578 built-in add -i: re-implement the `diff` command Johannes Schindelin b4bbbbd5 apply --allow-overlap: fix a corner case Johannes Schindelin 0060fd15 clone --recurse-submodules: prevent name squatting on Windows Johannes Schindelin 2e697ced built-in add -i: offer the `quit` command Jonathan Nieder c1547450 submodule: defend against submodule.update = !command in .gitmodules Junio C Hamano 7034cd09 Sync with Git 2.24.1 René Scharfe 0bb313a5 xdiff: unignore changes in function context Rohit Ashiwal 08187b4c rebase -i: support --ignore-date Rohit Ashiwal cbd8db17 rebase -i: support --committer-date-is-author-date Rohit Ashiwal c068bcc5 sequencer: allow callers of read_author_script() to ignore fields