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; 321returnerror_errno(_("could not open '%s' for reading"), 322 filename); 323} 324strbuf_read(&buf, fd,0); 325close(fd); 326if(parse_key_value_squoted(buf.buf, &kv)) 327goto finish; 328 329if(kv.nr !=3|| 330strcmp(kv.items[0].string,"GIT_AUTHOR_NAME") || 331strcmp(kv.items[1].string,"GIT_AUTHOR_EMAIL") || 332strcmp(kv.items[2].string,"GIT_AUTHOR_DATE")) 333goto finish; 334 state->author_name = kv.items[0].util; 335 state->author_email = kv.items[1].util; 336 state->author_date = kv.items[2].util; 337 retval =0; 338finish: 339string_list_clear(&kv, !!retval); 340strbuf_release(&buf); 341return retval; 342} 343 344/** 345 * Saves state->author_name, state->author_email and state->author_date in the 346 * state directory's "author-script" file. 347 */ 348static voidwrite_author_script(const struct am_state *state) 349{ 350struct strbuf sb = STRBUF_INIT; 351 352strbuf_addstr(&sb,"GIT_AUTHOR_NAME="); 353sq_quote_buf(&sb, state->author_name); 354strbuf_addch(&sb,'\n'); 355 356strbuf_addstr(&sb,"GIT_AUTHOR_EMAIL="); 357sq_quote_buf(&sb, state->author_email); 358strbuf_addch(&sb,'\n'); 359 360strbuf_addstr(&sb,"GIT_AUTHOR_DATE="); 361sq_quote_buf(&sb, state->author_date); 362strbuf_addch(&sb,'\n'); 363 364write_state_text(state,"author-script", sb.buf); 365 366strbuf_release(&sb); 367} 368 369/** 370 * Reads the commit message from the state directory's "final-commit" file, 371 * setting state->msg to its contents and state->msg_len to the length of its 372 * contents in bytes. 373 * 374 * Returns 0 on success, -1 if the file does not exist. 375 */ 376static intread_commit_msg(struct am_state *state) 377{ 378struct strbuf sb = STRBUF_INIT; 379 380assert(!state->msg); 381 382if(read_state_file(&sb, state,"final-commit",0) <0) { 383strbuf_release(&sb); 384return-1; 385} 386 387 state->msg =strbuf_detach(&sb, &state->msg_len); 388return0; 389} 390 391/** 392 * Saves state->msg in the state directory's "final-commit" file. 393 */ 394static voidwrite_commit_msg(const struct am_state *state) 395{ 396const char*filename =am_path(state,"final-commit"); 397write_file_buf(filename, state->msg, state->msg_len); 398} 399 400/** 401 * Loads state from disk. 402 */ 403static voidam_load(struct am_state *state) 404{ 405struct strbuf sb = STRBUF_INIT; 406 407if(read_state_file(&sb, state,"next",1) <0) 408BUG("state file 'next' does not exist"); 409 state->cur =strtol(sb.buf, NULL,10); 410 411if(read_state_file(&sb, state,"last",1) <0) 412BUG("state file 'last' does not exist"); 413 state->last =strtol(sb.buf, NULL,10); 414 415if(read_author_script(state) <0) 416die(_("could not parse author script")); 417 418read_commit_msg(state); 419 420if(read_state_file(&sb, state,"original-commit",1) <0) 421oidclr(&state->orig_commit); 422else if(get_oid_hex(sb.buf, &state->orig_commit) <0) 423die(_("could not parse%s"),am_path(state,"original-commit")); 424 425read_state_file(&sb, state,"threeway",1); 426 state->threeway = !strcmp(sb.buf,"t"); 427 428read_state_file(&sb, state,"quiet",1); 429 state->quiet = !strcmp(sb.buf,"t"); 430 431read_state_file(&sb, state,"sign",1); 432 state->signoff = !strcmp(sb.buf,"t"); 433 434read_state_file(&sb, state,"utf8",1); 435 state->utf8 = !strcmp(sb.buf,"t"); 436 437if(file_exists(am_path(state,"rerere-autoupdate"))) { 438read_state_file(&sb, state,"rerere-autoupdate",1); 439 state->allow_rerere_autoupdate =strcmp(sb.buf,"t") ? 440 RERERE_NOAUTOUPDATE : RERERE_AUTOUPDATE; 441}else{ 442 state->allow_rerere_autoupdate =0; 443} 444 445read_state_file(&sb, state,"keep",1); 446if(!strcmp(sb.buf,"t")) 447 state->keep = KEEP_TRUE; 448else if(!strcmp(sb.buf,"b")) 449 state->keep = KEEP_NON_PATCH; 450else 451 state->keep = KEEP_FALSE; 452 453read_state_file(&sb, state,"messageid",1); 454 state->message_id = !strcmp(sb.buf,"t"); 455 456read_state_file(&sb, state,"scissors",1); 457if(!strcmp(sb.buf,"t")) 458 state->scissors = SCISSORS_TRUE; 459else if(!strcmp(sb.buf,"f")) 460 state->scissors = SCISSORS_FALSE; 461else 462 state->scissors = SCISSORS_UNSET; 463 464read_state_file(&sb, state,"apply-opt",1); 465argv_array_clear(&state->git_apply_opts); 466if(sq_dequote_to_argv_array(sb.buf, &state->git_apply_opts) <0) 467die(_("could not parse%s"),am_path(state,"apply-opt")); 468 469 state->rebasing = !!file_exists(am_path(state,"rebasing")); 470 471strbuf_release(&sb); 472} 473 474/** 475 * Removes the am_state directory, forcefully terminating the current am 476 * session. 477 */ 478static voidam_destroy(const struct am_state *state) 479{ 480struct strbuf sb = STRBUF_INIT; 481 482strbuf_addstr(&sb, state->dir); 483remove_dir_recursively(&sb,0); 484strbuf_release(&sb); 485} 486 487/** 488 * Runs applypatch-msg hook. Returns its exit code. 489 */ 490static intrun_applypatch_msg_hook(struct am_state *state) 491{ 492int ret; 493 494assert(state->msg); 495 ret =run_hook_le(NULL,"applypatch-msg",am_path(state,"final-commit"), NULL); 496 497if(!ret) { 498FREE_AND_NULL(state->msg); 499if(read_commit_msg(state) <0) 500die(_("'%s' was deleted by the applypatch-msg hook"), 501am_path(state,"final-commit")); 502} 503 504return ret; 505} 506 507/** 508 * Runs post-rewrite hook. Returns it exit code. 509 */ 510static intrun_post_rewrite_hook(const struct am_state *state) 511{ 512struct child_process cp = CHILD_PROCESS_INIT; 513const char*hook =find_hook("post-rewrite"); 514int ret; 515 516if(!hook) 517return0; 518 519argv_array_push(&cp.args, hook); 520argv_array_push(&cp.args,"rebase"); 521 522 cp.in =xopen(am_path(state,"rewritten"), O_RDONLY); 523 cp.stdout_to_stderr =1; 524 525 ret =run_command(&cp); 526 527close(cp.in); 528return ret; 529} 530 531/** 532 * Reads the state directory's "rewritten" file, and copies notes from the old 533 * commits listed in the file to their rewritten commits. 534 * 535 * Returns 0 on success, -1 on failure. 536 */ 537static intcopy_notes_for_rebase(const struct am_state *state) 538{ 539struct notes_rewrite_cfg *c; 540struct strbuf sb = STRBUF_INIT; 541const char*invalid_line =_("Malformed input line: '%s'."); 542const char*msg ="Notes added by 'git rebase'"; 543FILE*fp; 544int ret =0; 545 546assert(state->rebasing); 547 548 c =init_copy_notes_for_rewrite("rebase"); 549if(!c) 550return0; 551 552 fp =xfopen(am_path(state,"rewritten"),"r"); 553 554while(!strbuf_getline_lf(&sb, fp)) { 555struct object_id from_obj, to_obj; 556 557if(sb.len != GIT_SHA1_HEXSZ *2+1) { 558 ret =error(invalid_line, sb.buf); 559goto finish; 560} 561 562if(get_oid_hex(sb.buf, &from_obj)) { 563 ret =error(invalid_line, sb.buf); 564goto finish; 565} 566 567if(sb.buf[GIT_SHA1_HEXSZ] !=' ') { 568 ret =error(invalid_line, sb.buf); 569goto finish; 570} 571 572if(get_oid_hex(sb.buf + GIT_SHA1_HEXSZ +1, &to_obj)) { 573 ret =error(invalid_line, sb.buf); 574goto finish; 575} 576 577if(copy_note_for_rewrite(c, &from_obj, &to_obj)) 578 ret =error(_("Failed to copy notes from '%s' to '%s'"), 579oid_to_hex(&from_obj),oid_to_hex(&to_obj)); 580} 581 582finish: 583finish_copy_notes_for_rewrite(c, msg); 584fclose(fp); 585strbuf_release(&sb); 586return ret; 587} 588 589/** 590 * Determines if the file looks like a piece of RFC2822 mail by grabbing all 591 * non-indented lines and checking if they look like they begin with valid 592 * header field names. 593 * 594 * Returns 1 if the file looks like a piece of mail, 0 otherwise. 595 */ 596static intis_mail(FILE*fp) 597{ 598const char*header_regex ="^[!-9;-~]+:"; 599struct strbuf sb = STRBUF_INIT; 600 regex_t regex; 601int ret =1; 602 603if(fseek(fp,0L, SEEK_SET)) 604die_errno(_("fseek failed")); 605 606if(regcomp(®ex, header_regex, REG_NOSUB | REG_EXTENDED)) 607die("invalid pattern:%s", header_regex); 608 609while(!strbuf_getline(&sb, fp)) { 610if(!sb.len) 611break;/* End of header */ 612 613/* Ignore indented folded lines */ 614if(*sb.buf =='\t'|| *sb.buf ==' ') 615continue; 616 617/* It's a header if it matches header_regex */ 618if(regexec(®ex, sb.buf,0, NULL,0)) { 619 ret =0; 620goto done; 621} 622} 623 624done: 625regfree(®ex); 626strbuf_release(&sb); 627return ret; 628} 629 630/** 631 * Attempts to detect the patch_format of the patches contained in `paths`, 632 * returning the PATCH_FORMAT_* enum value. Returns PATCH_FORMAT_UNKNOWN if 633 * detection fails. 634 */ 635static intdetect_patch_format(const char**paths) 636{ 637enum patch_format ret = PATCH_FORMAT_UNKNOWN; 638struct strbuf l1 = STRBUF_INIT; 639struct strbuf l2 = STRBUF_INIT; 640struct strbuf l3 = STRBUF_INIT; 641FILE*fp; 642 643/* 644 * We default to mbox format if input is from stdin and for directories 645 */ 646if(!*paths || !strcmp(*paths,"-") ||is_directory(*paths)) 647return PATCH_FORMAT_MBOX; 648 649/* 650 * Otherwise, check the first few lines of the first patch, starting 651 * from the first non-blank line, to try to detect its format. 652 */ 653 654 fp =xfopen(*paths,"r"); 655 656while(!strbuf_getline(&l1, fp)) { 657if(l1.len) 658break; 659} 660 661if(starts_with(l1.buf,"From ") ||starts_with(l1.buf,"From: ")) { 662 ret = PATCH_FORMAT_MBOX; 663goto done; 664} 665 666if(starts_with(l1.buf,"# This series applies on GIT commit")) { 667 ret = PATCH_FORMAT_STGIT_SERIES; 668goto done; 669} 670 671if(!strcmp(l1.buf,"# HG changeset patch")) { 672 ret = PATCH_FORMAT_HG; 673goto done; 674} 675 676strbuf_getline(&l2, fp); 677strbuf_getline(&l3, fp); 678 679/* 680 * If the second line is empty and the third is a From, Author or Date 681 * entry, this is likely an StGit patch. 682 */ 683if(l1.len && !l2.len && 684(starts_with(l3.buf,"From:") || 685starts_with(l3.buf,"Author:") || 686starts_with(l3.buf,"Date:"))) { 687 ret = PATCH_FORMAT_STGIT; 688goto done; 689} 690 691if(l1.len &&is_mail(fp)) { 692 ret = PATCH_FORMAT_MBOX; 693goto done; 694} 695 696done: 697fclose(fp); 698strbuf_release(&l1); 699strbuf_release(&l2); 700strbuf_release(&l3); 701return ret; 702} 703 704/** 705 * Splits out individual email patches from `paths`, where each path is either 706 * a mbox file or a Maildir. Returns 0 on success, -1 on failure. 707 */ 708static intsplit_mail_mbox(struct am_state *state,const char**paths, 709int keep_cr,int mboxrd) 710{ 711struct child_process cp = CHILD_PROCESS_INIT; 712struct strbuf last = STRBUF_INIT; 713int ret; 714 715 cp.git_cmd =1; 716argv_array_push(&cp.args,"mailsplit"); 717argv_array_pushf(&cp.args,"-d%d", state->prec); 718argv_array_pushf(&cp.args,"-o%s", state->dir); 719argv_array_push(&cp.args,"-b"); 720if(keep_cr) 721argv_array_push(&cp.args,"--keep-cr"); 722if(mboxrd) 723argv_array_push(&cp.args,"--mboxrd"); 724argv_array_push(&cp.args,"--"); 725argv_array_pushv(&cp.args, paths); 726 727 ret =capture_command(&cp, &last,8); 728if(ret) 729goto exit; 730 731 state->cur =1; 732 state->last =strtol(last.buf, NULL,10); 733 734exit: 735strbuf_release(&last); 736return ret ? -1:0; 737} 738 739/** 740 * Callback signature for split_mail_conv(). The foreign patch should be 741 * read from `in`, and the converted patch (in RFC2822 mail format) should be 742 * written to `out`. Return 0 on success, or -1 on failure. 743 */ 744typedefint(*mail_conv_fn)(FILE*out,FILE*in,int keep_cr); 745 746/** 747 * Calls `fn` for each file in `paths` to convert the foreign patch to the 748 * RFC2822 mail format suitable for parsing with git-mailinfo. 749 * 750 * Returns 0 on success, -1 on failure. 751 */ 752static intsplit_mail_conv(mail_conv_fn fn,struct am_state *state, 753const char**paths,int keep_cr) 754{ 755static const char*stdin_only[] = {"-", NULL}; 756int i; 757 758if(!*paths) 759 paths = stdin_only; 760 761for(i =0; *paths; paths++, i++) { 762FILE*in, *out; 763const char*mail; 764int ret; 765 766if(!strcmp(*paths,"-")) 767 in = stdin; 768else 769 in =fopen(*paths,"r"); 770 771if(!in) 772returnerror_errno(_("could not open '%s' for reading"), 773*paths); 774 775 mail =mkpath("%s/%0*d", state->dir, state->prec, i +1); 776 777 out =fopen(mail,"w"); 778if(!out) { 779if(in != stdin) 780fclose(in); 781returnerror_errno(_("could not open '%s' for writing"), 782 mail); 783} 784 785 ret =fn(out, in, keep_cr); 786 787fclose(out); 788if(in != stdin) 789fclose(in); 790 791if(ret) 792returnerror(_("could not parse patch '%s'"), *paths); 793} 794 795 state->cur =1; 796 state->last = i; 797return0; 798} 799 800/** 801 * A split_mail_conv() callback that converts an StGit patch to an RFC2822 802 * message suitable for parsing with git-mailinfo. 803 */ 804static intstgit_patch_to_mail(FILE*out,FILE*in,int keep_cr) 805{ 806struct strbuf sb = STRBUF_INIT; 807int subject_printed =0; 808 809while(!strbuf_getline_lf(&sb, in)) { 810const char*str; 811 812if(str_isspace(sb.buf)) 813continue; 814else if(skip_prefix(sb.buf,"Author:", &str)) 815fprintf(out,"From:%s\n", str); 816else if(starts_with(sb.buf,"From") ||starts_with(sb.buf,"Date")) 817fprintf(out,"%s\n", sb.buf); 818else if(!subject_printed) { 819fprintf(out,"Subject:%s\n", sb.buf); 820 subject_printed =1; 821}else{ 822fprintf(out,"\n%s\n", sb.buf); 823break; 824} 825} 826 827strbuf_reset(&sb); 828while(strbuf_fread(&sb,8192, in) >0) { 829fwrite(sb.buf,1, sb.len, out); 830strbuf_reset(&sb); 831} 832 833strbuf_release(&sb); 834return0; 835} 836 837/** 838 * This function only supports a single StGit series file in `paths`. 839 * 840 * Given an StGit series file, converts the StGit patches in the series into 841 * RFC2822 messages suitable for parsing with git-mailinfo, and queues them in 842 * the state directory. 843 * 844 * Returns 0 on success, -1 on failure. 845 */ 846static intsplit_mail_stgit_series(struct am_state *state,const char**paths, 847int keep_cr) 848{ 849const char*series_dir; 850char*series_dir_buf; 851FILE*fp; 852struct argv_array patches = ARGV_ARRAY_INIT; 853struct strbuf sb = STRBUF_INIT; 854int ret; 855 856if(!paths[0] || paths[1]) 857returnerror(_("Only one StGIT patch series can be applied at once")); 858 859 series_dir_buf =xstrdup(*paths); 860 series_dir =dirname(series_dir_buf); 861 862 fp =fopen(*paths,"r"); 863if(!fp) 864returnerror_errno(_("could not open '%s' for reading"), *paths); 865 866while(!strbuf_getline_lf(&sb, fp)) { 867if(*sb.buf =='#') 868continue;/* skip comment lines */ 869 870argv_array_push(&patches,mkpath("%s/%s", series_dir, sb.buf)); 871} 872 873fclose(fp); 874strbuf_release(&sb); 875free(series_dir_buf); 876 877 ret =split_mail_conv(stgit_patch_to_mail, state, patches.argv, keep_cr); 878 879argv_array_clear(&patches); 880return ret; 881} 882 883/** 884 * A split_patches_conv() callback that converts a mercurial patch to a RFC2822 885 * message suitable for parsing with git-mailinfo. 886 */ 887static inthg_patch_to_mail(FILE*out,FILE*in,int keep_cr) 888{ 889struct strbuf sb = STRBUF_INIT; 890int rc =0; 891 892while(!strbuf_getline_lf(&sb, in)) { 893const char*str; 894 895if(skip_prefix(sb.buf,"# User ", &str)) 896fprintf(out,"From:%s\n", str); 897else if(skip_prefix(sb.buf,"# Date ", &str)) { 898 timestamp_t timestamp; 899long tz, tz2; 900char*end; 901 902 errno =0; 903 timestamp =parse_timestamp(str, &end,10); 904if(errno) { 905 rc =error(_("invalid timestamp")); 906goto exit; 907} 908 909if(!skip_prefix(end," ", &str)) { 910 rc =error(_("invalid Date line")); 911goto exit; 912} 913 914 errno =0; 915 tz =strtol(str, &end,10); 916if(errno) { 917 rc =error(_("invalid timezone offset")); 918goto exit; 919} 920 921if(*end) { 922 rc =error(_("invalid Date line")); 923goto exit; 924} 925 926/* 927 * mercurial's timezone is in seconds west of UTC, 928 * however git's timezone is in hours + minutes east of 929 * UTC. Convert it. 930 */ 931 tz2 =labs(tz) /3600*100+labs(tz) %3600/60; 932if(tz >0) 933 tz2 = -tz2; 934 935fprintf(out,"Date:%s\n",show_date(timestamp, tz2,DATE_MODE(RFC2822))); 936}else if(starts_with(sb.buf,"# ")) { 937continue; 938}else{ 939fprintf(out,"\n%s\n", sb.buf); 940break; 941} 942} 943 944strbuf_reset(&sb); 945while(strbuf_fread(&sb,8192, in) >0) { 946fwrite(sb.buf,1, sb.len, out); 947strbuf_reset(&sb); 948} 949exit: 950strbuf_release(&sb); 951return rc; 952} 953 954/** 955 * Splits a list of files/directories into individual email patches. Each path 956 * in `paths` must be a file/directory that is formatted according to 957 * `patch_format`. 958 * 959 * Once split out, the individual email patches will be stored in the state 960 * directory, with each patch's filename being its index, padded to state->prec 961 * digits. 962 * 963 * state->cur will be set to the index of the first mail, and state->last will 964 * be set to the index of the last mail. 965 * 966 * Set keep_cr to 0 to convert all lines ending with \r\n to end with \n, 1 967 * to disable this behavior, -1 to use the default configured setting. 968 * 969 * Returns 0 on success, -1 on failure. 970 */ 971static intsplit_mail(struct am_state *state,enum patch_format patch_format, 972const char**paths,int keep_cr) 973{ 974if(keep_cr <0) { 975 keep_cr =0; 976git_config_get_bool("am.keepcr", &keep_cr); 977} 978 979switch(patch_format) { 980case PATCH_FORMAT_MBOX: 981returnsplit_mail_mbox(state, paths, keep_cr,0); 982case PATCH_FORMAT_STGIT: 983returnsplit_mail_conv(stgit_patch_to_mail, state, paths, keep_cr); 984case PATCH_FORMAT_STGIT_SERIES: 985returnsplit_mail_stgit_series(state, paths, keep_cr); 986case PATCH_FORMAT_HG: 987returnsplit_mail_conv(hg_patch_to_mail, state, paths, keep_cr); 988case PATCH_FORMAT_MBOXRD: 989returnsplit_mail_mbox(state, paths, keep_cr,1); 990default: 991BUG("invalid patch_format"); 992} 993return-1; 994} 995 996/** 997 * Setup a new am session for applying patches 998 */ 999static voidam_setup(struct am_state *state,enum patch_format patch_format,1000const char**paths,int keep_cr)1001{1002struct object_id curr_head;1003const char*str;1004struct strbuf sb = STRBUF_INIT;10051006if(!patch_format)1007 patch_format =detect_patch_format(paths);10081009if(!patch_format) {1010fprintf_ln(stderr,_("Patch format detection failed."));1011exit(128);1012}10131014if(mkdir(state->dir,0777) <0&& errno != EEXIST)1015die_errno(_("failed to create directory '%s'"), state->dir);1016delete_ref(NULL,"REBASE_HEAD", NULL, REF_NO_DEREF);10171018if(split_mail(state, patch_format, paths, keep_cr) <0) {1019am_destroy(state);1020die(_("Failed to split patches."));1021}10221023if(state->rebasing)1024 state->threeway =1;10251026write_state_bool(state,"threeway", state->threeway);1027write_state_bool(state,"quiet", state->quiet);1028write_state_bool(state,"sign", state->signoff);1029write_state_bool(state,"utf8", state->utf8);10301031if(state->allow_rerere_autoupdate)1032write_state_bool(state,"rerere-autoupdate",1033 state->allow_rerere_autoupdate == RERERE_AUTOUPDATE);10341035switch(state->keep) {1036case KEEP_FALSE:1037 str ="f";1038break;1039case KEEP_TRUE:1040 str ="t";1041break;1042case KEEP_NON_PATCH:1043 str ="b";1044break;1045default:1046BUG("invalid value for state->keep");1047}10481049write_state_text(state,"keep", str);1050write_state_bool(state,"messageid", state->message_id);10511052switch(state->scissors) {1053case SCISSORS_UNSET:1054 str ="";1055break;1056case SCISSORS_FALSE:1057 str ="f";1058break;1059case SCISSORS_TRUE:1060 str ="t";1061break;1062default:1063BUG("invalid value for state->scissors");1064}1065write_state_text(state,"scissors", str);10661067sq_quote_argv(&sb, state->git_apply_opts.argv);1068write_state_text(state,"apply-opt", sb.buf);10691070if(state->rebasing)1071write_state_text(state,"rebasing","");1072else1073write_state_text(state,"applying","");10741075if(!get_oid("HEAD", &curr_head)) {1076write_state_text(state,"abort-safety",oid_to_hex(&curr_head));1077if(!state->rebasing)1078update_ref("am","ORIG_HEAD", &curr_head, NULL,0,1079 UPDATE_REFS_DIE_ON_ERR);1080}else{1081write_state_text(state,"abort-safety","");1082if(!state->rebasing)1083delete_ref(NULL,"ORIG_HEAD", NULL,0);1084}10851086/*1087 * NOTE: Since the "next" and "last" files determine if an am_state1088 * session is in progress, they should be written last.1089 */10901091write_state_count(state,"next", state->cur);1092write_state_count(state,"last", state->last);10931094strbuf_release(&sb);1095}10961097/**1098 * Increments the patch pointer, and cleans am_state for the application of the1099 * next patch.1100 */1101static voidam_next(struct am_state *state)1102{1103struct object_id head;11041105FREE_AND_NULL(state->author_name);1106FREE_AND_NULL(state->author_email);1107FREE_AND_NULL(state->author_date);1108FREE_AND_NULL(state->msg);1109 state->msg_len =0;11101111unlink(am_path(state,"author-script"));1112unlink(am_path(state,"final-commit"));11131114oidclr(&state->orig_commit);1115unlink(am_path(state,"original-commit"));1116delete_ref(NULL,"REBASE_HEAD", NULL, REF_NO_DEREF);11171118if(!get_oid("HEAD", &head))1119write_state_text(state,"abort-safety",oid_to_hex(&head));1120else1121write_state_text(state,"abort-safety","");11221123 state->cur++;1124write_state_count(state,"next", state->cur);1125}11261127/**1128 * Returns the filename of the current patch email.1129 */1130static const char*msgnum(const struct am_state *state)1131{1132static struct strbuf sb = STRBUF_INIT;11331134strbuf_reset(&sb);1135strbuf_addf(&sb,"%0*d", state->prec, state->cur);11361137return sb.buf;1138}11391140/**1141 * Refresh and write index.1142 */1143static voidrefresh_and_write_cache(void)1144{1145struct lock_file lock_file = LOCK_INIT;11461147hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);1148refresh_cache(REFRESH_QUIET);1149if(write_locked_index(&the_index, &lock_file, COMMIT_LOCK))1150die(_("unable to write index file"));1151}11521153/**1154 * Dies with a user-friendly message on how to proceed after resolving the1155 * problem. This message can be overridden with state->resolvemsg.1156 */1157static void NORETURN die_user_resolve(const struct am_state *state)1158{1159if(state->resolvemsg) {1160printf_ln("%s", state->resolvemsg);1161}else{1162const char*cmdline = state->interactive ?"git am -i":"git am";11631164printf_ln(_("When you have resolved this problem, run\"%s--continue\"."), cmdline);1165printf_ln(_("If you prefer to skip this patch, run\"%s--skip\"instead."), cmdline);1166printf_ln(_("To restore the original branch and stop patching, run\"%s--abort\"."), cmdline);1167}11681169exit(128);1170}11711172/**1173 * Appends signoff to the "msg" field of the am_state.1174 */1175static voidam_append_signoff(struct am_state *state)1176{1177struct strbuf sb = STRBUF_INIT;11781179strbuf_attach(&sb, state->msg, state->msg_len, state->msg_len);1180append_signoff(&sb,0,0);1181 state->msg =strbuf_detach(&sb, &state->msg_len);1182}11831184/**1185 * Parses `mail` using git-mailinfo, extracting its patch and authorship info.1186 * state->msg will be set to the patch message. state->author_name,1187 * state->author_email and state->author_date will be set to the patch author's1188 * name, email and date respectively. The patch body will be written to the1189 * state directory's "patch" file.1190 *1191 * Returns 1 if the patch should be skipped, 0 otherwise.1192 */1193static intparse_mail(struct am_state *state,const char*mail)1194{1195FILE*fp;1196struct strbuf sb = STRBUF_INIT;1197struct strbuf msg = STRBUF_INIT;1198struct strbuf author_name = STRBUF_INIT;1199struct strbuf author_date = STRBUF_INIT;1200struct strbuf author_email = STRBUF_INIT;1201int ret =0;1202struct mailinfo mi;12031204setup_mailinfo(&mi);12051206if(state->utf8)1207 mi.metainfo_charset =get_commit_output_encoding();1208else1209 mi.metainfo_charset = NULL;12101211switch(state->keep) {1212case KEEP_FALSE:1213break;1214case KEEP_TRUE:1215 mi.keep_subject =1;1216break;1217case KEEP_NON_PATCH:1218 mi.keep_non_patch_brackets_in_subject =1;1219break;1220default:1221BUG("invalid value for state->keep");1222}12231224if(state->message_id)1225 mi.add_message_id =1;12261227switch(state->scissors) {1228case SCISSORS_UNSET:1229break;1230case SCISSORS_FALSE:1231 mi.use_scissors =0;1232break;1233case SCISSORS_TRUE:1234 mi.use_scissors =1;1235break;1236default:1237BUG("invalid value for state->scissors");1238}12391240 mi.input =xfopen(mail,"r");1241 mi.output =xfopen(am_path(state,"info"),"w");1242if(mailinfo(&mi,am_path(state,"msg"),am_path(state,"patch")))1243die("could not parse patch");12441245fclose(mi.input);1246fclose(mi.output);12471248if(mi.format_flowed)1249warning(_("Patch sent with format=flowed; "1250"space at the end of lines might be lost."));12511252/* Extract message and author information */1253 fp =xfopen(am_path(state,"info"),"r");1254while(!strbuf_getline_lf(&sb, fp)) {1255const char*x;12561257if(skip_prefix(sb.buf,"Subject: ", &x)) {1258if(msg.len)1259strbuf_addch(&msg,'\n');1260strbuf_addstr(&msg, x);1261}else if(skip_prefix(sb.buf,"Author: ", &x))1262strbuf_addstr(&author_name, x);1263else if(skip_prefix(sb.buf,"Email: ", &x))1264strbuf_addstr(&author_email, x);1265else if(skip_prefix(sb.buf,"Date: ", &x))1266strbuf_addstr(&author_date, x);1267}1268fclose(fp);12691270/* Skip pine's internal folder data */1271if(!strcmp(author_name.buf,"Mail System Internal Data")) {1272 ret =1;1273goto finish;1274}12751276if(is_empty_file(am_path(state,"patch"))) {1277printf_ln(_("Patch is empty."));1278die_user_resolve(state);1279}12801281strbuf_addstr(&msg,"\n\n");1282strbuf_addbuf(&msg, &mi.log_message);1283strbuf_stripspace(&msg,0);12841285assert(!state->author_name);1286 state->author_name =strbuf_detach(&author_name, NULL);12871288assert(!state->author_email);1289 state->author_email =strbuf_detach(&author_email, NULL);12901291assert(!state->author_date);1292 state->author_date =strbuf_detach(&author_date, NULL);12931294assert(!state->msg);1295 state->msg =strbuf_detach(&msg, &state->msg_len);12961297finish:1298strbuf_release(&msg);1299strbuf_release(&author_date);1300strbuf_release(&author_email);1301strbuf_release(&author_name);1302strbuf_release(&sb);1303clear_mailinfo(&mi);1304return ret;1305}13061307/**1308 * Sets commit_id to the commit hash where the mail was generated from.1309 * Returns 0 on success, -1 on failure.1310 */1311static intget_mail_commit_oid(struct object_id *commit_id,const char*mail)1312{1313struct strbuf sb = STRBUF_INIT;1314FILE*fp =xfopen(mail,"r");1315const char*x;1316int ret =0;13171318if(strbuf_getline_lf(&sb, fp) ||1319!skip_prefix(sb.buf,"From ", &x) ||1320get_oid_hex(x, commit_id) <0)1321 ret = -1;13221323strbuf_release(&sb);1324fclose(fp);1325return ret;1326}13271328/**1329 * Sets state->msg, state->author_name, state->author_email, state->author_date1330 * to the commit's respective info.1331 */1332static voidget_commit_info(struct am_state *state,struct commit *commit)1333{1334const char*buffer, *ident_line, *msg;1335size_t ident_len;1336struct ident_split id;13371338 buffer =logmsg_reencode(commit, NULL,get_commit_output_encoding());13391340 ident_line =find_commit_header(buffer,"author", &ident_len);13411342if(split_ident_line(&id, ident_line, ident_len) <0)1343die(_("invalid ident line: %.*s"), (int)ident_len, ident_line);13441345assert(!state->author_name);1346if(id.name_begin)1347 state->author_name =1348xmemdupz(id.name_begin, id.name_end - id.name_begin);1349else1350 state->author_name =xstrdup("");13511352assert(!state->author_email);1353if(id.mail_begin)1354 state->author_email =1355xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);1356else1357 state->author_email =xstrdup("");13581359assert(!state->author_date);1360 state->author_date =xstrdup(show_ident_date(&id,DATE_MODE(NORMAL)));13611362assert(!state->msg);1363 msg =strstr(buffer,"\n\n");1364if(!msg)1365die(_("unable to parse commit%s"),oid_to_hex(&commit->object.oid));1366 state->msg =xstrdup(msg +2);1367 state->msg_len =strlen(state->msg);1368unuse_commit_buffer(commit, buffer);1369}13701371/**1372 * Writes `commit` as a patch to the state directory's "patch" file.1373 */1374static voidwrite_commit_patch(const struct am_state *state,struct commit *commit)1375{1376struct rev_info rev_info;1377FILE*fp;13781379 fp =xfopen(am_path(state,"patch"),"w");1380init_revisions(&rev_info, NULL);1381 rev_info.diff =1;1382 rev_info.abbrev =0;1383 rev_info.disable_stdin =1;1384 rev_info.show_root_diff =1;1385 rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;1386 rev_info.no_commit_id =1;1387 rev_info.diffopt.flags.binary =1;1388 rev_info.diffopt.flags.full_index =1;1389 rev_info.diffopt.use_color =0;1390 rev_info.diffopt.file = fp;1391 rev_info.diffopt.close_file =1;1392add_pending_object(&rev_info, &commit->object,"");1393diff_setup_done(&rev_info.diffopt);1394log_tree_commit(&rev_info, commit);1395}13961397/**1398 * Writes the diff of the index against HEAD as a patch to the state1399 * directory's "patch" file.1400 */1401static voidwrite_index_patch(const struct am_state *state)1402{1403struct tree *tree;1404struct object_id head;1405struct rev_info rev_info;1406FILE*fp;14071408if(!get_oid_tree("HEAD", &head))1409 tree =lookup_tree(the_repository, &head);1410else1411 tree =lookup_tree(the_repository,1412 the_repository->hash_algo->empty_tree);14131414 fp =xfopen(am_path(state,"patch"),"w");1415init_revisions(&rev_info, NULL);1416 rev_info.diff =1;1417 rev_info.disable_stdin =1;1418 rev_info.no_commit_id =1;1419 rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;1420 rev_info.diffopt.use_color =0;1421 rev_info.diffopt.file = fp;1422 rev_info.diffopt.close_file =1;1423add_pending_object(&rev_info, &tree->object,"");1424diff_setup_done(&rev_info.diffopt);1425run_diff_index(&rev_info,1);1426}14271428/**1429 * Like parse_mail(), but parses the mail by looking up its commit ID1430 * directly. This is used in --rebasing mode to bypass git-mailinfo's munging1431 * of patches.1432 *1433 * state->orig_commit will be set to the original commit ID.1434 *1435 * Will always return 0 as the patch should never be skipped.1436 */1437static intparse_mail_rebase(struct am_state *state,const char*mail)1438{1439struct commit *commit;1440struct object_id commit_oid;14411442if(get_mail_commit_oid(&commit_oid, mail) <0)1443die(_("could not parse%s"), mail);14441445 commit =lookup_commit_or_die(&commit_oid, mail);14461447get_commit_info(state, commit);14481449write_commit_patch(state, commit);14501451oidcpy(&state->orig_commit, &commit_oid);1452write_state_text(state,"original-commit",oid_to_hex(&commit_oid));1453update_ref("am","REBASE_HEAD", &commit_oid,1454 NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);14551456return0;1457}14581459/**1460 * Applies current patch with git-apply. Returns 0 on success, -1 otherwise. If1461 * `index_file` is not NULL, the patch will be applied to that index.1462 */1463static intrun_apply(const struct am_state *state,const char*index_file)1464{1465struct argv_array apply_paths = ARGV_ARRAY_INIT;1466struct argv_array apply_opts = ARGV_ARRAY_INIT;1467struct apply_state apply_state;1468int res, opts_left;1469int force_apply =0;1470int options =0;14711472if(init_apply_state(&apply_state, the_repository, NULL))1473BUG("init_apply_state() failed");14741475argv_array_push(&apply_opts,"apply");1476argv_array_pushv(&apply_opts, state->git_apply_opts.argv);14771478 opts_left =apply_parse_options(apply_opts.argc, apply_opts.argv,1479&apply_state, &force_apply, &options,1480 NULL);14811482if(opts_left !=0)1483die("unknown option passed through to git apply");14841485if(index_file) {1486 apply_state.index_file = index_file;1487 apply_state.cached =1;1488}else1489 apply_state.check_index =1;14901491/*1492 * If we are allowed to fall back on 3-way merge, don't give false1493 * errors during the initial attempt.1494 */1495if(state->threeway && !index_file)1496 apply_state.apply_verbosity = verbosity_silent;14971498if(check_apply_state(&apply_state, force_apply))1499BUG("check_apply_state() failed");15001501argv_array_push(&apply_paths,am_path(state,"patch"));15021503 res =apply_all_patches(&apply_state, apply_paths.argc, apply_paths.argv, options);15041505argv_array_clear(&apply_paths);1506argv_array_clear(&apply_opts);1507clear_apply_state(&apply_state);15081509if(res)1510return res;15111512if(index_file) {1513/* Reload index as apply_all_patches() will have modified it. */1514discard_cache();1515read_cache_from(index_file);1516}15171518return0;1519}15201521/**1522 * Builds an index that contains just the blobs needed for a 3way merge.1523 */1524static intbuild_fake_ancestor(const struct am_state *state,const char*index_file)1525{1526struct child_process cp = CHILD_PROCESS_INIT;15271528 cp.git_cmd =1;1529argv_array_push(&cp.args,"apply");1530argv_array_pushv(&cp.args, state->git_apply_opts.argv);1531argv_array_pushf(&cp.args,"--build-fake-ancestor=%s", index_file);1532argv_array_push(&cp.args,am_path(state,"patch"));15331534if(run_command(&cp))1535return-1;15361537return0;1538}15391540/**1541 * Attempt a threeway merge, using index_path as the temporary index.1542 */1543static intfall_back_threeway(const struct am_state *state,const char*index_path)1544{1545struct object_id orig_tree, their_tree, our_tree;1546const struct object_id *bases[1] = { &orig_tree };1547struct merge_options o;1548struct commit *result;1549char*their_tree_name;15501551if(get_oid("HEAD", &our_tree) <0)1552oidcpy(&our_tree, the_hash_algo->empty_tree);15531554if(build_fake_ancestor(state, index_path))1555returnerror("could not build fake ancestor");15561557discard_cache();1558read_cache_from(index_path);15591560if(write_index_as_tree(&orig_tree, &the_index, index_path,0, NULL))1561returnerror(_("Repository lacks necessary blobs to fall back on 3-way merge."));15621563say(state, stdout,_("Using index info to reconstruct a base tree..."));15641565if(!state->quiet) {1566/*1567 * List paths that needed 3-way fallback, so that the user can1568 * review them with extra care to spot mismerges.1569 */1570struct rev_info rev_info;1571const char*diff_filter_str ="--diff-filter=AM";15721573init_revisions(&rev_info, NULL);1574 rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;1575diff_opt_parse(&rev_info.diffopt, &diff_filter_str,1, rev_info.prefix);1576add_pending_oid(&rev_info,"HEAD", &our_tree,0);1577diff_setup_done(&rev_info.diffopt);1578run_diff_index(&rev_info,1);1579}15801581if(run_apply(state, index_path))1582returnerror(_("Did you hand edit your patch?\n"1583"It does not apply to blobs recorded in its index."));15841585if(write_index_as_tree(&their_tree, &the_index, index_path,0, NULL))1586returnerror("could not write tree");15871588say(state, stdout,_("Falling back to patching base and 3-way merge..."));15891590discard_cache();1591read_cache();15921593/*1594 * This is not so wrong. Depending on which base we picked, orig_tree1595 * may be wildly different from ours, but their_tree has the same set of1596 * wildly different changes in parts the patch did not touch, so1597 * recursive ends up canceling them, saying that we reverted all those1598 * changes.1599 */16001601init_merge_options(&o);16021603 o.branch1 ="HEAD";1604 their_tree_name =xstrfmt("%.*s",linelen(state->msg), state->msg);1605 o.branch2 = their_tree_name;1606 o.detect_directory_renames =0;16071608if(state->quiet)1609 o.verbosity =0;16101611if(merge_recursive_generic(&o, &our_tree, &their_tree,1, bases, &result)) {1612rerere(state->allow_rerere_autoupdate);1613free(their_tree_name);1614returnerror(_("Failed to merge in the changes."));1615}16161617free(their_tree_name);1618return0;1619}16201621/**1622 * Commits the current index with state->msg as the commit message and1623 * state->author_name, state->author_email and state->author_date as the author1624 * information.1625 */1626static voiddo_commit(const struct am_state *state)1627{1628struct object_id tree, parent, commit;1629const struct object_id *old_oid;1630struct commit_list *parents = NULL;1631const char*reflog_msg, *author;1632struct strbuf sb = STRBUF_INIT;16331634if(run_hook_le(NULL,"pre-applypatch", NULL))1635exit(1);16361637if(write_cache_as_tree(&tree,0, NULL))1638die(_("git write-tree failed to write a tree"));16391640if(!get_oid_commit("HEAD", &parent)) {1641 old_oid = &parent;1642commit_list_insert(lookup_commit(the_repository, &parent),1643&parents);1644}else{1645 old_oid = NULL;1646say(state, stderr,_("applying to an empty history"));1647}16481649 author =fmt_ident(state->author_name, state->author_email,1650 state->ignore_date ? NULL : state->author_date,1651 IDENT_STRICT);16521653if(state->committer_date_is_author_date)1654setenv("GIT_COMMITTER_DATE",1655 state->ignore_date ?"": state->author_date,1);16561657if(commit_tree(state->msg, state->msg_len, &tree, parents, &commit,1658 author, state->sign_commit))1659die(_("failed to write commit object"));16601661 reflog_msg =getenv("GIT_REFLOG_ACTION");1662if(!reflog_msg)1663 reflog_msg ="am";16641665strbuf_addf(&sb,"%s: %.*s", reflog_msg,linelen(state->msg),1666 state->msg);16671668update_ref(sb.buf,"HEAD", &commit, old_oid,0,1669 UPDATE_REFS_DIE_ON_ERR);16701671if(state->rebasing) {1672FILE*fp =xfopen(am_path(state,"rewritten"),"a");16731674assert(!is_null_oid(&state->orig_commit));1675fprintf(fp,"%s",oid_to_hex(&state->orig_commit));1676fprintf(fp,"%s\n",oid_to_hex(&commit));1677fclose(fp);1678}16791680run_hook_le(NULL,"post-applypatch", NULL);16811682strbuf_release(&sb);1683}16841685/**1686 * Validates the am_state for resuming -- the "msg" and authorship fields must1687 * be filled up.1688 */1689static voidvalidate_resume_state(const struct am_state *state)1690{1691if(!state->msg)1692die(_("cannot resume:%sdoes not exist."),1693am_path(state,"final-commit"));16941695if(!state->author_name || !state->author_email || !state->author_date)1696die(_("cannot resume:%sdoes not exist."),1697am_path(state,"author-script"));1698}16991700/**1701 * Interactively prompt the user on whether the current patch should be1702 * applied.1703 *1704 * Returns 0 if the user chooses to apply the patch, 1 if the user chooses to1705 * skip it.1706 */1707static intdo_interactive(struct am_state *state)1708{1709assert(state->msg);17101711if(!isatty(0))1712die(_("cannot be interactive without stdin connected to a terminal."));17131714for(;;) {1715const char*reply;17161717puts(_("Commit Body is:"));1718puts("--------------------------");1719printf("%s", state->msg);1720puts("--------------------------");17211722/*1723 * TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]1724 * in your translation. The program will only accept English1725 * input at this point.1726 */1727 reply =git_prompt(_("Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "), PROMPT_ECHO);17281729if(!reply) {1730continue;1731}else if(*reply =='y'|| *reply =='Y') {1732return0;1733}else if(*reply =='a'|| *reply =='A') {1734 state->interactive =0;1735return0;1736}else if(*reply =='n'|| *reply =='N') {1737return1;1738}else if(*reply =='e'|| *reply =='E') {1739struct strbuf msg = STRBUF_INIT;17401741if(!launch_editor(am_path(state,"final-commit"), &msg, NULL)) {1742free(state->msg);1743 state->msg =strbuf_detach(&msg, &state->msg_len);1744}1745strbuf_release(&msg);1746}else if(*reply =='v'|| *reply =='V') {1747const char*pager =git_pager(1);1748struct child_process cp = CHILD_PROCESS_INIT;17491750if(!pager)1751 pager ="cat";1752prepare_pager_args(&cp, pager);1753argv_array_push(&cp.args,am_path(state,"patch"));1754run_command(&cp);1755}1756}1757}17581759/**1760 * Applies all queued mail.1761 *1762 * If `resume` is true, we are "resuming". The "msg" and authorship fields, as1763 * well as the state directory's "patch" file is used as-is for applying the1764 * patch and committing it.1765 */1766static voidam_run(struct am_state *state,int resume)1767{1768const char*argv_gc_auto[] = {"gc","--auto", NULL};1769struct strbuf sb = STRBUF_INIT;17701771unlink(am_path(state,"dirtyindex"));17721773refresh_and_write_cache();17741775if(index_has_changes(&the_index, NULL, &sb)) {1776write_state_bool(state,"dirtyindex",1);1777die(_("Dirty index: cannot apply patches (dirty:%s)"), sb.buf);1778}17791780strbuf_release(&sb);17811782while(state->cur <= state->last) {1783const char*mail =am_path(state,msgnum(state));1784int apply_status;17851786reset_ident_date();17871788if(!file_exists(mail))1789goto next;17901791if(resume) {1792validate_resume_state(state);1793}else{1794int skip;17951796if(state->rebasing)1797 skip =parse_mail_rebase(state, mail);1798else1799 skip =parse_mail(state, mail);18001801if(skip)1802goto next;/* mail should be skipped */18031804if(state->signoff)1805am_append_signoff(state);18061807write_author_script(state);1808write_commit_msg(state);1809}18101811if(state->interactive &&do_interactive(state))1812goto next;18131814if(run_applypatch_msg_hook(state))1815exit(1);18161817say(state, stdout,_("Applying: %.*s"),linelen(state->msg), state->msg);18181819 apply_status =run_apply(state, NULL);18201821if(apply_status && state->threeway) {1822struct strbuf sb = STRBUF_INIT;18231824strbuf_addstr(&sb,am_path(state,"patch-merge-index"));1825 apply_status =fall_back_threeway(state, sb.buf);1826strbuf_release(&sb);18271828/*1829 * Applying the patch to an earlier tree and merging1830 * the result may have produced the same tree as ours.1831 */1832if(!apply_status &&1833!index_has_changes(&the_index, NULL, NULL)) {1834say(state, stdout,_("No changes -- Patch already applied."));1835goto next;1836}1837}18381839if(apply_status) {1840printf_ln(_("Patch failed at%s%.*s"),msgnum(state),1841linelen(state->msg), state->msg);18421843if(advice_amworkdir)1844advise(_("Use 'git am --show-current-patch' to see the failed patch"));18451846die_user_resolve(state);1847}18481849do_commit(state);18501851next:1852am_next(state);18531854if(resume)1855am_load(state);1856 resume =0;1857}18581859if(!is_empty_file(am_path(state,"rewritten"))) {1860assert(state->rebasing);1861copy_notes_for_rebase(state);1862run_post_rewrite_hook(state);1863}18641865/*1866 * In rebasing mode, it's up to the caller to take care of1867 * housekeeping.1868 */1869if(!state->rebasing) {1870am_destroy(state);1871close_all_packs(the_repository->objects);1872run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);1873}1874}18751876/**1877 * Resume the current am session after patch application failure. The user did1878 * all the hard work, and we do not have to do any patch application. Just1879 * trust and commit what the user has in the index and working tree.1880 */1881static voidam_resolve(struct am_state *state)1882{1883validate_resume_state(state);18841885say(state, stdout,_("Applying: %.*s"),linelen(state->msg), state->msg);18861887if(!index_has_changes(&the_index, NULL, NULL)) {1888printf_ln(_("No changes - did you forget to use 'git add'?\n"1889"If there is nothing left to stage, chances are that something else\n"1890"already introduced the same changes; you might want to skip this patch."));1891die_user_resolve(state);1892}18931894if(unmerged_cache()) {1895printf_ln(_("You still have unmerged paths in your index.\n"1896"You should 'git add' each file with resolved conflicts to mark them as such.\n"1897"You might run `git rm` on a file to accept\"deleted by them\"for it."));1898die_user_resolve(state);1899}19001901if(state->interactive) {1902write_index_patch(state);1903if(do_interactive(state))1904goto next;1905}19061907rerere(0);19081909do_commit(state);19101911next:1912am_next(state);1913am_load(state);1914am_run(state,0);1915}19161917/**1918 * Performs a checkout fast-forward from `head` to `remote`. If `reset` is1919 * true, any unmerged entries will be discarded. Returns 0 on success, -1 on1920 * failure.1921 */1922static intfast_forward_to(struct tree *head,struct tree *remote,int reset)1923{1924struct lock_file lock_file = LOCK_INIT;1925struct unpack_trees_options opts;1926struct tree_desc t[2];19271928if(parse_tree(head) ||parse_tree(remote))1929return-1;19301931hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);19321933refresh_cache(REFRESH_QUIET);19341935memset(&opts,0,sizeof(opts));1936 opts.head_idx =1;1937 opts.src_index = &the_index;1938 opts.dst_index = &the_index;1939 opts.update =1;1940 opts.merge =1;1941 opts.reset = reset;1942 opts.fn = twoway_merge;1943init_tree_desc(&t[0], head->buffer, head->size);1944init_tree_desc(&t[1], remote->buffer, remote->size);19451946if(unpack_trees(2, t, &opts)) {1947rollback_lock_file(&lock_file);1948return-1;1949}19501951if(write_locked_index(&the_index, &lock_file, COMMIT_LOCK))1952die(_("unable to write new index file"));19531954return0;1955}19561957/**1958 * Merges a tree into the index. The index's stat info will take precedence1959 * over the merged tree's. Returns 0 on success, -1 on failure.1960 */1961static intmerge_tree(struct tree *tree)1962{1963struct lock_file lock_file = LOCK_INIT;1964struct unpack_trees_options opts;1965struct tree_desc t[1];19661967if(parse_tree(tree))1968return-1;19691970hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);19711972memset(&opts,0,sizeof(opts));1973 opts.head_idx =1;1974 opts.src_index = &the_index;1975 opts.dst_index = &the_index;1976 opts.merge =1;1977 opts.fn = oneway_merge;1978init_tree_desc(&t[0], tree->buffer, tree->size);19791980if(unpack_trees(1, t, &opts)) {1981rollback_lock_file(&lock_file);1982return-1;1983}19841985if(write_locked_index(&the_index, &lock_file, COMMIT_LOCK))1986die(_("unable to write new index file"));19871988return0;1989}19901991/**1992 * Clean the index without touching entries that are not modified between1993 * `head` and `remote`.1994 */1995static intclean_index(const struct object_id *head,const struct object_id *remote)1996{1997struct tree *head_tree, *remote_tree, *index_tree;1998struct object_id index;19992000 head_tree =parse_tree_indirect(head);2001if(!head_tree)2002returnerror(_("Could not parse object '%s'."),oid_to_hex(head));20032004 remote_tree =parse_tree_indirect(remote);2005if(!remote_tree)2006returnerror(_("Could not parse object '%s'."),oid_to_hex(remote));20072008read_cache_unmerged();20092010if(fast_forward_to(head_tree, head_tree,1))2011return-1;20122013if(write_cache_as_tree(&index,0, NULL))2014return-1;20152016 index_tree =parse_tree_indirect(&index);2017if(!index_tree)2018returnerror(_("Could not parse object '%s'."),oid_to_hex(&index));20192020if(fast_forward_to(index_tree, remote_tree,0))2021return-1;20222023if(merge_tree(remote_tree))2024return-1;20252026remove_branch_state();20272028return0;2029}20302031/**2032 * Resets rerere's merge resolution metadata.2033 */2034static voidam_rerere_clear(void)2035{2036struct string_list merge_rr = STRING_LIST_INIT_DUP;2037rerere_clear(&merge_rr);2038string_list_clear(&merge_rr,1);2039}20402041/**2042 * Resume the current am session by skipping the current patch.2043 */2044static voidam_skip(struct am_state *state)2045{2046struct object_id head;20472048am_rerere_clear();20492050if(get_oid("HEAD", &head))2051oidcpy(&head, the_hash_algo->empty_tree);20522053if(clean_index(&head, &head))2054die(_("failed to clean index"));20552056am_next(state);2057am_load(state);2058am_run(state,0);2059}20602061/**2062 * Returns true if it is safe to reset HEAD to the ORIG_HEAD, false otherwise.2063 *2064 * It is not safe to reset HEAD when:2065 * 1. git-am previously failed because the index was dirty.2066 * 2. HEAD has moved since git-am previously failed.2067 */2068static intsafe_to_abort(const struct am_state *state)2069{2070struct strbuf sb = STRBUF_INIT;2071struct object_id abort_safety, head;20722073if(file_exists(am_path(state,"dirtyindex")))2074return0;20752076if(read_state_file(&sb, state,"abort-safety",1) >0) {2077if(get_oid_hex(sb.buf, &abort_safety))2078die(_("could not parse%s"),am_path(state,"abort-safety"));2079}else2080oidclr(&abort_safety);2081strbuf_release(&sb);20822083if(get_oid("HEAD", &head))2084oidclr(&head);20852086if(oideq(&head, &abort_safety))2087return1;20882089warning(_("You seem to have moved HEAD since the last 'am' failure.\n"2090"Not rewinding to ORIG_HEAD"));20912092return0;2093}20942095/**2096 * Aborts the current am session if it is safe to do so.2097 */2098static voidam_abort(struct am_state *state)2099{2100struct object_id curr_head, orig_head;2101int has_curr_head, has_orig_head;2102char*curr_branch;21032104if(!safe_to_abort(state)) {2105am_destroy(state);2106return;2107}21082109am_rerere_clear();21102111 curr_branch =resolve_refdup("HEAD",0, &curr_head, NULL);2112 has_curr_head = curr_branch && !is_null_oid(&curr_head);2113if(!has_curr_head)2114oidcpy(&curr_head, the_hash_algo->empty_tree);21152116 has_orig_head = !get_oid("ORIG_HEAD", &orig_head);2117if(!has_orig_head)2118oidcpy(&orig_head, the_hash_algo->empty_tree);21192120clean_index(&curr_head, &orig_head);21212122if(has_orig_head)2123update_ref("am --abort","HEAD", &orig_head,2124 has_curr_head ? &curr_head : NULL,0,2125 UPDATE_REFS_DIE_ON_ERR);2126else if(curr_branch)2127delete_ref(NULL, curr_branch, NULL, REF_NO_DEREF);21282129free(curr_branch);2130am_destroy(state);2131}21322133static intshow_patch(struct am_state *state)2134{2135struct strbuf sb = STRBUF_INIT;2136const char*patch_path;2137int len;21382139if(!is_null_oid(&state->orig_commit)) {2140const char*av[4] = {"show", NULL,"--", NULL };2141char*new_oid_str;2142int ret;21432144 av[1] = new_oid_str =xstrdup(oid_to_hex(&state->orig_commit));2145 ret =run_command_v_opt(av, RUN_GIT_CMD);2146free(new_oid_str);2147return ret;2148}21492150 patch_path =am_path(state,msgnum(state));2151 len =strbuf_read_file(&sb, patch_path,0);2152if(len <0)2153die_errno(_("failed to read '%s'"), patch_path);21542155setup_pager();2156write_in_full(1, sb.buf, sb.len);2157strbuf_release(&sb);2158return0;2159}21602161/**2162 * parse_options() callback that validates and sets opt->value to the2163 * PATCH_FORMAT_* enum value corresponding to `arg`.2164 */2165static intparse_opt_patchformat(const struct option *opt,const char*arg,int unset)2166{2167int*opt_value = opt->value;21682169if(!strcmp(arg,"mbox"))2170*opt_value = PATCH_FORMAT_MBOX;2171else if(!strcmp(arg,"stgit"))2172*opt_value = PATCH_FORMAT_STGIT;2173else if(!strcmp(arg,"stgit-series"))2174*opt_value = PATCH_FORMAT_STGIT_SERIES;2175else if(!strcmp(arg,"hg"))2176*opt_value = PATCH_FORMAT_HG;2177else if(!strcmp(arg,"mboxrd"))2178*opt_value = PATCH_FORMAT_MBOXRD;2179else2180returnerror(_("Invalid value for --patch-format:%s"), arg);2181return0;2182}21832184enum resume_mode {2185 RESUME_FALSE =0,2186 RESUME_APPLY,2187 RESUME_RESOLVED,2188 RESUME_SKIP,2189 RESUME_ABORT,2190 RESUME_QUIT,2191 RESUME_SHOW_PATCH2192};21932194static intgit_am_config(const char*k,const char*v,void*cb)2195{2196int status;21972198 status =git_gpg_config(k, v, NULL);2199if(status)2200return status;22012202returngit_default_config(k, v, NULL);2203}22042205intcmd_am(int argc,const char**argv,const char*prefix)2206{2207struct am_state state;2208int binary = -1;2209int keep_cr = -1;2210int patch_format = PATCH_FORMAT_UNKNOWN;2211enum resume_mode resume = RESUME_FALSE;2212int in_progress;2213int ret =0;22142215const char*const usage[] = {2216N_("git am [<options>] [(<mbox> | <Maildir>)...]"),2217N_("git am [<options>] (--continue | --skip | --abort)"),2218 NULL2219};22202221struct option options[] = {2222OPT_BOOL('i',"interactive", &state.interactive,2223N_("run interactively")),2224OPT_HIDDEN_BOOL('b',"binary", &binary,2225N_("historical option -- no-op")),2226OPT_BOOL('3',"3way", &state.threeway,2227N_("allow fall back on 3way merging if needed")),2228OPT__QUIET(&state.quiet,N_("be quiet")),2229OPT_SET_INT('s',"signoff", &state.signoff,2230N_("add a Signed-off-by line to the commit message"),2231 SIGNOFF_EXPLICIT),2232OPT_BOOL('u',"utf8", &state.utf8,2233N_("recode into utf8 (default)")),2234OPT_SET_INT('k',"keep", &state.keep,2235N_("pass -k flag to git-mailinfo"), KEEP_TRUE),2236OPT_SET_INT(0,"keep-non-patch", &state.keep,2237N_("pass -b flag to git-mailinfo"), KEEP_NON_PATCH),2238OPT_BOOL('m',"message-id", &state.message_id,2239N_("pass -m flag to git-mailinfo")),2240OPT_SET_INT_F(0,"keep-cr", &keep_cr,2241N_("pass --keep-cr flag to git-mailsplit for mbox format"),22421, PARSE_OPT_NONEG),2243OPT_SET_INT_F(0,"no-keep-cr", &keep_cr,2244N_("do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"),22450, PARSE_OPT_NONEG),2246OPT_BOOL('c',"scissors", &state.scissors,2247N_("strip everything before a scissors line")),2248OPT_PASSTHRU_ARGV(0,"whitespace", &state.git_apply_opts,N_("action"),2249N_("pass it through git-apply"),22500),2251OPT_PASSTHRU_ARGV(0,"ignore-space-change", &state.git_apply_opts, NULL,2252N_("pass it through git-apply"),2253 PARSE_OPT_NOARG),2254OPT_PASSTHRU_ARGV(0,"ignore-whitespace", &state.git_apply_opts, NULL,2255N_("pass it through git-apply"),2256 PARSE_OPT_NOARG),2257OPT_PASSTHRU_ARGV(0,"directory", &state.git_apply_opts,N_("root"),2258N_("pass it through git-apply"),22590),2260OPT_PASSTHRU_ARGV(0,"exclude", &state.git_apply_opts,N_("path"),2261N_("pass it through git-apply"),22620),2263OPT_PASSTHRU_ARGV(0,"include", &state.git_apply_opts,N_("path"),2264N_("pass it through git-apply"),22650),2266OPT_PASSTHRU_ARGV('C', NULL, &state.git_apply_opts,N_("n"),2267N_("pass it through git-apply"),22680),2269OPT_PASSTHRU_ARGV('p', NULL, &state.git_apply_opts,N_("num"),2270N_("pass it through git-apply"),22710),2272OPT_CALLBACK(0,"patch-format", &patch_format,N_("format"),2273N_("format the patch(es) are in"),2274 parse_opt_patchformat),2275OPT_PASSTHRU_ARGV(0,"reject", &state.git_apply_opts, NULL,2276N_("pass it through git-apply"),2277 PARSE_OPT_NOARG),2278OPT_STRING(0,"resolvemsg", &state.resolvemsg, NULL,2279N_("override error message when patch failure occurs")),2280OPT_CMDMODE(0,"continue", &resume,2281N_("continue applying patches after resolving a conflict"),2282 RESUME_RESOLVED),2283OPT_CMDMODE('r',"resolved", &resume,2284N_("synonyms for --continue"),2285 RESUME_RESOLVED),2286OPT_CMDMODE(0,"skip", &resume,2287N_("skip the current patch"),2288 RESUME_SKIP),2289OPT_CMDMODE(0,"abort", &resume,2290N_("restore the original branch and abort the patching operation."),2291 RESUME_ABORT),2292OPT_CMDMODE(0,"quit", &resume,2293N_("abort the patching operation but keep HEAD where it is."),2294 RESUME_QUIT),2295OPT_CMDMODE(0,"show-current-patch", &resume,2296N_("show the patch being applied."),2297 RESUME_SHOW_PATCH),2298OPT_BOOL(0,"committer-date-is-author-date",2299&state.committer_date_is_author_date,2300N_("lie about committer date")),2301OPT_BOOL(0,"ignore-date", &state.ignore_date,2302N_("use current timestamp for author date")),2303OPT_RERERE_AUTOUPDATE(&state.allow_rerere_autoupdate),2304{ OPTION_STRING,'S',"gpg-sign", &state.sign_commit,N_("key-id"),2305N_("GPG-sign commits"),2306 PARSE_OPT_OPTARG, NULL, (intptr_t)""},2307OPT_HIDDEN_BOOL(0,"rebasing", &state.rebasing,2308N_("(internal use for git-rebase)")),2309OPT_END()2310};23112312if(argc ==2&& !strcmp(argv[1],"-h"))2313usage_with_options(usage, options);23142315git_config(git_am_config, NULL);23162317am_state_init(&state);23182319 in_progress =am_in_progress(&state);2320if(in_progress)2321am_load(&state);23222323 argc =parse_options(argc, argv, prefix, options, usage,0);23242325if(binary >=0)2326fprintf_ln(stderr,_("The -b/--binary option has been a no-op for long time, and\n"2327"it will be removed. Please do not use it anymore."));23282329/* Ensure a valid committer ident can be constructed */2330git_committer_info(IDENT_STRICT);23312332if(read_index_preload(&the_index, NULL) <0)2333die(_("failed to read the index"));23342335if(in_progress) {2336/*2337 * Catch user error to feed us patches when there is a session2338 * in progress:2339 *2340 * 1. mbox path(s) are provided on the command-line.2341 * 2. stdin is not a tty: the user is trying to feed us a patch2342 * from standard input. This is somewhat unreliable -- stdin2343 * could be /dev/null for example and the caller did not2344 * intend to feed us a patch but wanted to continue2345 * unattended.2346 */2347if(argc || (resume == RESUME_FALSE && !isatty(0)))2348die(_("previous rebase directory%sstill exists but mbox given."),2349 state.dir);23502351if(resume == RESUME_FALSE)2352 resume = RESUME_APPLY;23532354if(state.signoff == SIGNOFF_EXPLICIT)2355am_append_signoff(&state);2356}else{2357struct argv_array paths = ARGV_ARRAY_INIT;2358int i;23592360/*2361 * Handle stray state directory in the independent-run case. In2362 * the --rebasing case, it is up to the caller to take care of2363 * stray directories.2364 */2365if(file_exists(state.dir) && !state.rebasing) {2366if(resume == RESUME_ABORT || resume == RESUME_QUIT) {2367am_destroy(&state);2368am_state_release(&state);2369return0;2370}23712372die(_("Stray%sdirectory found.\n"2373"Use\"git am --abort\"to remove it."),2374 state.dir);2375}23762377if(resume)2378die(_("Resolve operation not in progress, we are not resuming."));23792380for(i =0; i < argc; i++) {2381if(is_absolute_path(argv[i]) || !prefix)2382argv_array_push(&paths, argv[i]);2383else2384argv_array_push(&paths,mkpath("%s/%s", prefix, argv[i]));2385}23862387am_setup(&state, patch_format, paths.argv, keep_cr);23882389argv_array_clear(&paths);2390}23912392switch(resume) {2393case RESUME_FALSE:2394am_run(&state,0);2395break;2396case RESUME_APPLY:2397am_run(&state,1);2398break;2399case RESUME_RESOLVED:2400am_resolve(&state);2401break;2402case RESUME_SKIP:2403am_skip(&state);2404break;2405case RESUME_ABORT:2406am_abort(&state);2407break;2408case RESUME_QUIT:2409am_rerere_clear();2410am_destroy(&state);2411break;2412case RESUME_SHOW_PATCH:2413 ret =show_patch(&state);2414break;2415default:2416BUG("invalid resume value");2417}24182419am_state_release(&state);24202421return ret;2422}