1/* 2 * Builtin "git am" 3 * 4 * Based on git-am.sh by Junio C Hamano. 5 */ 6#include"cache.h" 7#include"config.h" 8#include"builtin.h" 9#include"exec-cmd.h" 10#include"parse-options.h" 11#include"dir.h" 12#include"run-command.h" 13#include"quote.h" 14#include"tempfile.h" 15#include"lockfile.h" 16#include"cache-tree.h" 17#include"refs.h" 18#include"commit.h" 19#include"diff.h" 20#include"diffcore.h" 21#include"unpack-trees.h" 22#include"branch.h" 23#include"sequencer.h" 24#include"revision.h" 25#include"merge-recursive.h" 26#include"revision.h" 27#include"log-tree.h" 28#include"notes-utils.h" 29#include"rerere.h" 30#include"prompt.h" 31#include"mailinfo.h" 32#include"apply.h" 33#include"string-list.h" 34#include"packfile.h" 35#include"repository.h" 36 37/** 38 * Returns 1 if the file is empty or does not exist, 0 otherwise. 39 */ 40static intis_empty_file(const char*filename) 41{ 42struct stat st; 43 44if(stat(filename, &st) <0) { 45if(errno == ENOENT) 46return1; 47die_errno(_("could not stat%s"), filename); 48} 49 50return!st.st_size; 51} 52 53/** 54 * Returns the length of the first line of msg. 55 */ 56static intlinelen(const char*msg) 57{ 58returnstrchrnul(msg,'\n') - msg; 59} 60 61/** 62 * Returns true if `str` consists of only whitespace, false otherwise. 63 */ 64static intstr_isspace(const char*str) 65{ 66for(; *str; str++) 67if(!isspace(*str)) 68return0; 69 70return1; 71} 72 73enum patch_format { 74 PATCH_FORMAT_UNKNOWN =0, 75 PATCH_FORMAT_MBOX, 76 PATCH_FORMAT_STGIT, 77 PATCH_FORMAT_STGIT_SERIES, 78 PATCH_FORMAT_HG, 79 PATCH_FORMAT_MBOXRD 80}; 81 82enum keep_type { 83 KEEP_FALSE =0, 84 KEEP_TRUE,/* pass -k flag to git-mailinfo */ 85 KEEP_NON_PATCH /* pass -b flag to git-mailinfo */ 86}; 87 88enum scissors_type { 89 SCISSORS_UNSET = -1, 90 SCISSORS_FALSE =0,/* pass --no-scissors to git-mailinfo */ 91 SCISSORS_TRUE /* pass --scissors to git-mailinfo */ 92}; 93 94enum signoff_type { 95 SIGNOFF_FALSE =0, 96 SIGNOFF_TRUE =1, 97 SIGNOFF_EXPLICIT /* --signoff was set on the command-line */ 98}; 99 100struct am_state { 101/* state directory path */ 102char*dir; 103 104/* current and last patch numbers, 1-indexed */ 105int cur; 106int last; 107 108/* commit metadata and message */ 109char*author_name; 110char*author_email; 111char*author_date; 112char*msg; 113size_t msg_len; 114 115/* when --rebasing, records the original commit the patch came from */ 116struct object_id orig_commit; 117 118/* number of digits in patch filename */ 119int prec; 120 121/* various operating modes and command line options */ 122int interactive; 123int threeway; 124int quiet; 125int signoff;/* enum signoff_type */ 126int utf8; 127int keep;/* enum keep_type */ 128int message_id; 129int scissors;/* enum scissors_type */ 130struct argv_array git_apply_opts; 131const char*resolvemsg; 132int committer_date_is_author_date; 133int ignore_date; 134int allow_rerere_autoupdate; 135const char*sign_commit; 136int rebasing; 137}; 138 139/** 140 * Initializes am_state with the default values. 141 */ 142static voidam_state_init(struct am_state *state) 143{ 144int gpgsign; 145 146memset(state,0,sizeof(*state)); 147 148 state->dir =git_pathdup("rebase-apply"); 149 150 state->prec =4; 151 152git_config_get_bool("am.threeway", &state->threeway); 153 154 state->utf8 =1; 155 156git_config_get_bool("am.messageid", &state->message_id); 157 158 state->scissors = SCISSORS_UNSET; 159 160argv_array_init(&state->git_apply_opts); 161 162if(!git_config_get_bool("commit.gpgsign", &gpgsign)) 163 state->sign_commit = gpgsign ?"": NULL; 164} 165 166/** 167 * Releases memory allocated by an am_state. 168 */ 169static voidam_state_release(struct am_state *state) 170{ 171free(state->dir); 172free(state->author_name); 173free(state->author_email); 174free(state->author_date); 175free(state->msg); 176argv_array_clear(&state->git_apply_opts); 177} 178 179/** 180 * Returns path relative to the am_state directory. 181 */ 182staticinlineconst char*am_path(const struct am_state *state,const char*path) 183{ 184returnmkpath("%s/%s", state->dir, path); 185} 186 187/** 188 * For convenience to call write_file() 189 */ 190static voidwrite_state_text(const struct am_state *state, 191const char*name,const char*string) 192{ 193write_file(am_path(state, name),"%s", string); 194} 195 196static voidwrite_state_count(const struct am_state *state, 197const char*name,int value) 198{ 199write_file(am_path(state, name),"%d", value); 200} 201 202static voidwrite_state_bool(const struct am_state *state, 203const char*name,int value) 204{ 205write_state_text(state, name, value ?"t":"f"); 206} 207 208/** 209 * If state->quiet is false, calls fprintf(fp, fmt, ...), and appends a newline 210 * at the end. 211 */ 212static voidsay(const struct am_state *state,FILE*fp,const char*fmt, ...) 213{ 214va_list ap; 215 216va_start(ap, fmt); 217if(!state->quiet) { 218vfprintf(fp, fmt, ap); 219putc('\n', fp); 220} 221va_end(ap); 222} 223 224/** 225 * Returns 1 if there is an am session in progress, 0 otherwise. 226 */ 227static intam_in_progress(const struct am_state *state) 228{ 229struct stat st; 230 231if(lstat(state->dir, &st) <0|| !S_ISDIR(st.st_mode)) 232return0; 233if(lstat(am_path(state,"last"), &st) || !S_ISREG(st.st_mode)) 234return0; 235if(lstat(am_path(state,"next"), &st) || !S_ISREG(st.st_mode)) 236return0; 237return1; 238} 239 240/** 241 * Reads the contents of `file` in the `state` directory into `sb`. Returns the 242 * number of bytes read on success, -1 if the file does not exist. If `trim` is 243 * set, trailing whitespace will be removed. 244 */ 245static intread_state_file(struct strbuf *sb,const struct am_state *state, 246const char*file,int trim) 247{ 248strbuf_reset(sb); 249 250if(strbuf_read_file(sb,am_path(state, file),0) >=0) { 251if(trim) 252strbuf_trim(sb); 253 254return sb->len; 255} 256 257if(errno == ENOENT) 258return-1; 259 260die_errno(_("could not read '%s'"),am_path(state, file)); 261} 262 263/** 264 * Take a series of KEY='VALUE' lines where VALUE part is 265 * sq-quoted, and append <KEY, VALUE> at the end of the string list 266 */ 267static intparse_key_value_squoted(char*buf,struct string_list *list) 268{ 269while(*buf) { 270struct string_list_item *item; 271char*np; 272char*cp =strchr(buf,'='); 273if(!cp) 274return-1; 275 np =strchrnul(cp,'\n'); 276*cp++ ='\0'; 277 item =string_list_append(list, buf); 278 279 buf = np + (*np =='\n'); 280*np ='\0'; 281 cp =sq_dequote(cp); 282if(!cp) 283return-1; 284 item->util =xstrdup(cp); 285} 286return0; 287} 288 289/** 290 * Reads and parses the state directory's "author-script" file, and sets 291 * state->author_name, state->author_email and state->author_date accordingly. 292 * Returns 0 on success, -1 if the file could not be parsed. 293 * 294 * The author script is of the format: 295 * 296 * GIT_AUTHOR_NAME='$author_name' 297 * GIT_AUTHOR_EMAIL='$author_email' 298 * GIT_AUTHOR_DATE='$author_date' 299 * 300 * where $author_name, $author_email and $author_date are quoted. We are strict 301 * with our parsing, as the file was meant to be eval'd in the old git-am.sh 302 * script, and thus if the file differs from what this function expects, it is 303 * better to bail out than to do something that the user does not expect. 304 */ 305static intread_author_script(struct am_state *state) 306{ 307const char*filename =am_path(state,"author-script"); 308struct strbuf buf = STRBUF_INIT; 309struct string_list kv = STRING_LIST_INIT_DUP; 310int retval = -1;/* assume failure */ 311int fd; 312 313assert(!state->author_name); 314assert(!state->author_email); 315assert(!state->author_date); 316 317 fd =open(filename, O_RDONLY); 318if(fd <0) { 319if(errno == ENOENT) 320return0; 321die_errno(_("could not open '%s' for reading"), filename); 322} 323strbuf_read(&buf, fd,0); 324close(fd); 325if(parse_key_value_squoted(buf.buf, &kv)) 326goto finish; 327 328if(kv.nr !=3|| 329strcmp(kv.items[0].string,"GIT_AUTHOR_NAME") || 330strcmp(kv.items[1].string,"GIT_AUTHOR_EMAIL") || 331strcmp(kv.items[2].string,"GIT_AUTHOR_DATE")) 332goto finish; 333 state->author_name = kv.items[0].util; 334 state->author_email = kv.items[1].util; 335 state->author_date = kv.items[2].util; 336 retval =0; 337finish: 338string_list_clear(&kv, !!retval); 339strbuf_release(&buf); 340return retval; 341} 342 343/** 344 * Saves state->author_name, state->author_email and state->author_date in the 345 * state directory's "author-script" file. 346 */ 347static voidwrite_author_script(const struct am_state *state) 348{ 349struct strbuf sb = STRBUF_INIT; 350 351strbuf_addstr(&sb,"GIT_AUTHOR_NAME="); 352sq_quote_buf(&sb, state->author_name); 353strbuf_addch(&sb,'\n'); 354 355strbuf_addstr(&sb,"GIT_AUTHOR_EMAIL="); 356sq_quote_buf(&sb, state->author_email); 357strbuf_addch(&sb,'\n'); 358 359strbuf_addstr(&sb,"GIT_AUTHOR_DATE="); 360sq_quote_buf(&sb, state->author_date); 361strbuf_addch(&sb,'\n'); 362 363write_state_text(state,"author-script", sb.buf); 364 365strbuf_release(&sb); 366} 367 368/** 369 * Reads the commit message from the state directory's "final-commit" file, 370 * setting state->msg to its contents and state->msg_len to the length of its 371 * contents in bytes. 372 * 373 * Returns 0 on success, -1 if the file does not exist. 374 */ 375static intread_commit_msg(struct am_state *state) 376{ 377struct strbuf sb = STRBUF_INIT; 378 379assert(!state->msg); 380 381if(read_state_file(&sb, state,"final-commit",0) <0) { 382strbuf_release(&sb); 383return-1; 384} 385 386 state->msg =strbuf_detach(&sb, &state->msg_len); 387return0; 388} 389 390/** 391 * Saves state->msg in the state directory's "final-commit" file. 392 */ 393static voidwrite_commit_msg(const struct am_state *state) 394{ 395const char*filename =am_path(state,"final-commit"); 396write_file_buf(filename, state->msg, state->msg_len); 397} 398 399/** 400 * Loads state from disk. 401 */ 402static voidam_load(struct am_state *state) 403{ 404struct strbuf sb = STRBUF_INIT; 405 406if(read_state_file(&sb, state,"next",1) <0) 407BUG("state file 'next' does not exist"); 408 state->cur =strtol(sb.buf, NULL,10); 409 410if(read_state_file(&sb, state,"last",1) <0) 411BUG("state file 'last' does not exist"); 412 state->last =strtol(sb.buf, NULL,10); 413 414if(read_author_script(state) <0) 415die(_("could not parse author script")); 416 417read_commit_msg(state); 418 419if(read_state_file(&sb, state,"original-commit",1) <0) 420oidclr(&state->orig_commit); 421else if(get_oid_hex(sb.buf, &state->orig_commit) <0) 422die(_("could not parse%s"),am_path(state,"original-commit")); 423 424read_state_file(&sb, state,"threeway",1); 425 state->threeway = !strcmp(sb.buf,"t"); 426 427read_state_file(&sb, state,"quiet",1); 428 state->quiet = !strcmp(sb.buf,"t"); 429 430read_state_file(&sb, state,"sign",1); 431 state->signoff = !strcmp(sb.buf,"t"); 432 433read_state_file(&sb, state,"utf8",1); 434 state->utf8 = !strcmp(sb.buf,"t"); 435 436if(file_exists(am_path(state,"rerere-autoupdate"))) { 437read_state_file(&sb, state,"rerere-autoupdate",1); 438 state->allow_rerere_autoupdate =strcmp(sb.buf,"t") ? 439 RERERE_NOAUTOUPDATE : RERERE_AUTOUPDATE; 440}else{ 441 state->allow_rerere_autoupdate =0; 442} 443 444read_state_file(&sb, state,"keep",1); 445if(!strcmp(sb.buf,"t")) 446 state->keep = KEEP_TRUE; 447else if(!strcmp(sb.buf,"b")) 448 state->keep = KEEP_NON_PATCH; 449else 450 state->keep = KEEP_FALSE; 451 452read_state_file(&sb, state,"messageid",1); 453 state->message_id = !strcmp(sb.buf,"t"); 454 455read_state_file(&sb, state,"scissors",1); 456if(!strcmp(sb.buf,"t")) 457 state->scissors = SCISSORS_TRUE; 458else if(!strcmp(sb.buf,"f")) 459 state->scissors = SCISSORS_FALSE; 460else 461 state->scissors = SCISSORS_UNSET; 462 463read_state_file(&sb, state,"apply-opt",1); 464argv_array_clear(&state->git_apply_opts); 465if(sq_dequote_to_argv_array(sb.buf, &state->git_apply_opts) <0) 466die(_("could not parse%s"),am_path(state,"apply-opt")); 467 468 state->rebasing = !!file_exists(am_path(state,"rebasing")); 469 470strbuf_release(&sb); 471} 472 473/** 474 * Removes the am_state directory, forcefully terminating the current am 475 * session. 476 */ 477static voidam_destroy(const struct am_state *state) 478{ 479struct strbuf sb = STRBUF_INIT; 480 481strbuf_addstr(&sb, state->dir); 482remove_dir_recursively(&sb,0); 483strbuf_release(&sb); 484} 485 486/** 487 * Runs applypatch-msg hook. Returns its exit code. 488 */ 489static intrun_applypatch_msg_hook(struct am_state *state) 490{ 491int ret; 492 493assert(state->msg); 494 ret =run_hook_le(NULL,"applypatch-msg",am_path(state,"final-commit"), NULL); 495 496if(!ret) { 497FREE_AND_NULL(state->msg); 498if(read_commit_msg(state) <0) 499die(_("'%s' was deleted by the applypatch-msg hook"), 500am_path(state,"final-commit")); 501} 502 503return ret; 504} 505 506/** 507 * Runs post-rewrite hook. Returns it exit code. 508 */ 509static intrun_post_rewrite_hook(const struct am_state *state) 510{ 511struct child_process cp = CHILD_PROCESS_INIT; 512const char*hook =find_hook("post-rewrite"); 513int ret; 514 515if(!hook) 516return0; 517 518argv_array_push(&cp.args, hook); 519argv_array_push(&cp.args,"rebase"); 520 521 cp.in =xopen(am_path(state,"rewritten"), O_RDONLY); 522 cp.stdout_to_stderr =1; 523 524 ret =run_command(&cp); 525 526close(cp.in); 527return ret; 528} 529 530/** 531 * Reads the state directory's "rewritten" file, and copies notes from the old 532 * commits listed in the file to their rewritten commits. 533 * 534 * Returns 0 on success, -1 on failure. 535 */ 536static intcopy_notes_for_rebase(const struct am_state *state) 537{ 538struct notes_rewrite_cfg *c; 539struct strbuf sb = STRBUF_INIT; 540const char*invalid_line =_("Malformed input line: '%s'."); 541const char*msg ="Notes added by 'git rebase'"; 542FILE*fp; 543int ret =0; 544 545assert(state->rebasing); 546 547 c =init_copy_notes_for_rewrite("rebase"); 548if(!c) 549return0; 550 551 fp =xfopen(am_path(state,"rewritten"),"r"); 552 553while(!strbuf_getline_lf(&sb, fp)) { 554struct object_id from_obj, to_obj; 555 556if(sb.len != GIT_SHA1_HEXSZ *2+1) { 557 ret =error(invalid_line, sb.buf); 558goto finish; 559} 560 561if(get_oid_hex(sb.buf, &from_obj)) { 562 ret =error(invalid_line, sb.buf); 563goto finish; 564} 565 566if(sb.buf[GIT_SHA1_HEXSZ] !=' ') { 567 ret =error(invalid_line, sb.buf); 568goto finish; 569} 570 571if(get_oid_hex(sb.buf + GIT_SHA1_HEXSZ +1, &to_obj)) { 572 ret =error(invalid_line, sb.buf); 573goto finish; 574} 575 576if(copy_note_for_rewrite(c, &from_obj, &to_obj)) 577 ret =error(_("Failed to copy notes from '%s' to '%s'"), 578oid_to_hex(&from_obj),oid_to_hex(&to_obj)); 579} 580 581finish: 582finish_copy_notes_for_rewrite(c, msg); 583fclose(fp); 584strbuf_release(&sb); 585return ret; 586} 587 588/** 589 * Determines if the file looks like a piece of RFC2822 mail by grabbing all 590 * non-indented lines and checking if they look like they begin with valid 591 * header field names. 592 * 593 * Returns 1 if the file looks like a piece of mail, 0 otherwise. 594 */ 595static intis_mail(FILE*fp) 596{ 597const char*header_regex ="^[!-9;-~]+:"; 598struct strbuf sb = STRBUF_INIT; 599 regex_t regex; 600int ret =1; 601 602if(fseek(fp,0L, SEEK_SET)) 603die_errno(_("fseek failed")); 604 605if(regcomp(®ex, header_regex, REG_NOSUB | REG_EXTENDED)) 606die("invalid pattern:%s", header_regex); 607 608while(!strbuf_getline(&sb, fp)) { 609if(!sb.len) 610break;/* End of header */ 611 612/* Ignore indented folded lines */ 613if(*sb.buf =='\t'|| *sb.buf ==' ') 614continue; 615 616/* It's a header if it matches header_regex */ 617if(regexec(®ex, sb.buf,0, NULL,0)) { 618 ret =0; 619goto done; 620} 621} 622 623done: 624regfree(®ex); 625strbuf_release(&sb); 626return ret; 627} 628 629/** 630 * Attempts to detect the patch_format of the patches contained in `paths`, 631 * returning the PATCH_FORMAT_* enum value. Returns PATCH_FORMAT_UNKNOWN if 632 * detection fails. 633 */ 634static intdetect_patch_format(const char**paths) 635{ 636enum patch_format ret = PATCH_FORMAT_UNKNOWN; 637struct strbuf l1 = STRBUF_INIT; 638struct strbuf l2 = STRBUF_INIT; 639struct strbuf l3 = STRBUF_INIT; 640FILE*fp; 641 642/* 643 * We default to mbox format if input is from stdin and for directories 644 */ 645if(!*paths || !strcmp(*paths,"-") ||is_directory(*paths)) 646return PATCH_FORMAT_MBOX; 647 648/* 649 * Otherwise, check the first few lines of the first patch, starting 650 * from the first non-blank line, to try to detect its format. 651 */ 652 653 fp =xfopen(*paths,"r"); 654 655while(!strbuf_getline(&l1, fp)) { 656if(l1.len) 657break; 658} 659 660if(starts_with(l1.buf,"From ") ||starts_with(l1.buf,"From: ")) { 661 ret = PATCH_FORMAT_MBOX; 662goto done; 663} 664 665if(starts_with(l1.buf,"# This series applies on GIT commit")) { 666 ret = PATCH_FORMAT_STGIT_SERIES; 667goto done; 668} 669 670if(!strcmp(l1.buf,"# HG changeset patch")) { 671 ret = PATCH_FORMAT_HG; 672goto done; 673} 674 675strbuf_getline(&l2, fp); 676strbuf_getline(&l3, fp); 677 678/* 679 * If the second line is empty and the third is a From, Author or Date 680 * entry, this is likely an StGit patch. 681 */ 682if(l1.len && !l2.len && 683(starts_with(l3.buf,"From:") || 684starts_with(l3.buf,"Author:") || 685starts_with(l3.buf,"Date:"))) { 686 ret = PATCH_FORMAT_STGIT; 687goto done; 688} 689 690if(l1.len &&is_mail(fp)) { 691 ret = PATCH_FORMAT_MBOX; 692goto done; 693} 694 695done: 696fclose(fp); 697strbuf_release(&l1); 698strbuf_release(&l2); 699strbuf_release(&l3); 700return ret; 701} 702 703/** 704 * Splits out individual email patches from `paths`, where each path is either 705 * a mbox file or a Maildir. Returns 0 on success, -1 on failure. 706 */ 707static intsplit_mail_mbox(struct am_state *state,const char**paths, 708int keep_cr,int mboxrd) 709{ 710struct child_process cp = CHILD_PROCESS_INIT; 711struct strbuf last = STRBUF_INIT; 712int ret; 713 714 cp.git_cmd =1; 715argv_array_push(&cp.args,"mailsplit"); 716argv_array_pushf(&cp.args,"-d%d", state->prec); 717argv_array_pushf(&cp.args,"-o%s", state->dir); 718argv_array_push(&cp.args,"-b"); 719if(keep_cr) 720argv_array_push(&cp.args,"--keep-cr"); 721if(mboxrd) 722argv_array_push(&cp.args,"--mboxrd"); 723argv_array_push(&cp.args,"--"); 724argv_array_pushv(&cp.args, paths); 725 726 ret =capture_command(&cp, &last,8); 727if(ret) 728goto exit; 729 730 state->cur =1; 731 state->last =strtol(last.buf, NULL,10); 732 733exit: 734strbuf_release(&last); 735return ret ? -1:0; 736} 737 738/** 739 * Callback signature for split_mail_conv(). The foreign patch should be 740 * read from `in`, and the converted patch (in RFC2822 mail format) should be 741 * written to `out`. Return 0 on success, or -1 on failure. 742 */ 743typedefint(*mail_conv_fn)(FILE*out,FILE*in,int keep_cr); 744 745/** 746 * Calls `fn` for each file in `paths` to convert the foreign patch to the 747 * RFC2822 mail format suitable for parsing with git-mailinfo. 748 * 749 * Returns 0 on success, -1 on failure. 750 */ 751static intsplit_mail_conv(mail_conv_fn fn,struct am_state *state, 752const char**paths,int keep_cr) 753{ 754static const char*stdin_only[] = {"-", NULL}; 755int i; 756 757if(!*paths) 758 paths = stdin_only; 759 760for(i =0; *paths; paths++, i++) { 761FILE*in, *out; 762const char*mail; 763int ret; 764 765if(!strcmp(*paths,"-")) 766 in = stdin; 767else 768 in =fopen(*paths,"r"); 769 770if(!in) 771returnerror_errno(_("could not open '%s' for reading"), 772*paths); 773 774 mail =mkpath("%s/%0*d", state->dir, state->prec, i +1); 775 776 out =fopen(mail,"w"); 777if(!out) { 778if(in != stdin) 779fclose(in); 780returnerror_errno(_("could not open '%s' for writing"), 781 mail); 782} 783 784 ret =fn(out, in, keep_cr); 785 786fclose(out); 787if(in != stdin) 788fclose(in); 789 790if(ret) 791returnerror(_("could not parse patch '%s'"), *paths); 792} 793 794 state->cur =1; 795 state->last = i; 796return0; 797} 798 799/** 800 * A split_mail_conv() callback that converts an StGit patch to an RFC2822 801 * message suitable for parsing with git-mailinfo. 802 */ 803static intstgit_patch_to_mail(FILE*out,FILE*in,int keep_cr) 804{ 805struct strbuf sb = STRBUF_INIT; 806int subject_printed =0; 807 808while(!strbuf_getline_lf(&sb, in)) { 809const char*str; 810 811if(str_isspace(sb.buf)) 812continue; 813else if(skip_prefix(sb.buf,"Author:", &str)) 814fprintf(out,"From:%s\n", str); 815else if(starts_with(sb.buf,"From") ||starts_with(sb.buf,"Date")) 816fprintf(out,"%s\n", sb.buf); 817else if(!subject_printed) { 818fprintf(out,"Subject:%s\n", sb.buf); 819 subject_printed =1; 820}else{ 821fprintf(out,"\n%s\n", sb.buf); 822break; 823} 824} 825 826strbuf_reset(&sb); 827while(strbuf_fread(&sb,8192, in) >0) { 828fwrite(sb.buf,1, sb.len, out); 829strbuf_reset(&sb); 830} 831 832strbuf_release(&sb); 833return0; 834} 835 836/** 837 * This function only supports a single StGit series file in `paths`. 838 * 839 * Given an StGit series file, converts the StGit patches in the series into 840 * RFC2822 messages suitable for parsing with git-mailinfo, and queues them in 841 * the state directory. 842 * 843 * Returns 0 on success, -1 on failure. 844 */ 845static intsplit_mail_stgit_series(struct am_state *state,const char**paths, 846int keep_cr) 847{ 848const char*series_dir; 849char*series_dir_buf; 850FILE*fp; 851struct argv_array patches = ARGV_ARRAY_INIT; 852struct strbuf sb = STRBUF_INIT; 853int ret; 854 855if(!paths[0] || paths[1]) 856returnerror(_("Only one StGIT patch series can be applied at once")); 857 858 series_dir_buf =xstrdup(*paths); 859 series_dir =dirname(series_dir_buf); 860 861 fp =fopen(*paths,"r"); 862if(!fp) 863returnerror_errno(_("could not open '%s' for reading"), *paths); 864 865while(!strbuf_getline_lf(&sb, fp)) { 866if(*sb.buf =='#') 867continue;/* skip comment lines */ 868 869argv_array_push(&patches,mkpath("%s/%s", series_dir, sb.buf)); 870} 871 872fclose(fp); 873strbuf_release(&sb); 874free(series_dir_buf); 875 876 ret =split_mail_conv(stgit_patch_to_mail, state, patches.argv, keep_cr); 877 878argv_array_clear(&patches); 879return ret; 880} 881 882/** 883 * A split_patches_conv() callback that converts a mercurial patch to a RFC2822 884 * message suitable for parsing with git-mailinfo. 885 */ 886static inthg_patch_to_mail(FILE*out,FILE*in,int keep_cr) 887{ 888struct strbuf sb = STRBUF_INIT; 889int rc =0; 890 891while(!strbuf_getline_lf(&sb, in)) { 892const char*str; 893 894if(skip_prefix(sb.buf,"# User ", &str)) 895fprintf(out,"From:%s\n", str); 896else if(skip_prefix(sb.buf,"# Date ", &str)) { 897 timestamp_t timestamp; 898long tz, tz2; 899char*end; 900 901 errno =0; 902 timestamp =parse_timestamp(str, &end,10); 903if(errno) { 904 rc =error(_("invalid timestamp")); 905goto exit; 906} 907 908if(!skip_prefix(end," ", &str)) { 909 rc =error(_("invalid Date line")); 910goto exit; 911} 912 913 errno =0; 914 tz =strtol(str, &end,10); 915if(errno) { 916 rc =error(_("invalid timezone offset")); 917goto exit; 918} 919 920if(*end) { 921 rc =error(_("invalid Date line")); 922goto exit; 923} 924 925/* 926 * mercurial's timezone is in seconds west of UTC, 927 * however git's timezone is in hours + minutes east of 928 * UTC. Convert it. 929 */ 930 tz2 =labs(tz) /3600*100+labs(tz) %3600/60; 931if(tz >0) 932 tz2 = -tz2; 933 934fprintf(out,"Date:%s\n",show_date(timestamp, tz2,DATE_MODE(RFC2822))); 935}else if(starts_with(sb.buf,"# ")) { 936continue; 937}else{ 938fprintf(out,"\n%s\n", sb.buf); 939break; 940} 941} 942 943strbuf_reset(&sb); 944while(strbuf_fread(&sb,8192, in) >0) { 945fwrite(sb.buf,1, sb.len, out); 946strbuf_reset(&sb); 947} 948exit: 949strbuf_release(&sb); 950return rc; 951} 952 953/** 954 * Splits a list of files/directories into individual email patches. Each path 955 * in `paths` must be a file/directory that is formatted according to 956 * `patch_format`. 957 * 958 * Once split out, the individual email patches will be stored in the state 959 * directory, with each patch's filename being its index, padded to state->prec 960 * digits. 961 * 962 * state->cur will be set to the index of the first mail, and state->last will 963 * be set to the index of the last mail. 964 * 965 * Set keep_cr to 0 to convert all lines ending with \r\n to end with \n, 1 966 * to disable this behavior, -1 to use the default configured setting. 967 * 968 * Returns 0 on success, -1 on failure. 969 */ 970static intsplit_mail(struct am_state *state,enum patch_format patch_format, 971const char**paths,int keep_cr) 972{ 973if(keep_cr <0) { 974 keep_cr =0; 975git_config_get_bool("am.keepcr", &keep_cr); 976} 977 978switch(patch_format) { 979case PATCH_FORMAT_MBOX: 980returnsplit_mail_mbox(state, paths, keep_cr,0); 981case PATCH_FORMAT_STGIT: 982returnsplit_mail_conv(stgit_patch_to_mail, state, paths, keep_cr); 983case PATCH_FORMAT_STGIT_SERIES: 984returnsplit_mail_stgit_series(state, paths, keep_cr); 985case PATCH_FORMAT_HG: 986returnsplit_mail_conv(hg_patch_to_mail, state, paths, keep_cr); 987case PATCH_FORMAT_MBOXRD: 988returnsplit_mail_mbox(state, paths, keep_cr,1); 989default: 990BUG("invalid patch_format"); 991} 992return-1; 993} 994 995/** 996 * Setup a new am session for applying patches 997 */ 998static voidam_setup(struct am_state *state,enum patch_format patch_format, 999const char**paths,int keep_cr)1000{1001struct object_id curr_head;1002const char*str;1003struct strbuf sb = STRBUF_INIT;10041005if(!patch_format)1006 patch_format =detect_patch_format(paths);10071008if(!patch_format) {1009fprintf_ln(stderr,_("Patch format detection failed."));1010exit(128);1011}10121013if(mkdir(state->dir,0777) <0&& errno != EEXIST)1014die_errno(_("failed to create directory '%s'"), state->dir);1015delete_ref(NULL,"REBASE_HEAD", NULL, REF_NO_DEREF);10161017if(split_mail(state, patch_format, paths, keep_cr) <0) {1018am_destroy(state);1019die(_("Failed to split patches."));1020}10211022if(state->rebasing)1023 state->threeway =1;10241025write_state_bool(state,"threeway", state->threeway);1026write_state_bool(state,"quiet", state->quiet);1027write_state_bool(state,"sign", state->signoff);1028write_state_bool(state,"utf8", state->utf8);10291030if(state->allow_rerere_autoupdate)1031write_state_bool(state,"rerere-autoupdate",1032 state->allow_rerere_autoupdate == RERERE_AUTOUPDATE);10331034switch(state->keep) {1035case KEEP_FALSE:1036 str ="f";1037break;1038case KEEP_TRUE:1039 str ="t";1040break;1041case KEEP_NON_PATCH:1042 str ="b";1043break;1044default:1045BUG("invalid value for state->keep");1046}10471048write_state_text(state,"keep", str);1049write_state_bool(state,"messageid", state->message_id);10501051switch(state->scissors) {1052case SCISSORS_UNSET:1053 str ="";1054break;1055case SCISSORS_FALSE:1056 str ="f";1057break;1058case SCISSORS_TRUE:1059 str ="t";1060break;1061default:1062BUG("invalid value for state->scissors");1063}1064write_state_text(state,"scissors", str);10651066sq_quote_argv(&sb, state->git_apply_opts.argv);1067write_state_text(state,"apply-opt", sb.buf);10681069if(state->rebasing)1070write_state_text(state,"rebasing","");1071else1072write_state_text(state,"applying","");10731074if(!get_oid("HEAD", &curr_head)) {1075write_state_text(state,"abort-safety",oid_to_hex(&curr_head));1076if(!state->rebasing)1077update_ref("am","ORIG_HEAD", &curr_head, NULL,0,1078 UPDATE_REFS_DIE_ON_ERR);1079}else{1080write_state_text(state,"abort-safety","");1081if(!state->rebasing)1082delete_ref(NULL,"ORIG_HEAD", NULL,0);1083}10841085/*1086 * NOTE: Since the "next" and "last" files determine if an am_state1087 * session is in progress, they should be written last.1088 */10891090write_state_count(state,"next", state->cur);1091write_state_count(state,"last", state->last);10921093strbuf_release(&sb);1094}10951096/**1097 * Increments the patch pointer, and cleans am_state for the application of the1098 * next patch.1099 */1100static voidam_next(struct am_state *state)1101{1102struct object_id head;11031104FREE_AND_NULL(state->author_name);1105FREE_AND_NULL(state->author_email);1106FREE_AND_NULL(state->author_date);1107FREE_AND_NULL(state->msg);1108 state->msg_len =0;11091110unlink(am_path(state,"author-script"));1111unlink(am_path(state,"final-commit"));11121113oidclr(&state->orig_commit);1114unlink(am_path(state,"original-commit"));1115delete_ref(NULL,"REBASE_HEAD", NULL, REF_NO_DEREF);11161117if(!get_oid("HEAD", &head))1118write_state_text(state,"abort-safety",oid_to_hex(&head));1119else1120write_state_text(state,"abort-safety","");11211122 state->cur++;1123write_state_count(state,"next", state->cur);1124}11251126/**1127 * Returns the filename of the current patch email.1128 */1129static const char*msgnum(const struct am_state *state)1130{1131static struct strbuf sb = STRBUF_INIT;11321133strbuf_reset(&sb);1134strbuf_addf(&sb,"%0*d", state->prec, state->cur);11351136return sb.buf;1137}11381139/**1140 * Refresh and write index.1141 */1142static voidrefresh_and_write_cache(void)1143{1144struct lock_file lock_file = LOCK_INIT;11451146hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);1147refresh_cache(REFRESH_QUIET);1148if(write_locked_index(&the_index, &lock_file, COMMIT_LOCK))1149die(_("unable to write index file"));1150}11511152/**1153 * Dies with a user-friendly message on how to proceed after resolving the1154 * problem. This message can be overridden with state->resolvemsg.1155 */1156static void NORETURN die_user_resolve(const struct am_state *state)1157{1158if(state->resolvemsg) {1159printf_ln("%s", state->resolvemsg);1160}else{1161const char*cmdline = state->interactive ?"git am -i":"git am";11621163printf_ln(_("When you have resolved this problem, run\"%s--continue\"."), cmdline);1164printf_ln(_("If you prefer to skip this patch, run\"%s--skip\"instead."), cmdline);1165printf_ln(_("To restore the original branch and stop patching, run\"%s--abort\"."), cmdline);1166}11671168exit(128);1169}11701171/**1172 * Appends signoff to the "msg" field of the am_state.1173 */1174static voidam_append_signoff(struct am_state *state)1175{1176struct strbuf sb = STRBUF_INIT;11771178strbuf_attach(&sb, state->msg, state->msg_len, state->msg_len);1179append_signoff(&sb,0,0);1180 state->msg =strbuf_detach(&sb, &state->msg_len);1181}11821183/**1184 * Parses `mail` using git-mailinfo, extracting its patch and authorship info.1185 * state->msg will be set to the patch message. state->author_name,1186 * state->author_email and state->author_date will be set to the patch author's1187 * name, email and date respectively. The patch body will be written to the1188 * state directory's "patch" file.1189 *1190 * Returns 1 if the patch should be skipped, 0 otherwise.1191 */1192static intparse_mail(struct am_state *state,const char*mail)1193{1194FILE*fp;1195struct strbuf sb = STRBUF_INIT;1196struct strbuf msg = STRBUF_INIT;1197struct strbuf author_name = STRBUF_INIT;1198struct strbuf author_date = STRBUF_INIT;1199struct strbuf author_email = STRBUF_INIT;1200int ret =0;1201struct mailinfo mi;12021203setup_mailinfo(&mi);12041205if(state->utf8)1206 mi.metainfo_charset =get_commit_output_encoding();1207else1208 mi.metainfo_charset = NULL;12091210switch(state->keep) {1211case KEEP_FALSE:1212break;1213case KEEP_TRUE:1214 mi.keep_subject =1;1215break;1216case KEEP_NON_PATCH:1217 mi.keep_non_patch_brackets_in_subject =1;1218break;1219default:1220BUG("invalid value for state->keep");1221}12221223if(state->message_id)1224 mi.add_message_id =1;12251226switch(state->scissors) {1227case SCISSORS_UNSET:1228break;1229case SCISSORS_FALSE:1230 mi.use_scissors =0;1231break;1232case SCISSORS_TRUE:1233 mi.use_scissors =1;1234break;1235default:1236BUG("invalid value for state->scissors");1237}12381239 mi.input =xfopen(mail,"r");1240 mi.output =xfopen(am_path(state,"info"),"w");1241if(mailinfo(&mi,am_path(state,"msg"),am_path(state,"patch")))1242die("could not parse patch");12431244fclose(mi.input);1245fclose(mi.output);12461247if(mi.format_flowed)1248warning(_("Patch sent with format=flowed; "1249"space at the end of lines might be lost."));12501251/* Extract message and author information */1252 fp =xfopen(am_path(state,"info"),"r");1253while(!strbuf_getline_lf(&sb, fp)) {1254const char*x;12551256if(skip_prefix(sb.buf,"Subject: ", &x)) {1257if(msg.len)1258strbuf_addch(&msg,'\n');1259strbuf_addstr(&msg, x);1260}else if(skip_prefix(sb.buf,"Author: ", &x))1261strbuf_addstr(&author_name, x);1262else if(skip_prefix(sb.buf,"Email: ", &x))1263strbuf_addstr(&author_email, x);1264else if(skip_prefix(sb.buf,"Date: ", &x))1265strbuf_addstr(&author_date, x);1266}1267fclose(fp);12681269/* Skip pine's internal folder data */1270if(!strcmp(author_name.buf,"Mail System Internal Data")) {1271 ret =1;1272goto finish;1273}12741275if(is_empty_file(am_path(state,"patch"))) {1276printf_ln(_("Patch is empty."));1277die_user_resolve(state);1278}12791280strbuf_addstr(&msg,"\n\n");1281strbuf_addbuf(&msg, &mi.log_message);1282strbuf_stripspace(&msg,0);12831284assert(!state->author_name);1285 state->author_name =strbuf_detach(&author_name, NULL);12861287assert(!state->author_email);1288 state->author_email =strbuf_detach(&author_email, NULL);12891290assert(!state->author_date);1291 state->author_date =strbuf_detach(&author_date, NULL);12921293assert(!state->msg);1294 state->msg =strbuf_detach(&msg, &state->msg_len);12951296finish:1297strbuf_release(&msg);1298strbuf_release(&author_date);1299strbuf_release(&author_email);1300strbuf_release(&author_name);1301strbuf_release(&sb);1302clear_mailinfo(&mi);1303return ret;1304}13051306/**1307 * Sets commit_id to the commit hash where the mail was generated from.1308 * Returns 0 on success, -1 on failure.1309 */1310static intget_mail_commit_oid(struct object_id *commit_id,const char*mail)1311{1312struct strbuf sb = STRBUF_INIT;1313FILE*fp =xfopen(mail,"r");1314const char*x;1315int ret =0;13161317if(strbuf_getline_lf(&sb, fp) ||1318!skip_prefix(sb.buf,"From ", &x) ||1319get_oid_hex(x, commit_id) <0)1320 ret = -1;13211322strbuf_release(&sb);1323fclose(fp);1324return ret;1325}13261327/**1328 * Sets state->msg, state->author_name, state->author_email, state->author_date1329 * to the commit's respective info.1330 */1331static voidget_commit_info(struct am_state *state,struct commit *commit)1332{1333const char*buffer, *ident_line, *msg;1334size_t ident_len;1335struct ident_split id;13361337 buffer =logmsg_reencode(commit, NULL,get_commit_output_encoding());13381339 ident_line =find_commit_header(buffer,"author", &ident_len);13401341if(split_ident_line(&id, ident_line, ident_len) <0)1342die(_("invalid ident line: %.*s"), (int)ident_len, ident_line);13431344assert(!state->author_name);1345if(id.name_begin)1346 state->author_name =1347xmemdupz(id.name_begin, id.name_end - id.name_begin);1348else1349 state->author_name =xstrdup("");13501351assert(!state->author_email);1352if(id.mail_begin)1353 state->author_email =1354xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);1355else1356 state->author_email =xstrdup("");13571358assert(!state->author_date);1359 state->author_date =xstrdup(show_ident_date(&id,DATE_MODE(NORMAL)));13601361assert(!state->msg);1362 msg =strstr(buffer,"\n\n");1363if(!msg)1364die(_("unable to parse commit%s"),oid_to_hex(&commit->object.oid));1365 state->msg =xstrdup(msg +2);1366 state->msg_len =strlen(state->msg);1367unuse_commit_buffer(commit, buffer);1368}13691370/**1371 * Writes `commit` as a patch to the state directory's "patch" file.1372 */1373static voidwrite_commit_patch(const struct am_state *state,struct commit *commit)1374{1375struct rev_info rev_info;1376FILE*fp;13771378 fp =xfopen(am_path(state,"patch"),"w");1379repo_init_revisions(the_repository, &rev_info, NULL);1380 rev_info.diff =1;1381 rev_info.abbrev =0;1382 rev_info.disable_stdin =1;1383 rev_info.show_root_diff =1;1384 rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;1385 rev_info.no_commit_id =1;1386 rev_info.diffopt.flags.binary =1;1387 rev_info.diffopt.flags.full_index =1;1388 rev_info.diffopt.use_color =0;1389 rev_info.diffopt.file = fp;1390 rev_info.diffopt.close_file =1;1391add_pending_object(&rev_info, &commit->object,"");1392diff_setup_done(&rev_info.diffopt);1393log_tree_commit(&rev_info, commit);1394}13951396/**1397 * Writes the diff of the index against HEAD as a patch to the state1398 * directory's "patch" file.1399 */1400static voidwrite_index_patch(const struct am_state *state)1401{1402struct tree *tree;1403struct object_id head;1404struct rev_info rev_info;1405FILE*fp;14061407if(!get_oid_tree("HEAD", &head))1408 tree =lookup_tree(the_repository, &head);1409else1410 tree =lookup_tree(the_repository,1411 the_repository->hash_algo->empty_tree);14121413 fp =xfopen(am_path(state,"patch"),"w");1414repo_init_revisions(the_repository, &rev_info, NULL);1415 rev_info.diff =1;1416 rev_info.disable_stdin =1;1417 rev_info.no_commit_id =1;1418 rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;1419 rev_info.diffopt.use_color =0;1420 rev_info.diffopt.file = fp;1421 rev_info.diffopt.close_file =1;1422add_pending_object(&rev_info, &tree->object,"");1423diff_setup_done(&rev_info.diffopt);1424run_diff_index(&rev_info,1);1425}14261427/**1428 * Like parse_mail(), but parses the mail by looking up its commit ID1429 * directly. This is used in --rebasing mode to bypass git-mailinfo's munging1430 * of patches.1431 *1432 * state->orig_commit will be set to the original commit ID.1433 *1434 * Will always return 0 as the patch should never be skipped.1435 */1436static intparse_mail_rebase(struct am_state *state,const char*mail)1437{1438struct commit *commit;1439struct object_id commit_oid;14401441if(get_mail_commit_oid(&commit_oid, mail) <0)1442die(_("could not parse%s"), mail);14431444 commit =lookup_commit_or_die(&commit_oid, mail);14451446get_commit_info(state, commit);14471448write_commit_patch(state, commit);14491450oidcpy(&state->orig_commit, &commit_oid);1451write_state_text(state,"original-commit",oid_to_hex(&commit_oid));1452update_ref("am","REBASE_HEAD", &commit_oid,1453 NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);14541455return0;1456}14571458/**1459 * Applies current patch with git-apply. Returns 0 on success, -1 otherwise. If1460 * `index_file` is not NULL, the patch will be applied to that index.1461 */1462static intrun_apply(const struct am_state *state,const char*index_file)1463{1464struct argv_array apply_paths = ARGV_ARRAY_INIT;1465struct argv_array apply_opts = ARGV_ARRAY_INIT;1466struct apply_state apply_state;1467int res, opts_left;1468int force_apply =0;1469int options =0;14701471if(init_apply_state(&apply_state, the_repository, NULL))1472BUG("init_apply_state() failed");14731474argv_array_push(&apply_opts,"apply");1475argv_array_pushv(&apply_opts, state->git_apply_opts.argv);14761477 opts_left =apply_parse_options(apply_opts.argc, apply_opts.argv,1478&apply_state, &force_apply, &options,1479 NULL);14801481if(opts_left !=0)1482die("unknown option passed through to git apply");14831484if(index_file) {1485 apply_state.index_file = index_file;1486 apply_state.cached =1;1487}else1488 apply_state.check_index =1;14891490/*1491 * If we are allowed to fall back on 3-way merge, don't give false1492 * errors during the initial attempt.1493 */1494if(state->threeway && !index_file)1495 apply_state.apply_verbosity = verbosity_silent;14961497if(check_apply_state(&apply_state, force_apply))1498BUG("check_apply_state() failed");14991500argv_array_push(&apply_paths,am_path(state,"patch"));15011502 res =apply_all_patches(&apply_state, apply_paths.argc, apply_paths.argv, options);15031504argv_array_clear(&apply_paths);1505argv_array_clear(&apply_opts);1506clear_apply_state(&apply_state);15071508if(res)1509return res;15101511if(index_file) {1512/* Reload index as apply_all_patches() will have modified it. */1513discard_cache();1514read_cache_from(index_file);1515}15161517return0;1518}15191520/**1521 * Builds an index that contains just the blobs needed for a 3way merge.1522 */1523static intbuild_fake_ancestor(const struct am_state *state,const char*index_file)1524{1525struct child_process cp = CHILD_PROCESS_INIT;15261527 cp.git_cmd =1;1528argv_array_push(&cp.args,"apply");1529argv_array_pushv(&cp.args, state->git_apply_opts.argv);1530argv_array_pushf(&cp.args,"--build-fake-ancestor=%s", index_file);1531argv_array_push(&cp.args,am_path(state,"patch"));15321533if(run_command(&cp))1534return-1;15351536return0;1537}15381539/**1540 * Attempt a threeway merge, using index_path as the temporary index.1541 */1542static intfall_back_threeway(const struct am_state *state,const char*index_path)1543{1544struct object_id orig_tree, their_tree, our_tree;1545const struct object_id *bases[1] = { &orig_tree };1546struct merge_options o;1547struct commit *result;1548char*their_tree_name;15491550if(get_oid("HEAD", &our_tree) <0)1551oidcpy(&our_tree, the_hash_algo->empty_tree);15521553if(build_fake_ancestor(state, index_path))1554returnerror("could not build fake ancestor");15551556discard_cache();1557read_cache_from(index_path);15581559if(write_index_as_tree(&orig_tree, &the_index, index_path,0, NULL))1560returnerror(_("Repository lacks necessary blobs to fall back on 3-way merge."));15611562say(state, stdout,_("Using index info to reconstruct a base tree..."));15631564if(!state->quiet) {1565/*1566 * List paths that needed 3-way fallback, so that the user can1567 * review them with extra care to spot mismerges.1568 */1569struct rev_info rev_info;1570const char*diff_filter_str ="--diff-filter=AM";15711572repo_init_revisions(the_repository, &rev_info, NULL);1573 rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;1574diff_opt_parse(&rev_info.diffopt, &diff_filter_str,1, rev_info.prefix);1575add_pending_oid(&rev_info,"HEAD", &our_tree,0);1576diff_setup_done(&rev_info.diffopt);1577run_diff_index(&rev_info,1);1578}15791580if(run_apply(state, index_path))1581returnerror(_("Did you hand edit your patch?\n"1582"It does not apply to blobs recorded in its index."));15831584if(write_index_as_tree(&their_tree, &the_index, index_path,0, NULL))1585returnerror("could not write tree");15861587say(state, stdout,_("Falling back to patching base and 3-way merge..."));15881589discard_cache();1590read_cache();15911592/*1593 * This is not so wrong. Depending on which base we picked, orig_tree1594 * may be wildly different from ours, but their_tree has the same set of1595 * wildly different changes in parts the patch did not touch, so1596 * recursive ends up canceling them, saying that we reverted all those1597 * changes.1598 */15991600init_merge_options(&o);16011602 o.branch1 ="HEAD";1603 their_tree_name =xstrfmt("%.*s",linelen(state->msg), state->msg);1604 o.branch2 = their_tree_name;1605 o.detect_directory_renames =0;16061607if(state->quiet)1608 o.verbosity =0;16091610if(merge_recursive_generic(&o, &our_tree, &their_tree,1, bases, &result)) {1611repo_rerere(the_repository, state->allow_rerere_autoupdate);1612free(their_tree_name);1613returnerror(_("Failed to merge in the changes."));1614}16151616free(their_tree_name);1617return0;1618}16191620/**1621 * Commits the current index with state->msg as the commit message and1622 * state->author_name, state->author_email and state->author_date as the author1623 * information.1624 */1625static voiddo_commit(const struct am_state *state)1626{1627struct object_id tree, parent, commit;1628const struct object_id *old_oid;1629struct commit_list *parents = NULL;1630const char*reflog_msg, *author;1631struct strbuf sb = STRBUF_INIT;16321633if(run_hook_le(NULL,"pre-applypatch", NULL))1634exit(1);16351636if(write_cache_as_tree(&tree,0, NULL))1637die(_("git write-tree failed to write a tree"));16381639if(!get_oid_commit("HEAD", &parent)) {1640 old_oid = &parent;1641commit_list_insert(lookup_commit(the_repository, &parent),1642&parents);1643}else{1644 old_oid = NULL;1645say(state, stderr,_("applying to an empty history"));1646}16471648 author =fmt_ident(state->author_name, state->author_email,1649 state->ignore_date ? NULL : state->author_date,1650 IDENT_STRICT);16511652if(state->committer_date_is_author_date)1653setenv("GIT_COMMITTER_DATE",1654 state->ignore_date ?"": state->author_date,1);16551656if(commit_tree(state->msg, state->msg_len, &tree, parents, &commit,1657 author, state->sign_commit))1658die(_("failed to write commit object"));16591660 reflog_msg =getenv("GIT_REFLOG_ACTION");1661if(!reflog_msg)1662 reflog_msg ="am";16631664strbuf_addf(&sb,"%s: %.*s", reflog_msg,linelen(state->msg),1665 state->msg);16661667update_ref(sb.buf,"HEAD", &commit, old_oid,0,1668 UPDATE_REFS_DIE_ON_ERR);16691670if(state->rebasing) {1671FILE*fp =xfopen(am_path(state,"rewritten"),"a");16721673assert(!is_null_oid(&state->orig_commit));1674fprintf(fp,"%s",oid_to_hex(&state->orig_commit));1675fprintf(fp,"%s\n",oid_to_hex(&commit));1676fclose(fp);1677}16781679run_hook_le(NULL,"post-applypatch", NULL);16801681strbuf_release(&sb);1682}16831684/**1685 * Validates the am_state for resuming -- the "msg" and authorship fields must1686 * be filled up.1687 */1688static voidvalidate_resume_state(const struct am_state *state)1689{1690if(!state->msg)1691die(_("cannot resume:%sdoes not exist."),1692am_path(state,"final-commit"));16931694if(!state->author_name || !state->author_email || !state->author_date)1695die(_("cannot resume:%sdoes not exist."),1696am_path(state,"author-script"));1697}16981699/**1700 * Interactively prompt the user on whether the current patch should be1701 * applied.1702 *1703 * Returns 0 if the user chooses to apply the patch, 1 if the user chooses to1704 * skip it.1705 */1706static intdo_interactive(struct am_state *state)1707{1708assert(state->msg);17091710if(!isatty(0))1711die(_("cannot be interactive without stdin connected to a terminal."));17121713for(;;) {1714const char*reply;17151716puts(_("Commit Body is:"));1717puts("--------------------------");1718printf("%s", state->msg);1719puts("--------------------------");17201721/*1722 * TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]1723 * in your translation. The program will only accept English1724 * input at this point.1725 */1726 reply =git_prompt(_("Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "), PROMPT_ECHO);17271728if(!reply) {1729continue;1730}else if(*reply =='y'|| *reply =='Y') {1731return0;1732}else if(*reply =='a'|| *reply =='A') {1733 state->interactive =0;1734return0;1735}else if(*reply =='n'|| *reply =='N') {1736return1;1737}else if(*reply =='e'|| *reply =='E') {1738struct strbuf msg = STRBUF_INIT;17391740if(!launch_editor(am_path(state,"final-commit"), &msg, NULL)) {1741free(state->msg);1742 state->msg =strbuf_detach(&msg, &state->msg_len);1743}1744strbuf_release(&msg);1745}else if(*reply =='v'|| *reply =='V') {1746const char*pager =git_pager(1);1747struct child_process cp = CHILD_PROCESS_INIT;17481749if(!pager)1750 pager ="cat";1751prepare_pager_args(&cp, pager);1752argv_array_push(&cp.args,am_path(state,"patch"));1753run_command(&cp);1754}1755}1756}17571758/**1759 * Applies all queued mail.1760 *1761 * If `resume` is true, we are "resuming". The "msg" and authorship fields, as1762 * well as the state directory's "patch" file is used as-is for applying the1763 * patch and committing it.1764 */1765static voidam_run(struct am_state *state,int resume)1766{1767const char*argv_gc_auto[] = {"gc","--auto", NULL};1768struct strbuf sb = STRBUF_INIT;17691770unlink(am_path(state,"dirtyindex"));17711772refresh_and_write_cache();17731774if(index_has_changes(&the_index, NULL, &sb)) {1775write_state_bool(state,"dirtyindex",1);1776die(_("Dirty index: cannot apply patches (dirty:%s)"), sb.buf);1777}17781779strbuf_release(&sb);17801781while(state->cur <= state->last) {1782const char*mail =am_path(state,msgnum(state));1783int apply_status;17841785reset_ident_date();17861787if(!file_exists(mail))1788goto next;17891790if(resume) {1791validate_resume_state(state);1792}else{1793int skip;17941795if(state->rebasing)1796 skip =parse_mail_rebase(state, mail);1797else1798 skip =parse_mail(state, mail);17991800if(skip)1801goto next;/* mail should be skipped */18021803if(state->signoff)1804am_append_signoff(state);18051806write_author_script(state);1807write_commit_msg(state);1808}18091810if(state->interactive &&do_interactive(state))1811goto next;18121813if(run_applypatch_msg_hook(state))1814exit(1);18151816say(state, stdout,_("Applying: %.*s"),linelen(state->msg), state->msg);18171818 apply_status =run_apply(state, NULL);18191820if(apply_status && state->threeway) {1821struct strbuf sb = STRBUF_INIT;18221823strbuf_addstr(&sb,am_path(state,"patch-merge-index"));1824 apply_status =fall_back_threeway(state, sb.buf);1825strbuf_release(&sb);18261827/*1828 * Applying the patch to an earlier tree and merging1829 * the result may have produced the same tree as ours.1830 */1831if(!apply_status &&1832!index_has_changes(&the_index, NULL, NULL)) {1833say(state, stdout,_("No changes -- Patch already applied."));1834goto next;1835}1836}18371838if(apply_status) {1839printf_ln(_("Patch failed at%s%.*s"),msgnum(state),1840linelen(state->msg), state->msg);18411842if(advice_amworkdir)1843advise(_("Use 'git am --show-current-patch' to see the failed patch"));18441845die_user_resolve(state);1846}18471848do_commit(state);18491850next:1851am_next(state);18521853if(resume)1854am_load(state);1855 resume =0;1856}18571858if(!is_empty_file(am_path(state,"rewritten"))) {1859assert(state->rebasing);1860copy_notes_for_rebase(state);1861run_post_rewrite_hook(state);1862}18631864/*1865 * In rebasing mode, it's up to the caller to take care of1866 * housekeeping.1867 */1868if(!state->rebasing) {1869am_destroy(state);1870close_all_packs(the_repository->objects);1871run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);1872}1873}18741875/**1876 * Resume the current am session after patch application failure. The user did1877 * all the hard work, and we do not have to do any patch application. Just1878 * trust and commit what the user has in the index and working tree.1879 */1880static voidam_resolve(struct am_state *state)1881{1882validate_resume_state(state);18831884say(state, stdout,_("Applying: %.*s"),linelen(state->msg), state->msg);18851886if(!index_has_changes(&the_index, NULL, NULL)) {1887printf_ln(_("No changes - did you forget to use 'git add'?\n"1888"If there is nothing left to stage, chances are that something else\n"1889"already introduced the same changes; you might want to skip this patch."));1890die_user_resolve(state);1891}18921893if(unmerged_cache()) {1894printf_ln(_("You still have unmerged paths in your index.\n"1895"You should 'git add' each file with resolved conflicts to mark them as such.\n"1896"You might run `git rm` on a file to accept\"deleted by them\"for it."));1897die_user_resolve(state);1898}18991900if(state->interactive) {1901write_index_patch(state);1902if(do_interactive(state))1903goto next;1904}19051906repo_rerere(the_repository,0);19071908do_commit(state);19091910next:1911am_next(state);1912am_load(state);1913am_run(state,0);1914}19151916/**1917 * Performs a checkout fast-forward from `head` to `remote`. If `reset` is1918 * true, any unmerged entries will be discarded. Returns 0 on success, -1 on1919 * failure.1920 */1921static intfast_forward_to(struct tree *head,struct tree *remote,int reset)1922{1923struct lock_file lock_file = LOCK_INIT;1924struct unpack_trees_options opts;1925struct tree_desc t[2];19261927if(parse_tree(head) ||parse_tree(remote))1928return-1;19291930hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);19311932refresh_cache(REFRESH_QUIET);19331934memset(&opts,0,sizeof(opts));1935 opts.head_idx =1;1936 opts.src_index = &the_index;1937 opts.dst_index = &the_index;1938 opts.update =1;1939 opts.merge =1;1940 opts.reset = reset;1941 opts.fn = twoway_merge;1942init_tree_desc(&t[0], head->buffer, head->size);1943init_tree_desc(&t[1], remote->buffer, remote->size);19441945if(unpack_trees(2, t, &opts)) {1946rollback_lock_file(&lock_file);1947return-1;1948}19491950if(write_locked_index(&the_index, &lock_file, COMMIT_LOCK))1951die(_("unable to write new index file"));19521953return0;1954}19551956/**1957 * Merges a tree into the index. The index's stat info will take precedence1958 * over the merged tree's. Returns 0 on success, -1 on failure.1959 */1960static intmerge_tree(struct tree *tree)1961{1962struct lock_file lock_file = LOCK_INIT;1963struct unpack_trees_options opts;1964struct tree_desc t[1];19651966if(parse_tree(tree))1967return-1;19681969hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);19701971memset(&opts,0,sizeof(opts));1972 opts.head_idx =1;1973 opts.src_index = &the_index;1974 opts.dst_index = &the_index;1975 opts.merge =1;1976 opts.fn = oneway_merge;1977init_tree_desc(&t[0], tree->buffer, tree->size);19781979if(unpack_trees(1, t, &opts)) {1980rollback_lock_file(&lock_file);1981return-1;1982}19831984if(write_locked_index(&the_index, &lock_file, COMMIT_LOCK))1985die(_("unable to write new index file"));19861987return0;1988}19891990/**1991 * Clean the index without touching entries that are not modified between1992 * `head` and `remote`.1993 */1994static intclean_index(const struct object_id *head,const struct object_id *remote)1995{1996struct tree *head_tree, *remote_tree, *index_tree;1997struct object_id index;19981999 head_tree =parse_tree_indirect(head);2000if(!head_tree)2001returnerror(_("Could not parse object '%s'."),oid_to_hex(head));20022003 remote_tree =parse_tree_indirect(remote);2004if(!remote_tree)2005returnerror(_("Could not parse object '%s'."),oid_to_hex(remote));20062007read_cache_unmerged();20082009if(fast_forward_to(head_tree, head_tree,1))2010return-1;20112012if(write_cache_as_tree(&index,0, NULL))2013return-1;20142015 index_tree =parse_tree_indirect(&index);2016if(!index_tree)2017returnerror(_("Could not parse object '%s'."),oid_to_hex(&index));20182019if(fast_forward_to(index_tree, remote_tree,0))2020return-1;20212022if(merge_tree(remote_tree))2023return-1;20242025remove_branch_state(the_repository);20262027return0;2028}20292030/**2031 * Resets rerere's merge resolution metadata.2032 */2033static voidam_rerere_clear(void)2034{2035struct string_list merge_rr = STRING_LIST_INIT_DUP;2036rerere_clear(&merge_rr);2037string_list_clear(&merge_rr,1);2038}20392040/**2041 * Resume the current am session by skipping the current patch.2042 */2043static voidam_skip(struct am_state *state)2044{2045struct object_id head;20462047am_rerere_clear();20482049if(get_oid("HEAD", &head))2050oidcpy(&head, the_hash_algo->empty_tree);20512052if(clean_index(&head, &head))2053die(_("failed to clean index"));20542055am_next(state);2056am_load(state);2057am_run(state,0);2058}20592060/**2061 * Returns true if it is safe to reset HEAD to the ORIG_HEAD, false otherwise.2062 *2063 * It is not safe to reset HEAD when:2064 * 1. git-am previously failed because the index was dirty.2065 * 2. HEAD has moved since git-am previously failed.2066 */2067static intsafe_to_abort(const struct am_state *state)2068{2069struct strbuf sb = STRBUF_INIT;2070struct object_id abort_safety, head;20712072if(file_exists(am_path(state,"dirtyindex")))2073return0;20742075if(read_state_file(&sb, state,"abort-safety",1) >0) {2076if(get_oid_hex(sb.buf, &abort_safety))2077die(_("could not parse%s"),am_path(state,"abort-safety"));2078}else2079oidclr(&abort_safety);2080strbuf_release(&sb);20812082if(get_oid("HEAD", &head))2083oidclr(&head);20842085if(oideq(&head, &abort_safety))2086return1;20872088warning(_("You seem to have moved HEAD since the last 'am' failure.\n"2089"Not rewinding to ORIG_HEAD"));20902091return0;2092}20932094/**2095 * Aborts the current am session if it is safe to do so.2096 */2097static voidam_abort(struct am_state *state)2098{2099struct object_id curr_head, orig_head;2100int has_curr_head, has_orig_head;2101char*curr_branch;21022103if(!safe_to_abort(state)) {2104am_destroy(state);2105return;2106}21072108am_rerere_clear();21092110 curr_branch =resolve_refdup("HEAD",0, &curr_head, NULL);2111 has_curr_head = curr_branch && !is_null_oid(&curr_head);2112if(!has_curr_head)2113oidcpy(&curr_head, the_hash_algo->empty_tree);21142115 has_orig_head = !get_oid("ORIG_HEAD", &orig_head);2116if(!has_orig_head)2117oidcpy(&orig_head, the_hash_algo->empty_tree);21182119clean_index(&curr_head, &orig_head);21202121if(has_orig_head)2122update_ref("am --abort","HEAD", &orig_head,2123 has_curr_head ? &curr_head : NULL,0,2124 UPDATE_REFS_DIE_ON_ERR);2125else if(curr_branch)2126delete_ref(NULL, curr_branch, NULL, REF_NO_DEREF);21272128free(curr_branch);2129am_destroy(state);2130}21312132static intshow_patch(struct am_state *state)2133{2134struct strbuf sb = STRBUF_INIT;2135const char*patch_path;2136int len;21372138if(!is_null_oid(&state->orig_commit)) {2139const char*av[4] = {"show", NULL,"--", NULL };2140char*new_oid_str;2141int ret;21422143 av[1] = new_oid_str =xstrdup(oid_to_hex(&state->orig_commit));2144 ret =run_command_v_opt(av, RUN_GIT_CMD);2145free(new_oid_str);2146return ret;2147}21482149 patch_path =am_path(state,msgnum(state));2150 len =strbuf_read_file(&sb, patch_path,0);2151if(len <0)2152die_errno(_("failed to read '%s'"), patch_path);21532154setup_pager();2155write_in_full(1, sb.buf, sb.len);2156strbuf_release(&sb);2157return0;2158}21592160/**2161 * parse_options() callback that validates and sets opt->value to the2162 * PATCH_FORMAT_* enum value corresponding to `arg`.2163 */2164static intparse_opt_patchformat(const struct option *opt,const char*arg,int unset)2165{2166int*opt_value = opt->value;21672168if(!strcmp(arg,"mbox"))2169*opt_value = PATCH_FORMAT_MBOX;2170else if(!strcmp(arg,"stgit"))2171*opt_value = PATCH_FORMAT_STGIT;2172else if(!strcmp(arg,"stgit-series"))2173*opt_value = PATCH_FORMAT_STGIT_SERIES;2174else if(!strcmp(arg,"hg"))2175*opt_value = PATCH_FORMAT_HG;2176else if(!strcmp(arg,"mboxrd"))2177*opt_value = PATCH_FORMAT_MBOXRD;2178else2179returnerror(_("Invalid value for --patch-format:%s"), arg);2180return0;2181}21822183enum resume_mode {2184 RESUME_FALSE =0,2185 RESUME_APPLY,2186 RESUME_RESOLVED,2187 RESUME_SKIP,2188 RESUME_ABORT,2189 RESUME_QUIT,2190 RESUME_SHOW_PATCH2191};21922193static intgit_am_config(const char*k,const char*v,void*cb)2194{2195int status;21962197 status =git_gpg_config(k, v, NULL);2198if(status)2199return status;22002201returngit_default_config(k, v, NULL);2202}22032204intcmd_am(int argc,const char**argv,const char*prefix)2205{2206struct am_state state;2207int binary = -1;2208int keep_cr = -1;2209int patch_format = PATCH_FORMAT_UNKNOWN;2210enum resume_mode resume = RESUME_FALSE;2211int in_progress;2212int ret =0;22132214const char*const usage[] = {2215N_("git am [<options>] [(<mbox> | <Maildir>)...]"),2216N_("git am [<options>] (--continue | --skip | --abort)"),2217 NULL2218};22192220struct option options[] = {2221OPT_BOOL('i',"interactive", &state.interactive,2222N_("run interactively")),2223OPT_HIDDEN_BOOL('b',"binary", &binary,2224N_("historical option -- no-op")),2225OPT_BOOL('3',"3way", &state.threeway,2226N_("allow fall back on 3way merging if needed")),2227OPT__QUIET(&state.quiet,N_("be quiet")),2228OPT_SET_INT('s',"signoff", &state.signoff,2229N_("add a Signed-off-by line to the commit message"),2230 SIGNOFF_EXPLICIT),2231OPT_BOOL('u',"utf8", &state.utf8,2232N_("recode into utf8 (default)")),2233OPT_SET_INT('k',"keep", &state.keep,2234N_("pass -k flag to git-mailinfo"), KEEP_TRUE),2235OPT_SET_INT(0,"keep-non-patch", &state.keep,2236N_("pass -b flag to git-mailinfo"), KEEP_NON_PATCH),2237OPT_BOOL('m',"message-id", &state.message_id,2238N_("pass -m flag to git-mailinfo")),2239OPT_SET_INT_F(0,"keep-cr", &keep_cr,2240N_("pass --keep-cr flag to git-mailsplit for mbox format"),22411, PARSE_OPT_NONEG),2242OPT_SET_INT_F(0,"no-keep-cr", &keep_cr,2243N_("do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"),22440, PARSE_OPT_NONEG),2245OPT_BOOL('c',"scissors", &state.scissors,2246N_("strip everything before a scissors line")),2247OPT_PASSTHRU_ARGV(0,"whitespace", &state.git_apply_opts,N_("action"),2248N_("pass it through git-apply"),22490),2250OPT_PASSTHRU_ARGV(0,"ignore-space-change", &state.git_apply_opts, NULL,2251N_("pass it through git-apply"),2252 PARSE_OPT_NOARG),2253OPT_PASSTHRU_ARGV(0,"ignore-whitespace", &state.git_apply_opts, NULL,2254N_("pass it through git-apply"),2255 PARSE_OPT_NOARG),2256OPT_PASSTHRU_ARGV(0,"directory", &state.git_apply_opts,N_("root"),2257N_("pass it through git-apply"),22580),2259OPT_PASSTHRU_ARGV(0,"exclude", &state.git_apply_opts,N_("path"),2260N_("pass it through git-apply"),22610),2262OPT_PASSTHRU_ARGV(0,"include", &state.git_apply_opts,N_("path"),2263N_("pass it through git-apply"),22640),2265OPT_PASSTHRU_ARGV('C', NULL, &state.git_apply_opts,N_("n"),2266N_("pass it through git-apply"),22670),2268OPT_PASSTHRU_ARGV('p', NULL, &state.git_apply_opts,N_("num"),2269N_("pass it through git-apply"),22700),2271OPT_CALLBACK(0,"patch-format", &patch_format,N_("format"),2272N_("format the patch(es) are in"),2273 parse_opt_patchformat),2274OPT_PASSTHRU_ARGV(0,"reject", &state.git_apply_opts, NULL,2275N_("pass it through git-apply"),2276 PARSE_OPT_NOARG),2277OPT_STRING(0,"resolvemsg", &state.resolvemsg, NULL,2278N_("override error message when patch failure occurs")),2279OPT_CMDMODE(0,"continue", &resume,2280N_("continue applying patches after resolving a conflict"),2281 RESUME_RESOLVED),2282OPT_CMDMODE('r',"resolved", &resume,2283N_("synonyms for --continue"),2284 RESUME_RESOLVED),2285OPT_CMDMODE(0,"skip", &resume,2286N_("skip the current patch"),2287 RESUME_SKIP),2288OPT_CMDMODE(0,"abort", &resume,2289N_("restore the original branch and abort the patching operation."),2290 RESUME_ABORT),2291OPT_CMDMODE(0,"quit", &resume,2292N_("abort the patching operation but keep HEAD where it is."),2293 RESUME_QUIT),2294OPT_CMDMODE(0,"show-current-patch", &resume,2295N_("show the patch being applied."),2296 RESUME_SHOW_PATCH),2297OPT_BOOL(0,"committer-date-is-author-date",2298&state.committer_date_is_author_date,2299N_("lie about committer date")),2300OPT_BOOL(0,"ignore-date", &state.ignore_date,2301N_("use current timestamp for author date")),2302OPT_RERERE_AUTOUPDATE(&state.allow_rerere_autoupdate),2303{ OPTION_STRING,'S',"gpg-sign", &state.sign_commit,N_("key-id"),2304N_("GPG-sign commits"),2305 PARSE_OPT_OPTARG, NULL, (intptr_t)""},2306OPT_HIDDEN_BOOL(0,"rebasing", &state.rebasing,2307N_("(internal use for git-rebase)")),2308OPT_END()2309};23102311if(argc ==2&& !strcmp(argv[1],"-h"))2312usage_with_options(usage, options);23132314git_config(git_am_config, NULL);23152316am_state_init(&state);23172318 in_progress =am_in_progress(&state);2319if(in_progress)2320am_load(&state);23212322 argc =parse_options(argc, argv, prefix, options, usage,0);23232324if(binary >=0)2325fprintf_ln(stderr,_("The -b/--binary option has been a no-op for long time, and\n"2326"it will be removed. Please do not use it anymore."));23272328/* Ensure a valid committer ident can be constructed */2329git_committer_info(IDENT_STRICT);23302331if(read_index_preload(&the_index, NULL,0) <0)2332die(_("failed to read the index"));23332334if(in_progress) {2335/*2336 * Catch user error to feed us patches when there is a session2337 * in progress:2338 *2339 * 1. mbox path(s) are provided on the command-line.2340 * 2. stdin is not a tty: the user is trying to feed us a patch2341 * from standard input. This is somewhat unreliable -- stdin2342 * could be /dev/null for example and the caller did not2343 * intend to feed us a patch but wanted to continue2344 * unattended.2345 */2346if(argc || (resume == RESUME_FALSE && !isatty(0)))2347die(_("previous rebase directory%sstill exists but mbox given."),2348 state.dir);23492350if(resume == RESUME_FALSE)2351 resume = RESUME_APPLY;23522353if(state.signoff == SIGNOFF_EXPLICIT)2354am_append_signoff(&state);2355}else{2356struct argv_array paths = ARGV_ARRAY_INIT;2357int i;23582359/*2360 * Handle stray state directory in the independent-run case. In2361 * the --rebasing case, it is up to the caller to take care of2362 * stray directories.2363 */2364if(file_exists(state.dir) && !state.rebasing) {2365if(resume == RESUME_ABORT || resume == RESUME_QUIT) {2366am_destroy(&state);2367am_state_release(&state);2368return0;2369}23702371die(_("Stray%sdirectory found.\n"2372"Use\"git am --abort\"to remove it."),2373 state.dir);2374}23752376if(resume)2377die(_("Resolve operation not in progress, we are not resuming."));23782379for(i =0; i < argc; i++) {2380if(is_absolute_path(argv[i]) || !prefix)2381argv_array_push(&paths, argv[i]);2382else2383argv_array_push(&paths,mkpath("%s/%s", prefix, argv[i]));2384}23852386am_setup(&state, patch_format, paths.argv, keep_cr);23872388argv_array_clear(&paths);2389}23902391switch(resume) {2392case RESUME_FALSE:2393am_run(&state,0);2394break;2395case RESUME_APPLY:2396am_run(&state,1);2397break;2398case RESUME_RESOLVED:2399am_resolve(&state);2400break;2401case RESUME_SKIP:2402am_skip(&state);2403break;2404case RESUME_ABORT:2405am_abort(&state);2406break;2407case RESUME_QUIT:2408am_rerere_clear();2409am_destroy(&state);2410break;2411case RESUME_SHOW_PATCH:2412 ret =show_patch(&state);2413break;2414default:2415BUG("invalid resume value");2416}24172418am_state_release(&state);24192420return ret;2421}