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 36/** 37 * Returns 1 if the file is empty or does not exist, 0 otherwise. 38 */ 39static intis_empty_file(const char*filename) 40{ 41struct stat st; 42 43if(stat(filename, &st) <0) { 44if(errno == ENOENT) 45return1; 46die_errno(_("could not stat%s"), filename); 47} 48 49return!st.st_size; 50} 51 52/** 53 * Returns the length of the first line of msg. 54 */ 55static intlinelen(const char*msg) 56{ 57returnstrchrnul(msg,'\n') - msg; 58} 59 60/** 61 * Returns true if `str` consists of only whitespace, false otherwise. 62 */ 63static intstr_isspace(const char*str) 64{ 65for(; *str; str++) 66if(!isspace(*str)) 67return0; 68 69return1; 70} 71 72enum patch_format { 73 PATCH_FORMAT_UNKNOWN =0, 74 PATCH_FORMAT_MBOX, 75 PATCH_FORMAT_STGIT, 76 PATCH_FORMAT_STGIT_SERIES, 77 PATCH_FORMAT_HG, 78 PATCH_FORMAT_MBOXRD 79}; 80 81enum keep_type { 82 KEEP_FALSE =0, 83 KEEP_TRUE,/* pass -k flag to git-mailinfo */ 84 KEEP_NON_PATCH /* pass -b flag to git-mailinfo */ 85}; 86 87enum scissors_type { 88 SCISSORS_UNSET = -1, 89 SCISSORS_FALSE =0,/* pass --no-scissors to git-mailinfo */ 90 SCISSORS_TRUE /* pass --scissors to git-mailinfo */ 91}; 92 93enum signoff_type { 94 SIGNOFF_FALSE =0, 95 SIGNOFF_TRUE =1, 96 SIGNOFF_EXPLICIT /* --signoff was set on the command-line */ 97}; 98 99struct am_state { 100/* state directory path */ 101char*dir; 102 103/* current and last patch numbers, 1-indexed */ 104int cur; 105int last; 106 107/* commit metadata and message */ 108char*author_name; 109char*author_email; 110char*author_date; 111char*msg; 112size_t msg_len; 113 114/* when --rebasing, records the original commit the patch came from */ 115struct object_id orig_commit; 116 117/* number of digits in patch filename */ 118int prec; 119 120/* various operating modes and command line options */ 121int interactive; 122int threeway; 123int quiet; 124int signoff;/* enum signoff_type */ 125int utf8; 126int keep;/* enum keep_type */ 127int message_id; 128int scissors;/* enum scissors_type */ 129struct argv_array git_apply_opts; 130const char*resolvemsg; 131int committer_date_is_author_date; 132int ignore_date; 133int allow_rerere_autoupdate; 134const char*sign_commit; 135int rebasing; 136}; 137 138/** 139 * Initializes am_state with the default values. 140 */ 141static voidam_state_init(struct am_state *state) 142{ 143int gpgsign; 144 145memset(state,0,sizeof(*state)); 146 147 state->dir =git_pathdup("rebase-apply"); 148 149 state->prec =4; 150 151git_config_get_bool("am.threeway", &state->threeway); 152 153 state->utf8 =1; 154 155git_config_get_bool("am.messageid", &state->message_id); 156 157 state->scissors = SCISSORS_UNSET; 158 159argv_array_init(&state->git_apply_opts); 160 161if(!git_config_get_bool("commit.gpgsign", &gpgsign)) 162 state->sign_commit = gpgsign ?"": NULL; 163} 164 165/** 166 * Releases memory allocated by an am_state. 167 */ 168static voidam_state_release(struct am_state *state) 169{ 170free(state->dir); 171free(state->author_name); 172free(state->author_email); 173free(state->author_date); 174free(state->msg); 175argv_array_clear(&state->git_apply_opts); 176} 177 178/** 179 * Returns path relative to the am_state directory. 180 */ 181staticinlineconst char*am_path(const struct am_state *state,const char*path) 182{ 183returnmkpath("%s/%s", state->dir, path); 184} 185 186/** 187 * For convenience to call write_file() 188 */ 189static voidwrite_state_text(const struct am_state *state, 190const char*name,const char*string) 191{ 192write_file(am_path(state, name),"%s", string); 193} 194 195static voidwrite_state_count(const struct am_state *state, 196const char*name,int value) 197{ 198write_file(am_path(state, name),"%d", value); 199} 200 201static voidwrite_state_bool(const struct am_state *state, 202const char*name,int value) 203{ 204write_state_text(state, name, value ?"t":"f"); 205} 206 207/** 208 * If state->quiet is false, calls fprintf(fp, fmt, ...), and appends a newline 209 * at the end. 210 */ 211static voidsay(const struct am_state *state,FILE*fp,const char*fmt, ...) 212{ 213va_list ap; 214 215va_start(ap, fmt); 216if(!state->quiet) { 217vfprintf(fp, fmt, ap); 218putc('\n', fp); 219} 220va_end(ap); 221} 222 223/** 224 * Returns 1 if there is an am session in progress, 0 otherwise. 225 */ 226static intam_in_progress(const struct am_state *state) 227{ 228struct stat st; 229 230if(lstat(state->dir, &st) <0|| !S_ISDIR(st.st_mode)) 231return0; 232if(lstat(am_path(state,"last"), &st) || !S_ISREG(st.st_mode)) 233return0; 234if(lstat(am_path(state,"next"), &st) || !S_ISREG(st.st_mode)) 235return0; 236return1; 237} 238 239/** 240 * Reads the contents of `file` in the `state` directory into `sb`. Returns the 241 * number of bytes read on success, -1 if the file does not exist. If `trim` is 242 * set, trailing whitespace will be removed. 243 */ 244static intread_state_file(struct strbuf *sb,const struct am_state *state, 245const char*file,int trim) 246{ 247strbuf_reset(sb); 248 249if(strbuf_read_file(sb,am_path(state, file),0) >=0) { 250if(trim) 251strbuf_trim(sb); 252 253return sb->len; 254} 255 256if(errno == ENOENT) 257return-1; 258 259die_errno(_("could not read '%s'"),am_path(state, file)); 260} 261 262/** 263 * Take a series of KEY='VALUE' lines where VALUE part is 264 * sq-quoted, and append <KEY, VALUE> at the end of the string list 265 */ 266static intparse_key_value_squoted(char*buf,struct string_list *list) 267{ 268while(*buf) { 269struct string_list_item *item; 270char*np; 271char*cp =strchr(buf,'='); 272if(!cp) 273return-1; 274 np =strchrnul(cp,'\n'); 275*cp++ ='\0'; 276 item =string_list_append(list, buf); 277 278 buf = np + (*np =='\n'); 279*np ='\0'; 280 cp =sq_dequote(cp); 281if(!cp) 282return-1; 283 item->util =xstrdup(cp); 284} 285return0; 286} 287 288/** 289 * Reads and parses the state directory's "author-script" file, and sets 290 * state->author_name, state->author_email and state->author_date accordingly. 291 * Returns 0 on success, -1 if the file could not be parsed. 292 * 293 * The author script is of the format: 294 * 295 * GIT_AUTHOR_NAME='$author_name' 296 * GIT_AUTHOR_EMAIL='$author_email' 297 * GIT_AUTHOR_DATE='$author_date' 298 * 299 * where $author_name, $author_email and $author_date are quoted. We are strict 300 * with our parsing, as the file was meant to be eval'd in the old git-am.sh 301 * script, and thus if the file differs from what this function expects, it is 302 * better to bail out than to do something that the user does not expect. 303 */ 304static intread_author_script(struct am_state *state) 305{ 306const char*filename =am_path(state,"author-script"); 307struct strbuf buf = STRBUF_INIT; 308struct string_list kv = STRING_LIST_INIT_DUP; 309int retval = -1;/* assume failure */ 310int fd; 311 312assert(!state->author_name); 313assert(!state->author_email); 314assert(!state->author_date); 315 316 fd =open(filename, O_RDONLY); 317if(fd <0) { 318if(errno == ENOENT) 319return0; 320die_errno(_("could not open '%s' for reading"), filename); 321} 322strbuf_read(&buf, fd,0); 323close(fd); 324if(parse_key_value_squoted(buf.buf, &kv)) 325goto finish; 326 327if(kv.nr !=3|| 328strcmp(kv.items[0].string,"GIT_AUTHOR_NAME") || 329strcmp(kv.items[1].string,"GIT_AUTHOR_EMAIL") || 330strcmp(kv.items[2].string,"GIT_AUTHOR_DATE")) 331goto finish; 332 state->author_name = kv.items[0].util; 333 state->author_email = kv.items[1].util; 334 state->author_date = kv.items[2].util; 335 retval =0; 336finish: 337string_list_clear(&kv, !!retval); 338strbuf_release(&buf); 339return retval; 340} 341 342/** 343 * Saves state->author_name, state->author_email and state->author_date in the 344 * state directory's "author-script" file. 345 */ 346static voidwrite_author_script(const struct am_state *state) 347{ 348struct strbuf sb = STRBUF_INIT; 349 350strbuf_addstr(&sb,"GIT_AUTHOR_NAME="); 351sq_quote_buf(&sb, state->author_name); 352strbuf_addch(&sb,'\n'); 353 354strbuf_addstr(&sb,"GIT_AUTHOR_EMAIL="); 355sq_quote_buf(&sb, state->author_email); 356strbuf_addch(&sb,'\n'); 357 358strbuf_addstr(&sb,"GIT_AUTHOR_DATE="); 359sq_quote_buf(&sb, state->author_date); 360strbuf_addch(&sb,'\n'); 361 362write_state_text(state,"author-script", sb.buf); 363 364strbuf_release(&sb); 365} 366 367/** 368 * Reads the commit message from the state directory's "final-commit" file, 369 * setting state->msg to its contents and state->msg_len to the length of its 370 * contents in bytes. 371 * 372 * Returns 0 on success, -1 if the file does not exist. 373 */ 374static intread_commit_msg(struct am_state *state) 375{ 376struct strbuf sb = STRBUF_INIT; 377 378assert(!state->msg); 379 380if(read_state_file(&sb, state,"final-commit",0) <0) { 381strbuf_release(&sb); 382return-1; 383} 384 385 state->msg =strbuf_detach(&sb, &state->msg_len); 386return0; 387} 388 389/** 390 * Saves state->msg in the state directory's "final-commit" file. 391 */ 392static voidwrite_commit_msg(const struct am_state *state) 393{ 394const char*filename =am_path(state,"final-commit"); 395write_file_buf(filename, state->msg, state->msg_len); 396} 397 398/** 399 * Loads state from disk. 400 */ 401static voidam_load(struct am_state *state) 402{ 403struct strbuf sb = STRBUF_INIT; 404 405if(read_state_file(&sb, state,"next",1) <0) 406BUG("state file 'next' does not exist"); 407 state->cur =strtol(sb.buf, NULL,10); 408 409if(read_state_file(&sb, state,"last",1) <0) 410BUG("state file 'last' does not exist"); 411 state->last =strtol(sb.buf, NULL,10); 412 413if(read_author_script(state) <0) 414die(_("could not parse author script")); 415 416read_commit_msg(state); 417 418if(read_state_file(&sb, state,"original-commit",1) <0) 419oidclr(&state->orig_commit); 420else if(get_oid_hex(sb.buf, &state->orig_commit) <0) 421die(_("could not parse%s"),am_path(state,"original-commit")); 422 423read_state_file(&sb, state,"threeway",1); 424 state->threeway = !strcmp(sb.buf,"t"); 425 426read_state_file(&sb, state,"quiet",1); 427 state->quiet = !strcmp(sb.buf,"t"); 428 429read_state_file(&sb, state,"sign",1); 430 state->signoff = !strcmp(sb.buf,"t"); 431 432read_state_file(&sb, state,"utf8",1); 433 state->utf8 = !strcmp(sb.buf,"t"); 434 435if(file_exists(am_path(state,"rerere-autoupdate"))) { 436read_state_file(&sb, state,"rerere-autoupdate",1); 437 state->allow_rerere_autoupdate =strcmp(sb.buf,"t") ? 438 RERERE_NOAUTOUPDATE : RERERE_AUTOUPDATE; 439}else{ 440 state->allow_rerere_autoupdate =0; 441} 442 443read_state_file(&sb, state,"keep",1); 444if(!strcmp(sb.buf,"t")) 445 state->keep = KEEP_TRUE; 446else if(!strcmp(sb.buf,"b")) 447 state->keep = KEEP_NON_PATCH; 448else 449 state->keep = KEEP_FALSE; 450 451read_state_file(&sb, state,"messageid",1); 452 state->message_id = !strcmp(sb.buf,"t"); 453 454read_state_file(&sb, state,"scissors",1); 455if(!strcmp(sb.buf,"t")) 456 state->scissors = SCISSORS_TRUE; 457else if(!strcmp(sb.buf,"f")) 458 state->scissors = SCISSORS_FALSE; 459else 460 state->scissors = SCISSORS_UNSET; 461 462read_state_file(&sb, state,"apply-opt",1); 463argv_array_clear(&state->git_apply_opts); 464if(sq_dequote_to_argv_array(sb.buf, &state->git_apply_opts) <0) 465die(_("could not parse%s"),am_path(state,"apply-opt")); 466 467 state->rebasing = !!file_exists(am_path(state,"rebasing")); 468 469strbuf_release(&sb); 470} 471 472/** 473 * Removes the am_state directory, forcefully terminating the current am 474 * session. 475 */ 476static voidam_destroy(const struct am_state *state) 477{ 478struct strbuf sb = STRBUF_INIT; 479 480strbuf_addstr(&sb, state->dir); 481remove_dir_recursively(&sb,0); 482strbuf_release(&sb); 483} 484 485/** 486 * Runs applypatch-msg hook. Returns its exit code. 487 */ 488static intrun_applypatch_msg_hook(struct am_state *state) 489{ 490int ret; 491 492assert(state->msg); 493 ret =run_hook_le(NULL,"applypatch-msg",am_path(state,"final-commit"), NULL); 494 495if(!ret) { 496FREE_AND_NULL(state->msg); 497if(read_commit_msg(state) <0) 498die(_("'%s' was deleted by the applypatch-msg hook"), 499am_path(state,"final-commit")); 500} 501 502return ret; 503} 504 505/** 506 * Runs post-rewrite hook. Returns it exit code. 507 */ 508static intrun_post_rewrite_hook(const struct am_state *state) 509{ 510struct child_process cp = CHILD_PROCESS_INIT; 511const char*hook =find_hook("post-rewrite"); 512int ret; 513 514if(!hook) 515return0; 516 517argv_array_push(&cp.args, hook); 518argv_array_push(&cp.args,"rebase"); 519 520 cp.in =xopen(am_path(state,"rewritten"), O_RDONLY); 521 cp.stdout_to_stderr =1; 522 523 ret =run_command(&cp); 524 525close(cp.in); 526return ret; 527} 528 529/** 530 * Reads the state directory's "rewritten" file, and copies notes from the old 531 * commits listed in the file to their rewritten commits. 532 * 533 * Returns 0 on success, -1 on failure. 534 */ 535static intcopy_notes_for_rebase(const struct am_state *state) 536{ 537struct notes_rewrite_cfg *c; 538struct strbuf sb = STRBUF_INIT; 539const char*invalid_line =_("Malformed input line: '%s'."); 540const char*msg ="Notes added by 'git rebase'"; 541FILE*fp; 542int ret =0; 543 544assert(state->rebasing); 545 546 c =init_copy_notes_for_rewrite("rebase"); 547if(!c) 548return0; 549 550 fp =xfopen(am_path(state,"rewritten"),"r"); 551 552while(!strbuf_getline_lf(&sb, fp)) { 553struct object_id from_obj, to_obj; 554 555if(sb.len != GIT_SHA1_HEXSZ *2+1) { 556 ret =error(invalid_line, sb.buf); 557goto finish; 558} 559 560if(get_oid_hex(sb.buf, &from_obj)) { 561 ret =error(invalid_line, sb.buf); 562goto finish; 563} 564 565if(sb.buf[GIT_SHA1_HEXSZ] !=' ') { 566 ret =error(invalid_line, sb.buf); 567goto finish; 568} 569 570if(get_oid_hex(sb.buf + GIT_SHA1_HEXSZ +1, &to_obj)) { 571 ret =error(invalid_line, sb.buf); 572goto finish; 573} 574 575if(copy_note_for_rewrite(c, &from_obj, &to_obj)) 576 ret =error(_("Failed to copy notes from '%s' to '%s'"), 577oid_to_hex(&from_obj),oid_to_hex(&to_obj)); 578} 579 580finish: 581finish_copy_notes_for_rewrite(c, msg); 582fclose(fp); 583strbuf_release(&sb); 584return ret; 585} 586 587/** 588 * Determines if the file looks like a piece of RFC2822 mail by grabbing all 589 * non-indented lines and checking if they look like they begin with valid 590 * header field names. 591 * 592 * Returns 1 if the file looks like a piece of mail, 0 otherwise. 593 */ 594static intis_mail(FILE*fp) 595{ 596const char*header_regex ="^[!-9;-~]+:"; 597struct strbuf sb = STRBUF_INIT; 598 regex_t regex; 599int ret =1; 600 601if(fseek(fp,0L, SEEK_SET)) 602die_errno(_("fseek failed")); 603 604if(regcomp(®ex, header_regex, REG_NOSUB | REG_EXTENDED)) 605die("invalid pattern:%s", header_regex); 606 607while(!strbuf_getline(&sb, fp)) { 608if(!sb.len) 609break;/* End of header */ 610 611/* Ignore indented folded lines */ 612if(*sb.buf =='\t'|| *sb.buf ==' ') 613continue; 614 615/* It's a header if it matches header_regex */ 616if(regexec(®ex, sb.buf,0, NULL,0)) { 617 ret =0; 618goto done; 619} 620} 621 622done: 623regfree(®ex); 624strbuf_release(&sb); 625return ret; 626} 627 628/** 629 * Attempts to detect the patch_format of the patches contained in `paths`, 630 * returning the PATCH_FORMAT_* enum value. Returns PATCH_FORMAT_UNKNOWN if 631 * detection fails. 632 */ 633static intdetect_patch_format(const char**paths) 634{ 635enum patch_format ret = PATCH_FORMAT_UNKNOWN; 636struct strbuf l1 = STRBUF_INIT; 637struct strbuf l2 = STRBUF_INIT; 638struct strbuf l3 = STRBUF_INIT; 639FILE*fp; 640 641/* 642 * We default to mbox format if input is from stdin and for directories 643 */ 644if(!*paths || !strcmp(*paths,"-") ||is_directory(*paths)) 645return PATCH_FORMAT_MBOX; 646 647/* 648 * Otherwise, check the first few lines of the first patch, starting 649 * from the first non-blank line, to try to detect its format. 650 */ 651 652 fp =xfopen(*paths,"r"); 653 654while(!strbuf_getline(&l1, fp)) { 655if(l1.len) 656break; 657} 658 659if(starts_with(l1.buf,"From ") ||starts_with(l1.buf,"From: ")) { 660 ret = PATCH_FORMAT_MBOX; 661goto done; 662} 663 664if(starts_with(l1.buf,"# This series applies on GIT commit")) { 665 ret = PATCH_FORMAT_STGIT_SERIES; 666goto done; 667} 668 669if(!strcmp(l1.buf,"# HG changeset patch")) { 670 ret = PATCH_FORMAT_HG; 671goto done; 672} 673 674strbuf_getline(&l2, fp); 675strbuf_getline(&l3, fp); 676 677/* 678 * If the second line is empty and the third is a From, Author or Date 679 * entry, this is likely an StGit patch. 680 */ 681if(l1.len && !l2.len && 682(starts_with(l3.buf,"From:") || 683starts_with(l3.buf,"Author:") || 684starts_with(l3.buf,"Date:"))) { 685 ret = PATCH_FORMAT_STGIT; 686goto done; 687} 688 689if(l1.len &&is_mail(fp)) { 690 ret = PATCH_FORMAT_MBOX; 691goto done; 692} 693 694done: 695fclose(fp); 696strbuf_release(&l1); 697strbuf_release(&l2); 698strbuf_release(&l3); 699return ret; 700} 701 702/** 703 * Splits out individual email patches from `paths`, where each path is either 704 * a mbox file or a Maildir. Returns 0 on success, -1 on failure. 705 */ 706static intsplit_mail_mbox(struct am_state *state,const char**paths, 707int keep_cr,int mboxrd) 708{ 709struct child_process cp = CHILD_PROCESS_INIT; 710struct strbuf last = STRBUF_INIT; 711int ret; 712 713 cp.git_cmd =1; 714argv_array_push(&cp.args,"mailsplit"); 715argv_array_pushf(&cp.args,"-d%d", state->prec); 716argv_array_pushf(&cp.args,"-o%s", state->dir); 717argv_array_push(&cp.args,"-b"); 718if(keep_cr) 719argv_array_push(&cp.args,"--keep-cr"); 720if(mboxrd) 721argv_array_push(&cp.args,"--mboxrd"); 722argv_array_push(&cp.args,"--"); 723argv_array_pushv(&cp.args, paths); 724 725 ret =capture_command(&cp, &last,8); 726if(ret) 727goto exit; 728 729 state->cur =1; 730 state->last =strtol(last.buf, NULL,10); 731 732exit: 733strbuf_release(&last); 734return ret ? -1:0; 735} 736 737/** 738 * Callback signature for split_mail_conv(). The foreign patch should be 739 * read from `in`, and the converted patch (in RFC2822 mail format) should be 740 * written to `out`. Return 0 on success, or -1 on failure. 741 */ 742typedefint(*mail_conv_fn)(FILE*out,FILE*in,int keep_cr); 743 744/** 745 * Calls `fn` for each file in `paths` to convert the foreign patch to the 746 * RFC2822 mail format suitable for parsing with git-mailinfo. 747 * 748 * Returns 0 on success, -1 on failure. 749 */ 750static intsplit_mail_conv(mail_conv_fn fn,struct am_state *state, 751const char**paths,int keep_cr) 752{ 753static const char*stdin_only[] = {"-", NULL}; 754int i; 755 756if(!*paths) 757 paths = stdin_only; 758 759for(i =0; *paths; paths++, i++) { 760FILE*in, *out; 761const char*mail; 762int ret; 763 764if(!strcmp(*paths,"-")) 765 in = stdin; 766else 767 in =fopen(*paths,"r"); 768 769if(!in) 770returnerror_errno(_("could not open '%s' for reading"), 771*paths); 772 773 mail =mkpath("%s/%0*d", state->dir, state->prec, i +1); 774 775 out =fopen(mail,"w"); 776if(!out) { 777if(in != stdin) 778fclose(in); 779returnerror_errno(_("could not open '%s' for writing"), 780 mail); 781} 782 783 ret =fn(out, in, keep_cr); 784 785fclose(out); 786if(in != stdin) 787fclose(in); 788 789if(ret) 790returnerror(_("could not parse patch '%s'"), *paths); 791} 792 793 state->cur =1; 794 state->last = i; 795return0; 796} 797 798/** 799 * A split_mail_conv() callback that converts an StGit patch to an RFC2822 800 * message suitable for parsing with git-mailinfo. 801 */ 802static intstgit_patch_to_mail(FILE*out,FILE*in,int keep_cr) 803{ 804struct strbuf sb = STRBUF_INIT; 805int subject_printed =0; 806 807while(!strbuf_getline_lf(&sb, in)) { 808const char*str; 809 810if(str_isspace(sb.buf)) 811continue; 812else if(skip_prefix(sb.buf,"Author:", &str)) 813fprintf(out,"From:%s\n", str); 814else if(starts_with(sb.buf,"From") ||starts_with(sb.buf,"Date")) 815fprintf(out,"%s\n", sb.buf); 816else if(!subject_printed) { 817fprintf(out,"Subject:%s\n", sb.buf); 818 subject_printed =1; 819}else{ 820fprintf(out,"\n%s\n", sb.buf); 821break; 822} 823} 824 825strbuf_reset(&sb); 826while(strbuf_fread(&sb,8192, in) >0) { 827fwrite(sb.buf,1, sb.len, out); 828strbuf_reset(&sb); 829} 830 831strbuf_release(&sb); 832return0; 833} 834 835/** 836 * This function only supports a single StGit series file in `paths`. 837 * 838 * Given an StGit series file, converts the StGit patches in the series into 839 * RFC2822 messages suitable for parsing with git-mailinfo, and queues them in 840 * the state directory. 841 * 842 * Returns 0 on success, -1 on failure. 843 */ 844static intsplit_mail_stgit_series(struct am_state *state,const char**paths, 845int keep_cr) 846{ 847const char*series_dir; 848char*series_dir_buf; 849FILE*fp; 850struct argv_array patches = ARGV_ARRAY_INIT; 851struct strbuf sb = STRBUF_INIT; 852int ret; 853 854if(!paths[0] || paths[1]) 855returnerror(_("Only one StGIT patch series can be applied at once")); 856 857 series_dir_buf =xstrdup(*paths); 858 series_dir =dirname(series_dir_buf); 859 860 fp =fopen(*paths,"r"); 861if(!fp) 862returnerror_errno(_("could not open '%s' for reading"), *paths); 863 864while(!strbuf_getline_lf(&sb, fp)) { 865if(*sb.buf =='#') 866continue;/* skip comment lines */ 867 868argv_array_push(&patches,mkpath("%s/%s", series_dir, sb.buf)); 869} 870 871fclose(fp); 872strbuf_release(&sb); 873free(series_dir_buf); 874 875 ret =split_mail_conv(stgit_patch_to_mail, state, patches.argv, keep_cr); 876 877argv_array_clear(&patches); 878return ret; 879} 880 881/** 882 * A split_patches_conv() callback that converts a mercurial patch to a RFC2822 883 * message suitable for parsing with git-mailinfo. 884 */ 885static inthg_patch_to_mail(FILE*out,FILE*in,int keep_cr) 886{ 887struct strbuf sb = STRBUF_INIT; 888int rc =0; 889 890while(!strbuf_getline_lf(&sb, in)) { 891const char*str; 892 893if(skip_prefix(sb.buf,"# User ", &str)) 894fprintf(out,"From:%s\n", str); 895else if(skip_prefix(sb.buf,"# Date ", &str)) { 896 timestamp_t timestamp; 897long tz, tz2; 898char*end; 899 900 errno =0; 901 timestamp =parse_timestamp(str, &end,10); 902if(errno) { 903 rc =error(_("invalid timestamp")); 904goto exit; 905} 906 907if(!skip_prefix(end," ", &str)) { 908 rc =error(_("invalid Date line")); 909goto exit; 910} 911 912 errno =0; 913 tz =strtol(str, &end,10); 914if(errno) { 915 rc =error(_("invalid timezone offset")); 916goto exit; 917} 918 919if(*end) { 920 rc =error(_("invalid Date line")); 921goto exit; 922} 923 924/* 925 * mercurial's timezone is in seconds west of UTC, 926 * however git's timezone is in hours + minutes east of 927 * UTC. Convert it. 928 */ 929 tz2 =labs(tz) /3600*100+labs(tz) %3600/60; 930if(tz >0) 931 tz2 = -tz2; 932 933fprintf(out,"Date:%s\n",show_date(timestamp, tz2,DATE_MODE(RFC2822))); 934}else if(starts_with(sb.buf,"# ")) { 935continue; 936}else{ 937fprintf(out,"\n%s\n", sb.buf); 938break; 939} 940} 941 942strbuf_reset(&sb); 943while(strbuf_fread(&sb,8192, in) >0) { 944fwrite(sb.buf,1, sb.len, out); 945strbuf_reset(&sb); 946} 947exit: 948strbuf_release(&sb); 949return rc; 950} 951 952/** 953 * Splits a list of files/directories into individual email patches. Each path 954 * in `paths` must be a file/directory that is formatted according to 955 * `patch_format`. 956 * 957 * Once split out, the individual email patches will be stored in the state 958 * directory, with each patch's filename being its index, padded to state->prec 959 * digits. 960 * 961 * state->cur will be set to the index of the first mail, and state->last will 962 * be set to the index of the last mail. 963 * 964 * Set keep_cr to 0 to convert all lines ending with \r\n to end with \n, 1 965 * to disable this behavior, -1 to use the default configured setting. 966 * 967 * Returns 0 on success, -1 on failure. 968 */ 969static intsplit_mail(struct am_state *state,enum patch_format patch_format, 970const char**paths,int keep_cr) 971{ 972if(keep_cr <0) { 973 keep_cr =0; 974git_config_get_bool("am.keepcr", &keep_cr); 975} 976 977switch(patch_format) { 978case PATCH_FORMAT_MBOX: 979returnsplit_mail_mbox(state, paths, keep_cr,0); 980case PATCH_FORMAT_STGIT: 981returnsplit_mail_conv(stgit_patch_to_mail, state, paths, keep_cr); 982case PATCH_FORMAT_STGIT_SERIES: 983returnsplit_mail_stgit_series(state, paths, keep_cr); 984case PATCH_FORMAT_HG: 985returnsplit_mail_conv(hg_patch_to_mail, state, paths, keep_cr); 986case PATCH_FORMAT_MBOXRD: 987returnsplit_mail_mbox(state, paths, keep_cr,1); 988default: 989BUG("invalid patch_format"); 990} 991return-1; 992} 993 994/** 995 * Setup a new am session for applying patches 996 */ 997static voidam_setup(struct am_state *state,enum patch_format patch_format, 998const char**paths,int keep_cr) 999{1000struct object_id curr_head;1001const char*str;1002struct strbuf sb = STRBUF_INIT;10031004if(!patch_format)1005 patch_format =detect_patch_format(paths);10061007if(!patch_format) {1008fprintf_ln(stderr,_("Patch format detection failed."));1009exit(128);1010}10111012if(mkdir(state->dir,0777) <0&& errno != EEXIST)1013die_errno(_("failed to create directory '%s'"), state->dir);1014delete_ref(NULL,"REBASE_HEAD", NULL, REF_NO_DEREF);10151016if(split_mail(state, patch_format, paths, keep_cr) <0) {1017am_destroy(state);1018die(_("Failed to split patches."));1019}10201021if(state->rebasing)1022 state->threeway =1;10231024write_state_bool(state,"threeway", state->threeway);1025write_state_bool(state,"quiet", state->quiet);1026write_state_bool(state,"sign", state->signoff);1027write_state_bool(state,"utf8", state->utf8);10281029if(state->allow_rerere_autoupdate)1030write_state_bool(state,"rerere-autoupdate",1031 state->allow_rerere_autoupdate == RERERE_AUTOUPDATE);10321033switch(state->keep) {1034case KEEP_FALSE:1035 str ="f";1036break;1037case KEEP_TRUE:1038 str ="t";1039break;1040case KEEP_NON_PATCH:1041 str ="b";1042break;1043default:1044BUG("invalid value for state->keep");1045}10461047write_state_text(state,"keep", str);1048write_state_bool(state,"messageid", state->message_id);10491050switch(state->scissors) {1051case SCISSORS_UNSET:1052 str ="";1053break;1054case SCISSORS_FALSE:1055 str ="f";1056break;1057case SCISSORS_TRUE:1058 str ="t";1059break;1060default:1061BUG("invalid value for state->scissors");1062}1063write_state_text(state,"scissors", str);10641065sq_quote_argv(&sb, state->git_apply_opts.argv);1066write_state_text(state,"apply-opt", sb.buf);10671068if(state->rebasing)1069write_state_text(state,"rebasing","");1070else1071write_state_text(state,"applying","");10721073if(!get_oid("HEAD", &curr_head)) {1074write_state_text(state,"abort-safety",oid_to_hex(&curr_head));1075if(!state->rebasing)1076update_ref("am","ORIG_HEAD", &curr_head, NULL,0,1077 UPDATE_REFS_DIE_ON_ERR);1078}else{1079write_state_text(state,"abort-safety","");1080if(!state->rebasing)1081delete_ref(NULL,"ORIG_HEAD", NULL,0);1082}10831084/*1085 * NOTE: Since the "next" and "last" files determine if an am_state1086 * session is in progress, they should be written last.1087 */10881089write_state_count(state,"next", state->cur);1090write_state_count(state,"last", state->last);10911092strbuf_release(&sb);1093}10941095/**1096 * Increments the patch pointer, and cleans am_state for the application of the1097 * next patch.1098 */1099static voidam_next(struct am_state *state)1100{1101struct object_id head;11021103FREE_AND_NULL(state->author_name);1104FREE_AND_NULL(state->author_email);1105FREE_AND_NULL(state->author_date);1106FREE_AND_NULL(state->msg);1107 state->msg_len =0;11081109unlink(am_path(state,"author-script"));1110unlink(am_path(state,"final-commit"));11111112oidclr(&state->orig_commit);1113unlink(am_path(state,"original-commit"));1114delete_ref(NULL,"REBASE_HEAD", NULL, REF_NO_DEREF);11151116if(!get_oid("HEAD", &head))1117write_state_text(state,"abort-safety",oid_to_hex(&head));1118else1119write_state_text(state,"abort-safety","");11201121 state->cur++;1122write_state_count(state,"next", state->cur);1123}11241125/**1126 * Returns the filename of the current patch email.1127 */1128static const char*msgnum(const struct am_state *state)1129{1130static struct strbuf sb = STRBUF_INIT;11311132strbuf_reset(&sb);1133strbuf_addf(&sb,"%0*d", state->prec, state->cur);11341135return sb.buf;1136}11371138/**1139 * Refresh and write index.1140 */1141static voidrefresh_and_write_cache(void)1142{1143struct lock_file lock_file = LOCK_INIT;11441145hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);1146refresh_cache(REFRESH_QUIET);1147if(write_locked_index(&the_index, &lock_file, COMMIT_LOCK))1148die(_("unable to write index file"));1149}11501151/**1152 * Dies with a user-friendly message on how to proceed after resolving the1153 * problem. This message can be overridden with state->resolvemsg.1154 */1155static void NORETURN die_user_resolve(const struct am_state *state)1156{1157if(state->resolvemsg) {1158printf_ln("%s", state->resolvemsg);1159}else{1160const char*cmdline = state->interactive ?"git am -i":"git am";11611162printf_ln(_("When you have resolved this problem, run\"%s--continue\"."), cmdline);1163printf_ln(_("If you prefer to skip this patch, run\"%s--skip\"instead."), cmdline);1164printf_ln(_("To restore the original branch and stop patching, run\"%s--abort\"."), cmdline);1165}11661167exit(128);1168}11691170/**1171 * Appends signoff to the "msg" field of the am_state.1172 */1173static voidam_append_signoff(struct am_state *state)1174{1175struct strbuf sb = STRBUF_INIT;11761177strbuf_attach(&sb, state->msg, state->msg_len, state->msg_len);1178append_signoff(&sb,0,0);1179 state->msg =strbuf_detach(&sb, &state->msg_len);1180}11811182/**1183 * Parses `mail` using git-mailinfo, extracting its patch and authorship info.1184 * state->msg will be set to the patch message. state->author_name,1185 * state->author_email and state->author_date will be set to the patch author's1186 * name, email and date respectively. The patch body will be written to the1187 * state directory's "patch" file.1188 *1189 * Returns 1 if the patch should be skipped, 0 otherwise.1190 */1191static intparse_mail(struct am_state *state,const char*mail)1192{1193FILE*fp;1194struct strbuf sb = STRBUF_INIT;1195struct strbuf msg = STRBUF_INIT;1196struct strbuf author_name = STRBUF_INIT;1197struct strbuf author_date = STRBUF_INIT;1198struct strbuf author_email = STRBUF_INIT;1199int ret =0;1200struct mailinfo mi;12011202setup_mailinfo(&mi);12031204if(state->utf8)1205 mi.metainfo_charset =get_commit_output_encoding();1206else1207 mi.metainfo_charset = NULL;12081209switch(state->keep) {1210case KEEP_FALSE:1211break;1212case KEEP_TRUE:1213 mi.keep_subject =1;1214break;1215case KEEP_NON_PATCH:1216 mi.keep_non_patch_brackets_in_subject =1;1217break;1218default:1219BUG("invalid value for state->keep");1220}12211222if(state->message_id)1223 mi.add_message_id =1;12241225switch(state->scissors) {1226case SCISSORS_UNSET:1227break;1228case SCISSORS_FALSE:1229 mi.use_scissors =0;1230break;1231case SCISSORS_TRUE:1232 mi.use_scissors =1;1233break;1234default:1235BUG("invalid value for state->scissors");1236}12371238 mi.input =xfopen(mail,"r");1239 mi.output =xfopen(am_path(state,"info"),"w");1240if(mailinfo(&mi,am_path(state,"msg"),am_path(state,"patch")))1241die("could not parse patch");12421243fclose(mi.input);1244fclose(mi.output);12451246if(mi.format_flowed)1247warning(_("Patch sent with format=flowed; "1248"space at the end of lines might be lost."));12491250/* Extract message and author information */1251 fp =xfopen(am_path(state,"info"),"r");1252while(!strbuf_getline_lf(&sb, fp)) {1253const char*x;12541255if(skip_prefix(sb.buf,"Subject: ", &x)) {1256if(msg.len)1257strbuf_addch(&msg,'\n');1258strbuf_addstr(&msg, x);1259}else if(skip_prefix(sb.buf,"Author: ", &x))1260strbuf_addstr(&author_name, x);1261else if(skip_prefix(sb.buf,"Email: ", &x))1262strbuf_addstr(&author_email, x);1263else if(skip_prefix(sb.buf,"Date: ", &x))1264strbuf_addstr(&author_date, x);1265}1266fclose(fp);12671268/* Skip pine's internal folder data */1269if(!strcmp(author_name.buf,"Mail System Internal Data")) {1270 ret =1;1271goto finish;1272}12731274if(is_empty_file(am_path(state,"patch"))) {1275printf_ln(_("Patch is empty."));1276die_user_resolve(state);1277}12781279strbuf_addstr(&msg,"\n\n");1280strbuf_addbuf(&msg, &mi.log_message);1281strbuf_stripspace(&msg,0);12821283assert(!state->author_name);1284 state->author_name =strbuf_detach(&author_name, NULL);12851286assert(!state->author_email);1287 state->author_email =strbuf_detach(&author_email, NULL);12881289assert(!state->author_date);1290 state->author_date =strbuf_detach(&author_date, NULL);12911292assert(!state->msg);1293 state->msg =strbuf_detach(&msg, &state->msg_len);12941295finish:1296strbuf_release(&msg);1297strbuf_release(&author_date);1298strbuf_release(&author_email);1299strbuf_release(&author_name);1300strbuf_release(&sb);1301clear_mailinfo(&mi);1302return ret;1303}13041305/**1306 * Sets commit_id to the commit hash where the mail was generated from.1307 * Returns 0 on success, -1 on failure.1308 */1309static intget_mail_commit_oid(struct object_id *commit_id,const char*mail)1310{1311struct strbuf sb = STRBUF_INIT;1312FILE*fp =xfopen(mail,"r");1313const char*x;1314int ret =0;13151316if(strbuf_getline_lf(&sb, fp) ||1317!skip_prefix(sb.buf,"From ", &x) ||1318get_oid_hex(x, commit_id) <0)1319 ret = -1;13201321strbuf_release(&sb);1322fclose(fp);1323return ret;1324}13251326/**1327 * Sets state->msg, state->author_name, state->author_email, state->author_date1328 * to the commit's respective info.1329 */1330static voidget_commit_info(struct am_state *state,struct commit *commit)1331{1332const char*buffer, *ident_line, *msg;1333size_t ident_len;1334struct ident_split id;13351336 buffer =logmsg_reencode(commit, NULL,get_commit_output_encoding());13371338 ident_line =find_commit_header(buffer,"author", &ident_len);13391340if(split_ident_line(&id, ident_line, ident_len) <0)1341die(_("invalid ident line: %.*s"), (int)ident_len, ident_line);13421343assert(!state->author_name);1344if(id.name_begin)1345 state->author_name =1346xmemdupz(id.name_begin, id.name_end - id.name_begin);1347else1348 state->author_name =xstrdup("");13491350assert(!state->author_email);1351if(id.mail_begin)1352 state->author_email =1353xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);1354else1355 state->author_email =xstrdup("");13561357assert(!state->author_date);1358 state->author_date =xstrdup(show_ident_date(&id,DATE_MODE(NORMAL)));13591360assert(!state->msg);1361 msg =strstr(buffer,"\n\n");1362if(!msg)1363die(_("unable to parse commit%s"),oid_to_hex(&commit->object.oid));1364 state->msg =xstrdup(msg +2);1365 state->msg_len =strlen(state->msg);1366unuse_commit_buffer(commit, buffer);1367}13681369/**1370 * Writes `commit` as a patch to the state directory's "patch" file.1371 */1372static voidwrite_commit_patch(const struct am_state *state,struct commit *commit)1373{1374struct rev_info rev_info;1375FILE*fp;13761377 fp =xfopen(am_path(state,"patch"),"w");1378init_revisions(&rev_info, NULL);1379 rev_info.diff =1;1380 rev_info.abbrev =0;1381 rev_info.disable_stdin =1;1382 rev_info.show_root_diff =1;1383 rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;1384 rev_info.no_commit_id =1;1385 rev_info.diffopt.flags.binary =1;1386 rev_info.diffopt.flags.full_index =1;1387 rev_info.diffopt.use_color =0;1388 rev_info.diffopt.file = fp;1389 rev_info.diffopt.close_file =1;1390add_pending_object(&rev_info, &commit->object,"");1391diff_setup_done(&rev_info.diffopt);1392log_tree_commit(&rev_info, commit);1393}13941395/**1396 * Writes the diff of the index against HEAD as a patch to the state1397 * directory's "patch" file.1398 */1399static voidwrite_index_patch(const struct am_state *state)1400{1401struct tree *tree;1402struct object_id head;1403struct rev_info rev_info;1404FILE*fp;14051406if(!get_oid_tree("HEAD", &head))1407 tree =lookup_tree(&head);1408else1409 tree =lookup_tree(the_hash_algo->empty_tree);14101411 fp =xfopen(am_path(state,"patch"),"w");1412init_revisions(&rev_info, NULL);1413 rev_info.diff =1;1414 rev_info.disable_stdin =1;1415 rev_info.no_commit_id =1;1416 rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;1417 rev_info.diffopt.use_color =0;1418 rev_info.diffopt.file = fp;1419 rev_info.diffopt.close_file =1;1420add_pending_object(&rev_info, &tree->object,"");1421diff_setup_done(&rev_info.diffopt);1422run_diff_index(&rev_info,1);1423}14241425/**1426 * Like parse_mail(), but parses the mail by looking up its commit ID1427 * directly. This is used in --rebasing mode to bypass git-mailinfo's munging1428 * of patches.1429 *1430 * state->orig_commit will be set to the original commit ID.1431 *1432 * Will always return 0 as the patch should never be skipped.1433 */1434static intparse_mail_rebase(struct am_state *state,const char*mail)1435{1436struct commit *commit;1437struct object_id commit_oid;14381439if(get_mail_commit_oid(&commit_oid, mail) <0)1440die(_("could not parse%s"), mail);14411442 commit =lookup_commit_or_die(&commit_oid, mail);14431444get_commit_info(state, commit);14451446write_commit_patch(state, commit);14471448oidcpy(&state->orig_commit, &commit_oid);1449write_state_text(state,"original-commit",oid_to_hex(&commit_oid));1450update_ref("am","REBASE_HEAD", &commit_oid,1451 NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);14521453return0;1454}14551456/**1457 * Applies current patch with git-apply. Returns 0 on success, -1 otherwise. If1458 * `index_file` is not NULL, the patch will be applied to that index.1459 */1460static intrun_apply(const struct am_state *state,const char*index_file)1461{1462struct argv_array apply_paths = ARGV_ARRAY_INIT;1463struct argv_array apply_opts = ARGV_ARRAY_INIT;1464struct apply_state apply_state;1465int res, opts_left;1466int force_apply =0;1467int options =0;14681469if(init_apply_state(&apply_state, NULL))1470BUG("init_apply_state() failed");14711472argv_array_push(&apply_opts,"apply");1473argv_array_pushv(&apply_opts, state->git_apply_opts.argv);14741475 opts_left =apply_parse_options(apply_opts.argc, apply_opts.argv,1476&apply_state, &force_apply, &options,1477 NULL);14781479if(opts_left !=0)1480die("unknown option passed through to git apply");14811482if(index_file) {1483 apply_state.index_file = index_file;1484 apply_state.cached =1;1485}else1486 apply_state.check_index =1;14871488/*1489 * If we are allowed to fall back on 3-way merge, don't give false1490 * errors during the initial attempt.1491 */1492if(state->threeway && !index_file)1493 apply_state.apply_verbosity = verbosity_silent;14941495if(check_apply_state(&apply_state, force_apply))1496BUG("check_apply_state() failed");14971498argv_array_push(&apply_paths,am_path(state,"patch"));14991500 res =apply_all_patches(&apply_state, apply_paths.argc, apply_paths.argv, options);15011502argv_array_clear(&apply_paths);1503argv_array_clear(&apply_opts);1504clear_apply_state(&apply_state);15051506if(res)1507return res;15081509if(index_file) {1510/* Reload index as apply_all_patches() will have modified it. */1511discard_cache();1512read_cache_from(index_file);1513}15141515return0;1516}15171518/**1519 * Builds an index that contains just the blobs needed for a 3way merge.1520 */1521static intbuild_fake_ancestor(const struct am_state *state,const char*index_file)1522{1523struct child_process cp = CHILD_PROCESS_INIT;15241525 cp.git_cmd =1;1526argv_array_push(&cp.args,"apply");1527argv_array_pushv(&cp.args, state->git_apply_opts.argv);1528argv_array_pushf(&cp.args,"--build-fake-ancestor=%s", index_file);1529argv_array_push(&cp.args,am_path(state,"patch"));15301531if(run_command(&cp))1532return-1;15331534return0;1535}15361537/**1538 * Attempt a threeway merge, using index_path as the temporary index.1539 */1540static intfall_back_threeway(const struct am_state *state,const char*index_path)1541{1542struct object_id orig_tree, their_tree, our_tree;1543const struct object_id *bases[1] = { &orig_tree };1544struct merge_options o;1545struct commit *result;1546char*their_tree_name;15471548if(get_oid("HEAD", &our_tree) <0)1549oidcpy(&our_tree, the_hash_algo->empty_tree);15501551if(build_fake_ancestor(state, index_path))1552returnerror("could not build fake ancestor");15531554discard_cache();1555read_cache_from(index_path);15561557if(write_index_as_tree(&orig_tree, &the_index, index_path,0, NULL))1558returnerror(_("Repository lacks necessary blobs to fall back on 3-way merge."));15591560say(state, stdout,_("Using index info to reconstruct a base tree..."));15611562if(!state->quiet) {1563/*1564 * List paths that needed 3-way fallback, so that the user can1565 * review them with extra care to spot mismerges.1566 */1567struct rev_info rev_info;1568const char*diff_filter_str ="--diff-filter=AM";15691570init_revisions(&rev_info, NULL);1571 rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;1572diff_opt_parse(&rev_info.diffopt, &diff_filter_str,1, rev_info.prefix);1573add_pending_oid(&rev_info,"HEAD", &our_tree,0);1574diff_setup_done(&rev_info.diffopt);1575run_diff_index(&rev_info,1);1576}15771578if(run_apply(state, index_path))1579returnerror(_("Did you hand edit your patch?\n"1580"It does not apply to blobs recorded in its index."));15811582if(write_index_as_tree(&their_tree, &the_index, index_path,0, NULL))1583returnerror("could not write tree");15841585say(state, stdout,_("Falling back to patching base and 3-way merge..."));15861587discard_cache();1588read_cache();15891590/*1591 * This is not so wrong. Depending on which base we picked, orig_tree1592 * may be wildly different from ours, but their_tree has the same set of1593 * wildly different changes in parts the patch did not touch, so1594 * recursive ends up canceling them, saying that we reverted all those1595 * changes.1596 */15971598init_merge_options(&o);15991600 o.branch1 ="HEAD";1601 their_tree_name =xstrfmt("%.*s",linelen(state->msg), state->msg);1602 o.branch2 = their_tree_name;16031604if(state->quiet)1605 o.verbosity =0;16061607if(merge_recursive_generic(&o, &our_tree, &their_tree,1, bases, &result)) {1608rerere(state->allow_rerere_autoupdate);1609free(their_tree_name);1610returnerror(_("Failed to merge in the changes."));1611}16121613free(their_tree_name);1614return0;1615}16161617/**1618 * Commits the current index with state->msg as the commit message and1619 * state->author_name, state->author_email and state->author_date as the author1620 * information.1621 */1622static voiddo_commit(const struct am_state *state)1623{1624struct object_id tree, parent, commit;1625const struct object_id *old_oid;1626struct commit_list *parents = NULL;1627const char*reflog_msg, *author;1628struct strbuf sb = STRBUF_INIT;16291630if(run_hook_le(NULL,"pre-applypatch", NULL))1631exit(1);16321633if(write_cache_as_tree(&tree,0, NULL))1634die(_("git write-tree failed to write a tree"));16351636if(!get_oid_commit("HEAD", &parent)) {1637 old_oid = &parent;1638commit_list_insert(lookup_commit(&parent), &parents);1639}else{1640 old_oid = NULL;1641say(state, stderr,_("applying to an empty history"));1642}16431644 author =fmt_ident(state->author_name, state->author_email,1645 state->ignore_date ? NULL : state->author_date,1646 IDENT_STRICT);16471648if(state->committer_date_is_author_date)1649setenv("GIT_COMMITTER_DATE",1650 state->ignore_date ?"": state->author_date,1);16511652if(commit_tree(state->msg, state->msg_len, &tree, parents, &commit,1653 author, state->sign_commit))1654die(_("failed to write commit object"));16551656 reflog_msg =getenv("GIT_REFLOG_ACTION");1657if(!reflog_msg)1658 reflog_msg ="am";16591660strbuf_addf(&sb,"%s: %.*s", reflog_msg,linelen(state->msg),1661 state->msg);16621663update_ref(sb.buf,"HEAD", &commit, old_oid,0,1664 UPDATE_REFS_DIE_ON_ERR);16651666if(state->rebasing) {1667FILE*fp =xfopen(am_path(state,"rewritten"),"a");16681669assert(!is_null_oid(&state->orig_commit));1670fprintf(fp,"%s",oid_to_hex(&state->orig_commit));1671fprintf(fp,"%s\n",oid_to_hex(&commit));1672fclose(fp);1673}16741675run_hook_le(NULL,"post-applypatch", NULL);16761677strbuf_release(&sb);1678}16791680/**1681 * Validates the am_state for resuming -- the "msg" and authorship fields must1682 * be filled up.1683 */1684static voidvalidate_resume_state(const struct am_state *state)1685{1686if(!state->msg)1687die(_("cannot resume:%sdoes not exist."),1688am_path(state,"final-commit"));16891690if(!state->author_name || !state->author_email || !state->author_date)1691die(_("cannot resume:%sdoes not exist."),1692am_path(state,"author-script"));1693}16941695/**1696 * Interactively prompt the user on whether the current patch should be1697 * applied.1698 *1699 * Returns 0 if the user chooses to apply the patch, 1 if the user chooses to1700 * skip it.1701 */1702static intdo_interactive(struct am_state *state)1703{1704assert(state->msg);17051706if(!isatty(0))1707die(_("cannot be interactive without stdin connected to a terminal."));17081709for(;;) {1710const char*reply;17111712puts(_("Commit Body is:"));1713puts("--------------------------");1714printf("%s", state->msg);1715puts("--------------------------");17161717/*1718 * TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]1719 * in your translation. The program will only accept English1720 * input at this point.1721 */1722 reply =git_prompt(_("Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "), PROMPT_ECHO);17231724if(!reply) {1725continue;1726}else if(*reply =='y'|| *reply =='Y') {1727return0;1728}else if(*reply =='a'|| *reply =='A') {1729 state->interactive =0;1730return0;1731}else if(*reply =='n'|| *reply =='N') {1732return1;1733}else if(*reply =='e'|| *reply =='E') {1734struct strbuf msg = STRBUF_INIT;17351736if(!launch_editor(am_path(state,"final-commit"), &msg, NULL)) {1737free(state->msg);1738 state->msg =strbuf_detach(&msg, &state->msg_len);1739}1740strbuf_release(&msg);1741}else if(*reply =='v'|| *reply =='V') {1742const char*pager =git_pager(1);1743struct child_process cp = CHILD_PROCESS_INIT;17441745if(!pager)1746 pager ="cat";1747prepare_pager_args(&cp, pager);1748argv_array_push(&cp.args,am_path(state,"patch"));1749run_command(&cp);1750}1751}1752}17531754/**1755 * Applies all queued mail.1756 *1757 * If `resume` is true, we are "resuming". The "msg" and authorship fields, as1758 * well as the state directory's "patch" file is used as-is for applying the1759 * patch and committing it.1760 */1761static voidam_run(struct am_state *state,int resume)1762{1763const char*argv_gc_auto[] = {"gc","--auto", NULL};1764struct strbuf sb = STRBUF_INIT;17651766unlink(am_path(state,"dirtyindex"));17671768refresh_and_write_cache();17691770if(index_has_changes(&sb)) {1771write_state_bool(state,"dirtyindex",1);1772die(_("Dirty index: cannot apply patches (dirty:%s)"), sb.buf);1773}17741775strbuf_release(&sb);17761777while(state->cur <= state->last) {1778const char*mail =am_path(state,msgnum(state));1779int apply_status;17801781reset_ident_date();17821783if(!file_exists(mail))1784goto next;17851786if(resume) {1787validate_resume_state(state);1788}else{1789int skip;17901791if(state->rebasing)1792 skip =parse_mail_rebase(state, mail);1793else1794 skip =parse_mail(state, mail);17951796if(skip)1797goto next;/* mail should be skipped */17981799if(state->signoff)1800am_append_signoff(state);18011802write_author_script(state);1803write_commit_msg(state);1804}18051806if(state->interactive &&do_interactive(state))1807goto next;18081809if(run_applypatch_msg_hook(state))1810exit(1);18111812say(state, stdout,_("Applying: %.*s"),linelen(state->msg), state->msg);18131814 apply_status =run_apply(state, NULL);18151816if(apply_status && state->threeway) {1817struct strbuf sb = STRBUF_INIT;18181819strbuf_addstr(&sb,am_path(state,"patch-merge-index"));1820 apply_status =fall_back_threeway(state, sb.buf);1821strbuf_release(&sb);18221823/*1824 * Applying the patch to an earlier tree and merging1825 * the result may have produced the same tree as ours.1826 */1827if(!apply_status && !index_has_changes(NULL)) {1828say(state, stdout,_("No changes -- Patch already applied."));1829goto next;1830}1831}18321833if(apply_status) {1834int advice_amworkdir =1;18351836printf_ln(_("Patch failed at%s%.*s"),msgnum(state),1837linelen(state->msg), state->msg);18381839git_config_get_bool("advice.amworkdir", &advice_amworkdir);18401841if(advice_amworkdir)1842printf_ln(_("Use 'git am --show-current-patch' to see the failed patch"));18431844die_user_resolve(state);1845}18461847do_commit(state);18481849next:1850am_next(state);18511852if(resume)1853am_load(state);1854 resume =0;1855}18561857if(!is_empty_file(am_path(state,"rewritten"))) {1858assert(state->rebasing);1859copy_notes_for_rebase(state);1860run_post_rewrite_hook(state);1861}18621863/*1864 * In rebasing mode, it's up to the caller to take care of1865 * housekeeping.1866 */1867if(!state->rebasing) {1868am_destroy(state);1869close_all_packs(the_repository->objects);1870run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);1871}1872}18731874/**1875 * Resume the current am session after patch application failure. The user did1876 * all the hard work, and we do not have to do any patch application. Just1877 * trust and commit what the user has in the index and working tree.1878 */1879static voidam_resolve(struct am_state *state)1880{1881validate_resume_state(state);18821883say(state, stdout,_("Applying: %.*s"),linelen(state->msg), state->msg);18841885if(!index_has_changes(NULL)) {1886printf_ln(_("No changes - did you forget to use 'git add'?\n"1887"If there is nothing left to stage, chances are that something else\n"1888"already introduced the same changes; you might want to skip this patch."));1889die_user_resolve(state);1890}18911892if(unmerged_cache()) {1893printf_ln(_("You still have unmerged paths in your index.\n"1894"You should 'git add' each file with resolved conflicts to mark them as such.\n"1895"You might run `git rm` on a file to accept\"deleted by them\"for it."));1896die_user_resolve(state);1897}18981899if(state->interactive) {1900write_index_patch(state);1901if(do_interactive(state))1902goto next;1903}19041905rerere(0);19061907do_commit(state);19081909next:1910am_next(state);1911am_load(state);1912am_run(state,0);1913}19141915/**1916 * Performs a checkout fast-forward from `head` to `remote`. If `reset` is1917 * true, any unmerged entries will be discarded. Returns 0 on success, -1 on1918 * failure.1919 */1920static intfast_forward_to(struct tree *head,struct tree *remote,int reset)1921{1922struct lock_file lock_file = LOCK_INIT;1923struct unpack_trees_options opts;1924struct tree_desc t[2];19251926if(parse_tree(head) ||parse_tree(remote))1927return-1;19281929hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);19301931refresh_cache(REFRESH_QUIET);19321933memset(&opts,0,sizeof(opts));1934 opts.head_idx =1;1935 opts.src_index = &the_index;1936 opts.dst_index = &the_index;1937 opts.update =1;1938 opts.merge =1;1939 opts.reset = reset;1940 opts.fn = twoway_merge;1941init_tree_desc(&t[0], head->buffer, head->size);1942init_tree_desc(&t[1], remote->buffer, remote->size);19431944if(unpack_trees(2, t, &opts)) {1945rollback_lock_file(&lock_file);1946return-1;1947}19481949if(write_locked_index(&the_index, &lock_file, COMMIT_LOCK))1950die(_("unable to write new index file"));19511952return0;1953}19541955/**1956 * Merges a tree into the index. The index's stat info will take precedence1957 * over the merged tree's. Returns 0 on success, -1 on failure.1958 */1959static intmerge_tree(struct tree *tree)1960{1961struct lock_file lock_file = LOCK_INIT;1962struct unpack_trees_options opts;1963struct tree_desc t[1];19641965if(parse_tree(tree))1966return-1;19671968hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);19691970memset(&opts,0,sizeof(opts));1971 opts.head_idx =1;1972 opts.src_index = &the_index;1973 opts.dst_index = &the_index;1974 opts.merge =1;1975 opts.fn = oneway_merge;1976init_tree_desc(&t[0], tree->buffer, tree->size);19771978if(unpack_trees(1, t, &opts)) {1979rollback_lock_file(&lock_file);1980return-1;1981}19821983if(write_locked_index(&the_index, &lock_file, COMMIT_LOCK))1984die(_("unable to write new index file"));19851986return0;1987}19881989/**1990 * Clean the index without touching entries that are not modified between1991 * `head` and `remote`.1992 */1993static intclean_index(const struct object_id *head,const struct object_id *remote)1994{1995struct tree *head_tree, *remote_tree, *index_tree;1996struct object_id index;19971998 head_tree =parse_tree_indirect(head);1999if(!head_tree)2000returnerror(_("Could not parse object '%s'."),oid_to_hex(head));20012002 remote_tree =parse_tree_indirect(remote);2003if(!remote_tree)2004returnerror(_("Could not parse object '%s'."),oid_to_hex(remote));20052006read_cache_unmerged();20072008if(fast_forward_to(head_tree, head_tree,1))2009return-1;20102011if(write_cache_as_tree(&index,0, NULL))2012return-1;20132014 index_tree =parse_tree_indirect(&index);2015if(!index_tree)2016returnerror(_("Could not parse object '%s'."),oid_to_hex(&index));20172018if(fast_forward_to(index_tree, remote_tree,0))2019return-1;20202021if(merge_tree(remote_tree))2022return-1;20232024remove_branch_state();20252026return0;2027}20282029/**2030 * Resets rerere's merge resolution metadata.2031 */2032static voidam_rerere_clear(void)2033{2034struct string_list merge_rr = STRING_LIST_INIT_DUP;2035rerere_clear(&merge_rr);2036string_list_clear(&merge_rr,1);2037}20382039/**2040 * Resume the current am session by skipping the current patch.2041 */2042static voidam_skip(struct am_state *state)2043{2044struct object_id head;20452046am_rerere_clear();20472048if(get_oid("HEAD", &head))2049oidcpy(&head, the_hash_algo->empty_tree);20502051if(clean_index(&head, &head))2052die(_("failed to clean index"));20532054am_next(state);2055am_load(state);2056am_run(state,0);2057}20582059/**2060 * Returns true if it is safe to reset HEAD to the ORIG_HEAD, false otherwise.2061 *2062 * It is not safe to reset HEAD when:2063 * 1. git-am previously failed because the index was dirty.2064 * 2. HEAD has moved since git-am previously failed.2065 */2066static intsafe_to_abort(const struct am_state *state)2067{2068struct strbuf sb = STRBUF_INIT;2069struct object_id abort_safety, head;20702071if(file_exists(am_path(state,"dirtyindex")))2072return0;20732074if(read_state_file(&sb, state,"abort-safety",1) >0) {2075if(get_oid_hex(sb.buf, &abort_safety))2076die(_("could not parse%s"),am_path(state,"abort-safety"));2077}else2078oidclr(&abort_safety);2079strbuf_release(&sb);20802081if(get_oid("HEAD", &head))2082oidclr(&head);20832084if(!oidcmp(&head, &abort_safety))2085return1;20862087warning(_("You seem to have moved HEAD since the last 'am' failure.\n"2088"Not rewinding to ORIG_HEAD"));20892090return0;2091}20922093/**2094 * Aborts the current am session if it is safe to do so.2095 */2096static voidam_abort(struct am_state *state)2097{2098struct object_id curr_head, orig_head;2099int has_curr_head, has_orig_head;2100char*curr_branch;21012102if(!safe_to_abort(state)) {2103am_destroy(state);2104return;2105}21062107am_rerere_clear();21082109 curr_branch =resolve_refdup("HEAD",0, &curr_head, NULL);2110 has_curr_head = curr_branch && !is_null_oid(&curr_head);2111if(!has_curr_head)2112oidcpy(&curr_head, the_hash_algo->empty_tree);21132114 has_orig_head = !get_oid("ORIG_HEAD", &orig_head);2115if(!has_orig_head)2116oidcpy(&orig_head, the_hash_algo->empty_tree);21172118clean_index(&curr_head, &orig_head);21192120if(has_orig_head)2121update_ref("am --abort","HEAD", &orig_head,2122 has_curr_head ? &curr_head : NULL,0,2123 UPDATE_REFS_DIE_ON_ERR);2124else if(curr_branch)2125delete_ref(NULL, curr_branch, NULL, REF_NO_DEREF);21262127free(curr_branch);2128am_destroy(state);2129}21302131static intshow_patch(struct am_state *state)2132{2133struct strbuf sb = STRBUF_INIT;2134const char*patch_path;2135int len;21362137if(!is_null_oid(&state->orig_commit)) {2138const char*av[4] = {"show", NULL,"--", NULL };2139char*new_oid_str;2140int ret;21412142 av[1] = new_oid_str =xstrdup(oid_to_hex(&state->orig_commit));2143 ret =run_command_v_opt(av, RUN_GIT_CMD);2144free(new_oid_str);2145return ret;2146}21472148 patch_path =am_path(state,msgnum(state));2149 len =strbuf_read_file(&sb, patch_path,0);2150if(len <0)2151die_errno(_("failed to read '%s'"), patch_path);21522153setup_pager();2154write_in_full(1, sb.buf, sb.len);2155strbuf_release(&sb);2156return0;2157}21582159/**2160 * parse_options() callback that validates and sets opt->value to the2161 * PATCH_FORMAT_* enum value corresponding to `arg`.2162 */2163static intparse_opt_patchformat(const struct option *opt,const char*arg,int unset)2164{2165int*opt_value = opt->value;21662167if(!strcmp(arg,"mbox"))2168*opt_value = PATCH_FORMAT_MBOX;2169else if(!strcmp(arg,"stgit"))2170*opt_value = PATCH_FORMAT_STGIT;2171else if(!strcmp(arg,"stgit-series"))2172*opt_value = PATCH_FORMAT_STGIT_SERIES;2173else if(!strcmp(arg,"hg"))2174*opt_value = PATCH_FORMAT_HG;2175else if(!strcmp(arg,"mboxrd"))2176*opt_value = PATCH_FORMAT_MBOXRD;2177else2178returnerror(_("Invalid value for --patch-format:%s"), arg);2179return0;2180}21812182enum resume_mode {2183 RESUME_FALSE =0,2184 RESUME_APPLY,2185 RESUME_RESOLVED,2186 RESUME_SKIP,2187 RESUME_ABORT,2188 RESUME_QUIT,2189 RESUME_SHOW_PATCH2190};21912192static intgit_am_config(const char*k,const char*v,void*cb)2193{2194int status;21952196 status =git_gpg_config(k, v, NULL);2197if(status)2198return status;21992200returngit_default_config(k, v, NULL);2201}22022203intcmd_am(int argc,const char**argv,const char*prefix)2204{2205struct am_state state;2206int binary = -1;2207int keep_cr = -1;2208int patch_format = PATCH_FORMAT_UNKNOWN;2209enum resume_mode resume = RESUME_FALSE;2210int in_progress;2211int ret =0;22122213const char*const usage[] = {2214N_("git am [<options>] [(<mbox> | <Maildir>)...]"),2215N_("git am [<options>] (--continue | --skip | --abort)"),2216 NULL2217};22182219struct option options[] = {2220OPT_BOOL('i',"interactive", &state.interactive,2221N_("run interactively")),2222OPT_HIDDEN_BOOL('b',"binary", &binary,2223N_("historical option -- no-op")),2224OPT_BOOL('3',"3way", &state.threeway,2225N_("allow fall back on 3way merging if needed")),2226OPT__QUIET(&state.quiet,N_("be quiet")),2227OPT_SET_INT('s',"signoff", &state.signoff,2228N_("add a Signed-off-by line to the commit message"),2229 SIGNOFF_EXPLICIT),2230OPT_BOOL('u',"utf8", &state.utf8,2231N_("recode into utf8 (default)")),2232OPT_SET_INT('k',"keep", &state.keep,2233N_("pass -k flag to git-mailinfo"), KEEP_TRUE),2234OPT_SET_INT(0,"keep-non-patch", &state.keep,2235N_("pass -b flag to git-mailinfo"), KEEP_NON_PATCH),2236OPT_BOOL('m',"message-id", &state.message_id,2237N_("pass -m flag to git-mailinfo")),2238OPT_SET_INT_F(0,"keep-cr", &keep_cr,2239N_("pass --keep-cr flag to git-mailsplit for mbox format"),22401, PARSE_OPT_NONEG),2241OPT_SET_INT_F(0,"no-keep-cr", &keep_cr,2242N_("do not pass --keep-cr flag to git-mailsplit independent of am.keepcr"),22430, PARSE_OPT_NONEG),2244OPT_BOOL('c',"scissors", &state.scissors,2245N_("strip everything before a scissors line")),2246OPT_PASSTHRU_ARGV(0,"whitespace", &state.git_apply_opts,N_("action"),2247N_("pass it through git-apply"),22480),2249OPT_PASSTHRU_ARGV(0,"ignore-space-change", &state.git_apply_opts, NULL,2250N_("pass it through git-apply"),2251 PARSE_OPT_NOARG),2252OPT_PASSTHRU_ARGV(0,"ignore-whitespace", &state.git_apply_opts, NULL,2253N_("pass it through git-apply"),2254 PARSE_OPT_NOARG),2255OPT_PASSTHRU_ARGV(0,"directory", &state.git_apply_opts,N_("root"),2256N_("pass it through git-apply"),22570),2258OPT_PASSTHRU_ARGV(0,"exclude", &state.git_apply_opts,N_("path"),2259N_("pass it through git-apply"),22600),2261OPT_PASSTHRU_ARGV(0,"include", &state.git_apply_opts,N_("path"),2262N_("pass it through git-apply"),22630),2264OPT_PASSTHRU_ARGV('C', NULL, &state.git_apply_opts,N_("n"),2265N_("pass it through git-apply"),22660),2267OPT_PASSTHRU_ARGV('p', NULL, &state.git_apply_opts,N_("num"),2268N_("pass it through git-apply"),22690),2270OPT_CALLBACK(0,"patch-format", &patch_format,N_("format"),2271N_("format the patch(es) are in"),2272 parse_opt_patchformat),2273OPT_PASSTHRU_ARGV(0,"reject", &state.git_apply_opts, NULL,2274N_("pass it through git-apply"),2275 PARSE_OPT_NOARG),2276OPT_STRING(0,"resolvemsg", &state.resolvemsg, NULL,2277N_("override error message when patch failure occurs")),2278OPT_CMDMODE(0,"continue", &resume,2279N_("continue applying patches after resolving a conflict"),2280 RESUME_RESOLVED),2281OPT_CMDMODE('r',"resolved", &resume,2282N_("synonyms for --continue"),2283 RESUME_RESOLVED),2284OPT_CMDMODE(0,"skip", &resume,2285N_("skip the current patch"),2286 RESUME_SKIP),2287OPT_CMDMODE(0,"abort", &resume,2288N_("restore the original branch and abort the patching operation."),2289 RESUME_ABORT),2290OPT_CMDMODE(0,"quit", &resume,2291N_("abort the patching operation but keep HEAD where it is."),2292 RESUME_QUIT),2293OPT_CMDMODE(0,"show-current-patch", &resume,2294N_("show the patch being applied."),2295 RESUME_SHOW_PATCH),2296OPT_BOOL(0,"committer-date-is-author-date",2297&state.committer_date_is_author_date,2298N_("lie about committer date")),2299OPT_BOOL(0,"ignore-date", &state.ignore_date,2300N_("use current timestamp for author date")),2301OPT_RERERE_AUTOUPDATE(&state.allow_rerere_autoupdate),2302{ OPTION_STRING,'S',"gpg-sign", &state.sign_commit,N_("key-id"),2303N_("GPG-sign commits"),2304 PARSE_OPT_OPTARG, NULL, (intptr_t)""},2305OPT_HIDDEN_BOOL(0,"rebasing", &state.rebasing,2306N_("(internal use for git-rebase)")),2307OPT_END()2308};23092310if(argc ==2&& !strcmp(argv[1],"-h"))2311usage_with_options(usage, options);23122313git_config(git_am_config, NULL);23142315am_state_init(&state);23162317 in_progress =am_in_progress(&state);2318if(in_progress)2319am_load(&state);23202321 argc =parse_options(argc, argv, prefix, options, usage,0);23222323if(binary >=0)2324fprintf_ln(stderr,_("The -b/--binary option has been a no-op for long time, and\n"2325"it will be removed. Please do not use it anymore."));23262327/* Ensure a valid committer ident can be constructed */2328git_committer_info(IDENT_STRICT);23292330if(read_index_preload(&the_index, NULL) <0)2331die(_("failed to read the index"));23322333if(in_progress) {2334/*2335 * Catch user error to feed us patches when there is a session2336 * in progress:2337 *2338 * 1. mbox path(s) are provided on the command-line.2339 * 2. stdin is not a tty: the user is trying to feed us a patch2340 * from standard input. This is somewhat unreliable -- stdin2341 * could be /dev/null for example and the caller did not2342 * intend to feed us a patch but wanted to continue2343 * unattended.2344 */2345if(argc || (resume == RESUME_FALSE && !isatty(0)))2346die(_("previous rebase directory%sstill exists but mbox given."),2347 state.dir);23482349if(resume == RESUME_FALSE)2350 resume = RESUME_APPLY;23512352if(state.signoff == SIGNOFF_EXPLICIT)2353am_append_signoff(&state);2354}else{2355struct argv_array paths = ARGV_ARRAY_INIT;2356int i;23572358/*2359 * Handle stray state directory in the independent-run case. In2360 * the --rebasing case, it is up to the caller to take care of2361 * stray directories.2362 */2363if(file_exists(state.dir) && !state.rebasing) {2364if(resume == RESUME_ABORT || resume == RESUME_QUIT) {2365am_destroy(&state);2366am_state_release(&state);2367return0;2368}23692370die(_("Stray%sdirectory found.\n"2371"Use\"git am --abort\"to remove it."),2372 state.dir);2373}23742375if(resume)2376die(_("Resolve operation not in progress, we are not resuming."));23772378for(i =0; i < argc; i++) {2379if(is_absolute_path(argv[i]) || !prefix)2380argv_array_push(&paths, argv[i]);2381else2382argv_array_push(&paths,mkpath("%s/%s", prefix, argv[i]));2383}23842385am_setup(&state, patch_format, paths.argv, keep_cr);23862387argv_array_clear(&paths);2388}23892390switch(resume) {2391case RESUME_FALSE:2392am_run(&state,0);2393break;2394case RESUME_APPLY:2395am_run(&state,1);2396break;2397case RESUME_RESOLVED:2398am_resolve(&state);2399break;2400case RESUME_SKIP:2401am_skip(&state);2402break;2403case RESUME_ABORT:2404am_abort(&state);2405break;2406case RESUME_QUIT:2407am_rerere_clear();2408am_destroy(&state);2409break;2410case RESUME_SHOW_PATCH:2411 ret =show_patch(&state);2412break;2413default:2414BUG("invalid resume value");2415}24162417am_state_release(&state);24182419return ret;2420}