{"thread":{"id":"2542","subject":"[PATCH 0/4] reworking git-rebase","startedAt":"2005-11-15T23:32:05Z","lastAt":"2005-11-17T10:57:51Z","messageCount":8,"participants":["Junio C Hamano","Sven Verdoolaege"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"11956","messageId":"7voe4lfpxm.fsf@assigned-by-dhcp.cox.net","threadId":"2542","inReplyTo":null,"subject":"[PATCH 0/4] reworking git-rebase","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-15T23:32:05Z","receivedAt":"2005-11-15T23:32:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The current rebase implementation finds commits in our tree but\nnot in the upstream tree using git-cherry, and tries to apply\nthem using git-cherry-pick (i.e. always use 3-way) one by one.\n\nWhich is fine, but when some of the changes do not apply\ncleanly, it punts, and punts badly.\n\nSuppose you have commits A-B-C-D-E since you forked from the\nupstream and submitted the changes for inclusion.  You fetch\nfrom upstream head U and find that B has been picked up.  You\nrun git-rebase to update your branch, which tries to apply\nchanges contained in A-C-D-E, in this order, but replaying of C\nfails, because the upstream got changes that touch the same area\nfrom elsewhere.\n\nNow what?\n\nIt notes that fact, and goes ahead to apply D and E, and at the\nvery end tells you to deal with C by hand.  Even if you somehow\nmanaged to replay C on top of the result, you would now end up\nwith ...-B-...-U-A-D-E-C.\n\nBreaking the order between B and others was the conscious\ndecision made by the upstream, so we would not worry about it,\nand even if it were worrisome, it is too late for us to fix now.\nWhat D and E do may well depend on having C applied before them,\nwhich is a problem for us.\n\nHere is a series requesting comments and testing.  I think this\nchange makes rebase easier to use when some of the changes do\nnot replay cleanly.  What it does is:\n\n - Instead of calling git-cherry-pick, it runs git-format-patch\n   on the unmerged commits git-cherry found, and feeds the\n   result to \"git-am --3way\".\n\n - To keep rebase working on a repository that manages binary\n   files, it adds a very limited support to handle \"binary\n   diffs\".\n\nIn the \"unapplicable patch in the middle\" case, this \"rebase\"\nworks like this:\n\n - A series of patches in e-mail form is created that records\n   what A-C-D-E do, and is fed to git-am.  This is stored in\n   .dotest/ directory, just like the case you tried to apply\n   them from your mailbox.  Your branch is rewound to the tip of\n   upstream U, and the original head is kept in .git/ORIG_HEAD,\n   so you could \"git reset --hard ORIG_HEAD\" in case the end\n   result is really messy.\n\n - Patch A applies cleanly.  This could either be a clean patch\n   application on top of rewound head (i.e. same as upstream\n   head), or git-am might have internally fell back on 3-way\n   (i.e.  it would have done the same thing as git-cherry-pick).\n   In either case, a rebased commit A is made on top of U.\n\n - Patch C does not apply.  git-am stops here, with conflicts to\n   be resolved in the working tree.  Yet-to-be-applied D and E\n   are still kept in .dotest/ directory at this point.  What the\n   user does is exactly the same as fixing up unapplicable patch\n   when running git-am:\n\n   - Resolve conflict just like any merge conflicts. \n\n   - \"git diff -p --full-index HEAD >.dotest/patch\" to pretend\n     as if you received a perfect, applicable patch.\n\n   - \"git reset --hard\", to pretend you have not tried to apply\n     that patch yet.\n\n   [Side note] I think the latter two steps can and should be\n   made into a short-hand to tell \"git-am\" that the conflicting\n   patch is resolved.  \"git-am --resolved\", perhaps?\n\n - Continue with \"git am --3way\".  This applies the fixed-up\n   patch so by definition it had better apply.  \"git am\" knows\n   the patch after the fixed-up one is D and then E; it applies\n   them, and you will get the changes from A-C-D-E commits on\n   top of U, in this order.\n\nI've been using this without noticing any problem, and as people\nmay know I do a lot of rebases.\n"},{"id":"11960","messageId":"7virutfpvc.fsf@assigned-by-dhcp.cox.net","threadId":"2542","inReplyTo":"7voe4lfpxm.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 1/4] Rewrite rebase to use git-format-patch piped to git-am.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-15T23:33:27Z","receivedAt":"2005-11-15T23:33:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This does not handle binary files yet, but a patch or two to\ngit-apply should solve that problem.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n git-rebase.sh |   71 ++++++++++++---------------------------------------------\n 1 files changed, 15 insertions(+), 56 deletions(-)\n\napplies-to: efad0bc70473bdc02b8ac6a5e5f001519f1d5dfa\nd64a7b926edfcebf9f5b116fedebd365e5c206f1\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex fa95009..56196e7 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -5,65 +5,24 @@\n \n . git-sh-setup || die \"Not a git archive.\"\n \n-usage=\"usage: $0 \"'<upstream> [<head>]\n-\n-Uses output from git-cherry to rebase local commits to the new head of\n-upstream tree.'\n-\n-case \"$#,$1\" in\n-1,*..*)\n-    upstream=$(expr \"$1\" : '\\(.*\\)\\.\\.') ours=$(expr \"$1\" : '.*\\.\\.\\(.*\\)$')\n-    set x \"$upstream\" \"$ours\"\n-    shift ;;\n-esac\n+# The other head is given\n+other=$(git-rev-parse --verify \"$1^0\") || exit\n \n+# The tree must be really really clean.\n git-update-index --refresh || exit\n+diff=$(git-diff-index --cached --name-status -r HEAD)\n+case \"$different\" in\n+?*)\techo \"$diff\"\n+\texit 1\n+\t;;\n+esac\n \n+# If the branch to rebase is given, first switch to it.\n case \"$#\" in\n-1) ours_symbolic=HEAD ;;\n-2) ours_symbolic=\"$2\" ;;\n-*) die \"$usage\" ;;\n+2)\n+\tgit-checkout \"$2\" || exit\n esac\n \n-upstream=`git-rev-parse --verify \"$1\"` &&\n-ours=`git-rev-parse --verify \"$ours_symbolic\"` || exit\n-different1=$(git-diff-index --name-only --cached \"$ours\") &&\n-different2=$(git-diff-index --name-only \"$ours\") &&\n-test \"$different1$different2\" = \"\" ||\n-die \"Your working tree does not match $ours_symbolic.\"\n-\n-git-read-tree -m -u $ours $upstream &&\n-new_head=$(git-rev-parse --verify \"$upstream^0\") &&\n-git-update-ref HEAD \"$new_head\" || exit\n-\n-tmp=.rebase-tmp$$\n-fail=$tmp-fail\n-trap \"rm -rf $tmp-*\" 1 2 3 15\n-\n->$fail\n-\n-git-cherry -v $upstream $ours |\n-while read sign commit msg\n-do\n-\tcase \"$sign\" in\n-\t-)\n-\t\techo >&2 \"* Already applied: $msg\"\n-\t\tcontinue ;;\n-\tesac\n-\techo >&2 \"* Applying: $msg\"\n-\tS=$(git-rev-parse --verify HEAD) &&\n-\tgit-cherry-pick --replay $commit || {\n-\t\techo >&2 \"* Not applying the patch and continuing.\"\n-\t\techo $commit >>$fail\n-\t\tgit-reset --hard $S\n-\t}\n-done\n-if test -s $fail\n-then\n-\techo >&2 Some commits could not be rebased, check by hand:\n-\tcat >&2 $fail\n-\techo >&2 \"(the same list of commits are found in $tmp)\"\n-\texit 1\n-else\n-\trm -f $fail\n-fi\n+# Rewind the head to \"$other\"\n+git-reset --hard \"$other\"\n+git-format-patch -k --stdout \"$other\" ORIG_HEAD | git am -3 -k\n---\n0.99.9.GIT\n"},{"id":"11959","messageId":"7vek5hfpuj.fsf@assigned-by-dhcp.cox.net","threadId":"2542","inReplyTo":"7voe4lfpxm.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 2/4] apply: allow-binary-replacement.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-15T23:33:56Z","receivedAt":"2005-11-15T23:33:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"A new option, --allow-binary-replacement, is introduced.\n\nWhen you feed a diff that records full SHA1 name of pre- and\npost-image blob on its index line to git-apply with this option,\nthe post-image blob replaces the path if what you have in the\nworking tree matches the pre-image _and_ post-image blob is\nalready available in the object directory.\n\nLater we _might_ want to enhance the diff output to also include\nthe full binary data of the post-image, to make this more\nuseful, but this is good enough for local rebasing application.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n Documentation/git-apply.txt |   13 +++++++-\n apply.c                     |   72 +++++++++++++++++++++++++++++++++++++++++--\n 2 files changed, 81 insertions(+), 4 deletions(-)\n\napplies-to: 4567363448244862ec2c6c8bd74fc09cd322f153\n0d534967c6850288e1a36eae364da700348a77fe\ndiff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt\nindex 6702a18..626e281 100644\n--- a/Documentation/git-apply.txt\n+++ b/Documentation/git-apply.txt\n@@ -8,7 +8,7 @@ git-apply - Apply patch on a git index f\n \n SYNOPSIS\n --------\n-'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [-z] [<patch>...]\n+'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [<patch>...]\n \n DESCRIPTION\n -----------\n@@ -79,6 +79,17 @@ OPTIONS\n \tthe result with this option, which would apply the\n \tdeletion part but not addition part.\n \n+--allow-binary-replacement::\n+\tWhen applying a patch, which is a git-enhanced patch\n+\tthat was prepared to record the pre- and post-image object\n+\tname in full, and the path being patched exactly matches\n+\tthe object the patch applies to (i.e. \"index\" line's\n+\tpre-image object name is what is in the working tree),\n+\tand the post-image object is available in the object\n+\tdatabase, use the post-image object as the patch\n+\tresult.  This allows binary files to be patched in a\n+\tvery limited way.\n+\n Author\n ------\n Written by Linus Torvalds <torvalds@osdl.org>\ndiff --git a/apply.c b/apply.c\nindex 590adc6..cb9a6c0 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -16,6 +16,7 @@\n //  --numstat does numeric diffstat, and doesn't actually apply\n //  --index-info shows the old and new index info for paths if available.\n //\n+static int allow_binary_replacement = 0;\n static int check_index = 0;\n static int write_index = 0;\n static int diffstat = 0;\n@@ -27,7 +28,7 @@ static int no_add = 0;\n static int show_index_info = 0;\n static int line_termination = '\\n';\n static const char apply_usage[] =\n-\"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [-z] <patch>...\";\n+\"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] <patch>...\";\n \n /*\n  * For \"diff-stat\" like behaviour, we keep track of the biggest change\n@@ -899,8 +900,12 @@ static int parse_chunk(char *buffer, uns\n \t\t\t    sizeof(binhdr)-1))\n \t\t\tpatch->is_binary = 1;\n \n-\t\tif (patch->is_binary && !apply && !check)\n-\t\t\t;\n+\t\tif (patch->is_binary) {\n+\t\t\tif ((!apply && !check) || allow_binary_replacement)\n+\t\t\t\t;\n+\t\t\telse\n+\t\t\t\tdie(\"binary patch at line %d; you might want to try --allow-binary-replacement?\", linenr);\n+\t\t}\n \t\telse\n \t\t\tdie(\"patch with only garbage at line %d\", linenr);\n \t}\n@@ -1156,6 +1161,63 @@ static int apply_fragments(struct buffer\n {\n \tstruct fragment *frag = patch->fragments;\n \n+\tif (patch->is_binary) {\n+\t\tunsigned char sha1[20];\n+\t\tconst char *name = patch->old_name ? patch->old_name : patch->new_name;\n+\n+\t\tif (!allow_binary_replacement)\n+\t\t\treturn error(\"cannot apply binary patch to '%s' without --allow-binary-replacement\", name);\n+\n+\t\t/* For safety, we require patch index line to contain\n+\t\t * full 40-byte textual SHA1 for old and new, at least for now.\n+\t\t */\n+\t\tif (strlen(patch->old_sha1_prefix) != 40 ||\n+\t\t    strlen(patch->new_sha1_prefix) != 40 ||\n+\t\t    get_sha1_hex(patch->old_sha1_prefix, sha1) ||\n+\t\t    get_sha1_hex(patch->new_sha1_prefix, sha1))\n+\t\t\treturn error(\"cannot apply binary patch to '%s' without full index line\", name);\n+\n+\t\tif (patch->old_name) {\n+\t\t\tunsigned char hdr[50];\n+\t\t\tint hdrlen;\n+\n+\t\t\t/* See if the old one matches what the patch\n+\t\t\t * applies to.\n+\t\t\t */\n+\t\t\twrite_sha1_file_prepare(desc->buffer, desc->size,\n+\t\t\t\t\t\t\"blob\", sha1, hdr, &hdrlen);\n+\t\t\tif (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))\n+\t\t\t\treturn error(\"the patch applies to '%s' (%s), which does not match the current contents.\", name, sha1_to_hex(sha1));\n+\t\t}\n+\t\telse {\n+\t\t\t/* Otherwise, the old one must be empty. */\n+\t\t\tif (desc->size)\n+\t\t\t\treturn error(\"the patch applies to an empty '%s' but it is not empty\", name);\n+\t\t}\n+\n+\t\t/* For now, we do not record post-image data in the patch,\n+\t\t * and require the object already present in the recipient's\n+\t\t * object database.\n+\t\t */\n+\t\tif (desc->buffer) {\n+\t\t\tfree(desc->buffer);\n+\t\t\tdesc->alloc = desc->size = 0;\n+\t\t}\n+\t\tget_sha1_hex(patch->new_sha1_prefix, sha1);\n+\n+\t\tif (memcmp(sha1, null_sha1, 20)) {\n+\t\t\tchar type[10];\n+\t\t\tunsigned long size;\n+\n+\t\t\tdesc->buffer = read_sha1_file(sha1, type, &size);\n+\t\t\tif (!desc->buffer)\n+\t\t\t\treturn error(\"the necessary postimage %s for '%s' does not exist\", patch->new_sha1_prefix, name);\n+\t\t\tdesc->alloc = desc->size = size;\n+\t\t}\n+\n+\t\treturn 0;\n+\t}\n+\n \twhile (frag) {\n \t\tif (apply_one_fragment(desc, frag) < 0)\n \t\t\treturn error(\"patch failed: %s:%ld\", patch->old_name, frag->oldpos);\n@@ -1723,6 +1785,10 @@ int main(int argc, char **argv)\n \t\t\tdiffstat = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--allow-binary-replacement\")) {\n+\t\t\tallow_binary_replacement = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"--numstat\")) {\n \t\t\tapply = 0;\n \t\t\tnumstat = 1;\n---\n0.99.9.GIT\n"},{"id":"11958","messageId":"7vacg5fpu7.fsf@assigned-by-dhcp.cox.net","threadId":"2542","inReplyTo":"7voe4lfpxm.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 3/4] diff: --full-index","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-15T23:34:08Z","receivedAt":"2005-11-15T23:34:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"A new option, --full-index, is introduced to diff family.  This\ncauses the full object name of pre- and post-images to appear on\nthe index line of patch formatted output, to be used in\nconjunction with --allow-binary-replacement option of git-apply.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n Documentation/diff-options.txt |    5 +++++\n diff.c                         |   14 ++++++++------\n diff.h                         |    4 +++-\n 3 files changed, 16 insertions(+), 7 deletions(-)\n\napplies-to: 87c089ccd1a4e2ea6284c1ac5e944efd5299f60e\n3c38f257b87e61f02e8bf49195eb5084652ff0f9\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 8eef86e..6b496ed 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -13,6 +13,11 @@\n --name-status::\n \tShow only names and status of changed files.\n \n+--full-index::\n+\tInstead of the first handful characters, show full\n+\tobject name of pre- and post-image blob on the \"index\"\n+\tline when generating a patch format output.\t\n+\n -B::\n \tBreak complete rewrite changes into pairs of delete and create.\n \ndiff --git a/diff.c b/diff.c\nindex ec94a96..8b7bb67 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -648,7 +648,7 @@ static void diff_fill_sha1_info(struct d\n \t\tmemset(one->sha1, 0, 20);\n }\n \n-static void run_diff(struct diff_filepair *p)\n+static void run_diff(struct diff_filepair *p, struct diff_options *o)\n {\n \tconst char *pgm = external_diff();\n \tchar msg[PATH_MAX*2+300], *xfrm_msg;\n@@ -711,11 +711,11 @@ static void run_diff(struct diff_filepai\n \n \tif (memcmp(one->sha1, two->sha1, 20)) {\n \t\tchar one_sha1[41];\n+\t\tconst char *index_fmt = o->full_index ? \"index %s..%s\" : \"index %.7s..%.7s\";\n \t\tmemcpy(one_sha1, sha1_to_hex(one->sha1), 41);\n \n \t\tlen += snprintf(msg + len, sizeof(msg) - len,\n-\t\t\t\t\"index %.7s..%.7s\", one_sha1,\n-\t\t\t\tsha1_to_hex(two->sha1));\n+\t\t\t\tindex_fmt, one_sha1, sha1_to_hex(two->sha1));\n \t\tif (one->mode == two->mode)\n \t\t\tlen += snprintf(msg + len, sizeof(msg) - len,\n \t\t\t\t\t\" %06o\", one->mode);\n@@ -789,6 +789,8 @@ int diff_opt_parse(struct diff_options *\n \t\toptions->line_termination = 0;\n \telse if (!strncmp(arg, \"-l\", 2))\n \t\toptions->rename_limit = strtoul(arg+2, NULL, 10);\n+\telse if (!strcmp(arg, \"--full-index\"))\n+\t\toptions->full_index = 1;\n \telse if (!strcmp(arg, \"--name-only\"))\n \t\toptions->output_format = DIFF_FORMAT_NAME;\n \telse if (!strcmp(arg, \"--name-status\"))\n@@ -1017,7 +1019,7 @@ int diff_unmodified_pair(struct diff_fil\n \treturn 0;\n }\n \n-static void diff_flush_patch(struct diff_filepair *p)\n+static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o)\n {\n \tif (diff_unmodified_pair(p))\n \t\treturn;\n@@ -1026,7 +1028,7 @@ static void diff_flush_patch(struct diff\n \t    (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))\n \t\treturn; /* no tree diffs in patch format */ \n \n-\trun_diff(p);\n+\trun_diff(p, o);\n }\n \n int diff_queue_is_empty(void)\n@@ -1158,7 +1160,7 @@ void diff_flush(struct diff_options *opt\n \t\t\tdie(\"internal error in diff-resolve-rename-copy\");\n \t\tswitch (diff_output_format) {\n \t\tcase DIFF_FORMAT_PATCH:\n-\t\t\tdiff_flush_patch(p);\n+\t\t\tdiff_flush_patch(p, options);\n \t\t\tbreak;\n \t\tcase DIFF_FORMAT_RAW:\n \t\tcase DIFF_FORMAT_NAME_STATUS:\ndiff --git a/diff.h b/diff.h\nindex 1259079..9b2e1e6 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -32,7 +32,8 @@ struct diff_options {\n \tconst char *orderfile;\n \tconst char *pickaxe;\n \tunsigned recursive:1,\n-\t\t tree_in_recursive:1;\n+\t\t tree_in_recursive:1,\n+\t\t full_index:1;\n \tint break_opt;\n \tint detect_rename;\n \tint find_copies_harder;\n@@ -96,6 +97,7 @@ extern void diffcore_std_no_resolve(stru\n \"  -u            synonym for -p.\\n\" \\\n \"  --name-only   show only names of changed files.\\n\" \\\n \"  --name-status show names and status of changed files.\\n\" \\\n+\"  --full-index  show full object name on index ines.\\n\" \\\n \"  -R            swap input file pairs.\\n\" \\\n \"  -B            detect complete rewrites.\\n\" \\\n \"  -M            detect renames.\\n\" \\\n---\n0.99.9.GIT\n"},{"id":"11957","messageId":"7v64qtfptx.fsf@assigned-by-dhcp.cox.net","threadId":"2542","inReplyTo":"7voe4lfpxm.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 4/4] rebase: make it usable for binary files as well.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-15T23:34:18Z","receivedAt":"2005-11-15T23:34:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Use git-format-patch --full-index to generate a patch, and feed\nthat to git-am that uses git-apply --allow-binary-replacement.\nThis way, rebase can be used to move development that contains\nbinary files as long as there is no need for file-level merges.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n git-am.sh     |    7 ++++---\n git-rebase.sh |    2 +-\n 2 files changed, 5 insertions(+), 4 deletions(-)\n\napplies-to: 349326f3647597dabf38d82e1c2806cef45060f7\n7f5bff7c3e5b1245e479fc13665641424dee9a41\ndiff --git a/git-am.sh b/git-am.sh\nindex 38841d9..8307d77 100755\n--- a/git-am.sh\n+++ b/git-am.sh\n@@ -46,7 +46,7 @@ fall_back_3way () {\n \t    cd \"$dotest/patch-merge-tmp-dir\" &&\n \t    GIT_INDEX_FILE=\"../patch-merge-tmp-index\" \\\n \t    GIT_OBJECT_DIRECTORY=\"$O_OBJECT\" \\\n-\t    git-apply --index <../patch\n+\t    git-apply --allow-binary-replacement --index <../patch\n         )\n     then\n \techo Using index info to reconstruct a base tree...\n@@ -77,7 +77,7 @@ fall_back_3way () {\n \t\tGIT_OBJECT_DIRECTORY=\"$O_OBJECT\" &&\n \t\texport GIT_INDEX_FILE GIT_OBJECT_DIRECTORY &&\n \t\tgit-read-tree \"$base\" &&\n-\t\tgit-apply --index &&\n+\t\tgit-apply --index --allow-binary-replacement &&\n \t\tmv ../patch-merge-tmp-index ../patch-merge-index &&\n \t\techo \"$base\" >../patch-merge-base\n \t    ) <\"$dotest/patch\"  2>/dev/null && break\n@@ -310,7 +310,8 @@ do\n \techo \"Applying '$SUBJECT'\"\n \techo\n \n-\tgit-apply --index \"$dotest/patch\"; apply_status=$?\n+\tgit-apply --allow-binary-replacement --index \"$dotest/patch\"\n+\tapply_status=$?\n \tif test $apply_status = 1 && test \"$threeway\" = t\n \tthen\n \t\tif (fall_back_3way)\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 56196e7..b8abf33 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -25,4 +25,4 @@ esac\n \n # Rewind the head to \"$other\"\n git-reset --hard \"$other\"\n-git-format-patch -k --stdout \"$other\" ORIG_HEAD | git am -3 -k\n+git-format-patch -k --stdout --full-index \"$other\" ORIG_HEAD | git am -3 -k\n---\n0.99.9.GIT\n"},{"id":"12005","messageId":"7v7jb99c4j.fsf@assigned-by-dhcp.cox.net","threadId":"2542","inReplyTo":"7voe4lfpxm.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] git-am: --resolved.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-16T09:26:52Z","receivedAt":"2005-11-16T09:26:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n>  - Patch C does not apply.  git-am stops here, with conflicts to\n>    be resolved in the working tree.  Yet-to-be-applied D and E\n>    are still kept in .dotest/ directory at this point.  What the\n>    user does is exactly the same as fixing up unapplicable patch\n>    when running git-am:\n>\n>    - Resolve conflict just like any merge conflicts. \n>\n>    - \"git diff -p --full-index HEAD >.dotest/patch\" to pretend\n>      as if you received a perfect, applicable patch.\n>\n>    - \"git reset --hard\", to pretend you have not tried to apply\n>      that patch yet.\n>\n>    [Side note] I think the latter two steps can and should be\n>    made into a short-hand to tell \"git-am\" that the conflicting\n>    patch is resolved.  \"git-am --resolved\", perhaps?\n\nIt turns out that the above \"diff >.dotest/patch && reset --hard\"\nwas unnecessary.  Instead, the above workflow would read:\n\n    - Resolve conflict just like any merge conflicts.\n\n    - Do necessary 'git-update-index' to prepare your index to\n      record the result of the patch application.\n\n    - \"git am --resolved\".\n\nWhat it does is just record the current index as tree, along\nwith the commit log message and authorship information taken\nfrom the e-mail.  No diff & patch is involved.  Oh, and you can\ndo this in a dirty working tree as long as your index is clean\nand dirty paths do not interfere with the patch application.\n\nThe patch I am posting here is against the tip of the master, if\nsomebody wants to try it out.  Proposed updates branch has an\nequivalent patch on top of the reworked rebase series.\n\n-- >8 --\nAfter failed patch application, you can manually apply the patch\n(this includes resolving the conflicted merge after git-am falls\nback to 3-way merge) and run git-update-index on necessary paths\nto prepare the index file in a shape a successful patch\napplication should have produced.  Then re-running git-am --resolved\nwould record the resulting index file along with the commit log\ninformation taken from the patch e-mail.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n git-am.sh |   65 ++++++++++++++++++++++++++++++++++++++++++++++++++-----------\n 1 files changed, 53 insertions(+), 12 deletions(-)\n\napplies-to: 1e3fcf60526c196a46433e6947c9104ca236f230\n3efc3e216c8a64fae53a15767064162ee431f57e\ndiff --git a/git-am.sh b/git-am.sh\nindex 38841d9..98a390a 100755\n--- a/git-am.sh\n+++ b/git-am.sh\n@@ -3,16 +3,10 @@\n #\n . git-sh-setup || die \"Not a git archive\"\n \n-files=$(git-diff-index --cached --name-only HEAD) || exit\n-if [ \"$files\" ]; then\n-   echo \"Dirty index: cannot apply patches (dirty: $files)\" >&2\n-   exit 1\n-fi\n-\n usage () {\n     echo >&2 \"usage: $0 [--signoff] [--dotest=<dir>] [--utf8] [--3way] <mbox>\"\n     echo >&2 \"\tor, when resuming\"\n-    echo >&2 \"\t$0 [--skip]\"\n+    echo >&2 \"\t$0 [--skip | --resolved]\"\n     exit 1;\n }\n \n@@ -104,7 +98,7 @@ fall_back_3way () {\n }\n \n prec=4\n-dotest=.dotest sign= utf8= keep= skip= interactive=\n+dotest=.dotest sign= utf8= keep= skip= interactive= resolved=\n \n while case \"$#\" in 0) break;; esac\n do\n@@ -128,6 +122,9 @@ do\n \t-k|--k|--ke|--kee|--keep)\n \tkeep=t; shift ;;\n \n+\t-r|--r|--re|--res|--reso|--resol|--resolv|--resolve|--resolved)\n+\tresolved=t; shift ;;\n+\n \t--sk|--ski|--skip)\n \tskip=t; shift ;;\n \n@@ -140,6 +137,8 @@ do\n \tesac\n done\n \n+# If the dotest directory exists, but we have finished applying all the\n+# patches in them, clear it out.\n if test -d \"$dotest\" &&\n    last=$(cat \"$dotest/last\") &&\n    next=$(cat \"$dotest/next\") &&\n@@ -155,9 +154,9 @@ then\n \tdie \"previous dotest directory $dotest still exists but mbox given.\"\n \tresume=yes\n else\n-\t# Make sure we are not given --skip\n-\ttest \",$skip,\" = ,, ||\n-\tdie \"we are not resuming.\"\n+\t# Make sure we are not given --skip nor --resolved\n+\ttest \",$skip,$resolved,\" = ,,, ||\n+\t\tdie \"we are not resuming.\"\n \n \t# Start afresh.\n \tmkdir -p \"$dotest\" || exit\n@@ -170,12 +169,24 @@ else\n \t\texit 1\n \t}\n \n+\t# -s, -u and -k flags are kept for the resuming session after\n+\t# a patch failure.\n+\t# -3 and -i can and must be given when resuming.\n \techo \"$sign\" >\"$dotest/sign\"\n \techo \"$utf8\" >\"$dotest/utf8\"\n \techo \"$keep\" >\"$dotest/keep\"\n \techo 1 >\"$dotest/next\"\n fi\n \n+case \"$resolved\" in\n+'')\n+\tfiles=$(git-diff-index --cached --name-only HEAD) || exit\n+\tif [ \"$files\" ]; then\n+\t   echo \"Dirty index: cannot apply patches (dirty: $files)\" >&2\n+\t   exit 1\n+\tfi\n+esac\n+\n if test \"$(cat \"$dotest/utf8\")\" = t\n then\n \tutf8=-u\n@@ -216,6 +227,15 @@ do\n \t\tgo_next\n \t\tcontinue\n \t}\n+\n+\t# If we are not resuming, parse and extract the patch information\n+\t# into separate files:\n+\t#  - info records the authorship and title\n+\t#  - msg is the rest of commit log message\n+\t#  - patch is the patch body.\n+\t#\n+\t# When we are resuming, these files are either already prepared\n+\t# by the user, or the user can tell us to do so by --resolved flag.\n \tcase \"$resume\" in\n \t'')\n \t\tgit-mailinfo $keep $utf8 \"$dotest/msg\" \"$dotest/patch\" \\\n@@ -263,6 +283,13 @@ do\n \t\tfi\n \t    } >\"$dotest/final-commit\"\n \t    ;;\n+\t*)\n+\t\tcase \"$resolved,$interactive\" in\n+\t\ttt)\n+\t\t\t# This is used only for interactive view option.\n+\t\t\tgit-diff-index -p --cached HEAD >\"$dotest/patch\"\n+\t\t\t;;\n+\t\tesac\n \tesac\n \n \tresume=\n@@ -310,7 +337,21 @@ do\n \techo \"Applying '$SUBJECT'\"\n \techo\n \n-\tgit-apply --index \"$dotest/patch\"; apply_status=$?\n+\tcase \"$resolved\" in\n+\t'')\n+\t\tgit-apply --index \"$dotest/patch\"\n+\t\tapply_status=$?\n+\t\t;;\n+\tt)\n+\t\t# Resolved means the user did all the hard work, and\n+\t\t# we do not have to do any patch application.  Just\n+\t\t# trust what the user has in the index file and the\n+\t\t# working tree.\n+\t\tresolved=\n+\t\tapply_status=0\n+\t\t;;\n+\tesac\n+\n \tif test $apply_status = 1 && test \"$threeway\" = t\n \tthen\n \t\tif (fall_back_3way)\n---\n0.99.9.GIT\n"},{"id":"12083","messageId":"20051117103027.GR8383MdfPADPa@greensroom.kotnet.org","threadId":"2542","inReplyTo":"7voe4lfpxm.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 0/4] reworking git-rebase","fromName":"Sven Verdoolaege","fromEmail":"skimo@kotnet.org","sentAt":"2005-11-17T10:30:27Z","receivedAt":"2005-11-17T10:30:27Z","isPatch":true,"sender":{"key":"skimo@kotnet.org","avatar":null},"body":"On Tue, Nov 15, 2005 at 03:32:05PM -0800, Junio C Hamano wrote:\n> It notes that fact, and goes ahead to apply D and E, and at the\n> very end tells you to deal with C by hand.  Even if you somehow\n> managed to replay C on top of the result, you would now end up\n> with ...-B-...-U-A-D-E-C.\n\nActually this is sometimes useful when rewriting history.\nSuppose you cherry-pick two changes that touch the same piece\nof code and combine them into a single change and then rebase\nall your changes on top of this combined change.\nThe two cherry-picked changes will not apply and end up and\nat the end of the chain where you can simply discard them.\n\nWill the reworked rebase still support this use or is there\na better way to do this ?\n\nskimo\n"},{"id":"12087","messageId":"7v1x1fy21c.fsf@assigned-by-dhcp.cox.net","threadId":"2542","inReplyTo":"20051117103027.GR8383MdfPADPa@greensroom.kotnet.org","subject":"Re: [PATCH 0/4] reworking git-rebase","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-17T10:57:51Z","receivedAt":"2005-11-17T10:57:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sven Verdoolaege <skimo@kotnet.org> writes:\n\n> Will the reworked rebase still support this use or is there\n> a better way to do this ?\n\nI think it is reasonable to assume that you would not usually\nwant to muck with commits that cleanly replay.  Further, you\nwould do that kind of irregular replaying (e.g. not replaying\nall of them, or skipping some of them) only after one of the\ncommit fails to cleanly replay, and you would not mind (rather,\nyou would be happy) to keep the commits that have been already\ncleanly replayed, and would start playing games like dropping\npatches after the one that fails.\n\nIf the above is a reasonable assumption, then, the answer is\nyes.  And if not, you can always resort to manual\n\"git-format-patch -k\", followed by file editing, followed by\n\"git am -k -3\", to reorder patches.  Although at that point you\nshould either be looking at StGIT or doing a just plain merge.\n\nWhen \"git am\" first fails, all the rest of patches are kept in\n.dotest/.  And after fixing up the failed one in your working\ntree, you can restart it with interactive flag, like this: \"git\nam -i -3 --resolved\".  It lets you tell it skip one patch, or\nnot apply any of the rest.  [Side note: it might be a good idea\nto make --resolved imply --interactive].\n\nQuite often, the reason why a rebased patch does not apply is\nbecause an equivalent patch (or a set of patches whose\ncumulative effect is the same as one of your patches) has been\nthrown in to the new \"master\".  \"git cherry\" is too dumb (IOW,\ngit-patch-id is too strict) to notice such cases.  \"git am -3\"\nfirst tries to do git-apply, and when it fails (and it will fail\nif your working tree already has what the patch would do), it\nfalls back to 3-way merge by picking up the pre-image blob ids\nrecorded in the patch.  When seeing an already applied patch,\nthis 3-way merge often results in the same tree as you started.\nWhen \"git am\" notices the situation, it throws away that patch\n(it says \"already applied\") automatically.\n"}]}