{"thread":{"id":"22709","subject":"How to create patches for a merge?","startedAt":"2010-02-18T11:40:07Z","lastAt":"2010-02-20T17:39:10Z","messageCount":5,"participants":["Geoffrey Lee","Junio C Hamano","Jeff King","Clemens Buchacher"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"134951","messageId":"83d7aaa41002180340p2f9b7241h9c220b84ec5dd1d@mail.gmail.com","threadId":"22709","inReplyTo":null,"subject":"How to create patches for a merge?","fromName":"Geoffrey Lee","fromEmail":"geoffreyj.lee@gmail.com","sentAt":"2010-02-18T11:40:07Z","receivedAt":"2010-02-18T11:40:07Z","isPatch":false,"sender":{"key":"geoffreyj.lee@gmail.com","avatar":"https://gravatar.com/avatar/eda7290effb2fe936a54951db47d049adf71d6bd41b70c56dd9dedc8f3327c39?d=mp&s=160"},"body":"When I use \"git format-patch\", it doesn't seem to include merges. How\ncan I perform a merge and then e-mail it to someone as a set of\npatches?\n\nFor example, let's say that I merge two branches and perform another\ncommit on top of the merge:\n\ngit init\n\necho \"initial file\" > test.txt\ngit add test.txt\ngit commit -m \"Commit A\"\n\ngit checkout -b foo master\necho \"foo\" > test.txt\ngit commit -a -m \"Commit B\"\n\ngit checkout -b bar master\necho \"bar\" > test.txt\ngit commit -a -m \"Commit C\"\n\ngit merge foo\necho \"foobar\" > test.txt\ngit commit -a -m \"Commit M\"\n\necho \"2nd line\" >> test.txt\ngit commit -a -m \"Commit D\"\n\nThis creates the following tree:\n\n    B\n  /   \\\nA       M - D\n  \\   /\n    C\n\nNow I try to checkout the initial commit and replay the above changes:\n\ngit checkout -b replay master\ngit format-patch --stdout master..bar | git am -3\n\nThis produces a merge conflict. In this scenario, \"git format-patch\nmaster..bar\" only produces 3 patches, omitting \"Commit M\". How do I\ndeal with this?\n\n-Geoffrey Lee\n"},{"id":"134982","messageId":"7veikifm9m.fsf@alter.siamese.dyndns.org","threadId":"22709","inReplyTo":"83d7aaa41002180340p2f9b7241h9c220b84ec5dd1d@mail.gmail.com","subject":"Re: How to create patches for a merge?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-02-18T18:10:13Z","receivedAt":"2010-02-18T18:10:13Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Geoffrey Lee <geoffreyj.lee@gmail.com> writes:\n\n> This produces a merge conflict. In this scenario, \"git format-patch\n> master..bar\" only produces 3 patches, omitting \"Commit M\". How do I\n> deal with this?\n\nThere is no provision for communicating how a conflict is resolved over\npatches.  The answer to your \"How do I deal with *this*\" question would be\n\"It is up to you.\", if your \"*this*\" is \"I want to communicate this as a\npatch\".  The steps to deal with \"*this*\" may go like this:\n\n - Think what shape of patch you want to see in order to convey what\n   \"Commit M\" did to the recipient of your patch series.  First, try to\n   construct it, by hand if necessary, as a design of such a feature.\n\n - How would a recipient \"apply\" such a patch?  As commonly used \"patch\"\n   implementations, including \"git apply\", may not be able to read the\n   above format, and they would certainly not create a merge commit, so\n   you need to design the recieving side as well.\n\n - Then implement them ;-)\n\nThe best I think of offhand to reproduce\n\n     B---M---D\n    /   /\n   A---C\n\nmight go like this:\n\n (1) Emit diff between (A,B) as usual;\n\n (2) Emit diff between (A,C) as usual, but with additional information\n     usually not found in regular patches to help recipient that this\n     should be applied to the same commit as (1) is applied to;\n\n (3) Emit diff between (B,M) and (C,M), but make sure that they won't be\n     seen as a patch to be applied by ordinary \"patch\" programs to avoid\n     mistakes at the recipient side.  Include some way to tell the\n     recipient that these two \"patches\" need to be applied to the results\n     of applying (1) and (2), and that the result needs to be recorded as\n     a merge between them.\n\n (4) Emit D as usual;\n\nThen the recipient would start from something that resembles A (call it X)\nand do the following:\n\n (5) Apply (1); call that result B'\n\n       B'\n      /\n     X\n\n (6) Apply (2), following that additional insn to apply the patch to the\n     base of (5); call that result C'\n\n       B'\n      /\n     X---C'\n\n (7) Apply (B,M) half of (3) to B' and call it M'\n\n\n       B'..M'\n      /\n     X---C'\n\n (8) Apply (C,M) half of (3) to C' and call it M\"\n\n       B'--M' M\"\n      /      .\n     X------C'\n\n (9) If M' and M\" do not match (which can happen when A and X are majorly\n     different), merge them using X as their common ancestor, and resolve\n     conflicts as necessary, and call the result M'\".\n\n     If M' and M\" do match, be happy and call either of them M'\".\n\n         B'..M'..M'\"                B'..M'\"\n        /       .       or         /   . \n       /       M\"                 X---C'\n      /       .\n     X-------C'\n\n (10) Record M'\" as children of B' and C'.\n\n       B'--M'\"\n      /   /\n     X---C'\n\n (11) Apply (4); call that result D'\n\n        B'--M'\"-D'\n      /   /\n     X---C'\n\nand you are done.\n"},{"id":"135006","messageId":"20100218203738.GB8110@coredump.intra.peff.net","threadId":"22709","inReplyTo":"83d7aaa41002180340p2f9b7241h9c220b84ec5dd1d@mail.gmail.com","subject":"Re: How to create patches for a merge?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2010-02-18T20:37:38Z","receivedAt":"2010-02-18T20:37:38Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Feb 18, 2010 at 03:40:07AM -0800, Geoffrey Lee wrote:\n\n> When I use \"git format-patch\", it doesn't seem to include merges. How\n> can I perform a merge and then e-mail it to someone as a set of\n> patches?\n\nIs it important that it be patches, or simply that it go over email? In\nthe latter case, you can use \"git bundle\" to create a set of commits,\nincluding merges, and send them to the remote.\n\n-Peff\n"},{"id":"135068","messageId":"83d7aaa41002190225o3255248re1581a86e1346f28@mail.gmail.com","threadId":"22709","inReplyTo":"20100218203738.GB8110@coredump.intra.peff.net","subject":"Re: How to create patches for a merge?","fromName":"Geoffrey Lee","fromEmail":"geoffreyj.lee@gmail.com","sentAt":"2010-02-19T10:25:14Z","receivedAt":"2010-02-19T10:25:14Z","isPatch":false,"sender":{"key":"geoffreyj.lee@gmail.com","avatar":"https://gravatar.com/avatar/eda7290effb2fe936a54951db47d049adf71d6bd41b70c56dd9dedc8f3327c39?d=mp&s=160"},"body":"On Thu, Feb 18, 2010 at 12:37 PM, Jeff King <peff@peff.net> wrote:\n> On Thu, Feb 18, 2010 at 03:40:07AM -0800, Geoffrey Lee wrote:\n>\n>> When I use \"git format-patch\", it doesn't seem to include merges. How\n>> can I perform a merge and then e-mail it to someone as a set of\n>> patches?\n>\n> Is it important that it be patches, or simply that it go over email? In\n> the latter case, you can use \"git bundle\" to create a set of commits,\n> including merges, and send them to the remote.\n\nI was not aware of \"git bundle\". That does exactly what I need. Thanks!\n\n-Geoffrey Lee\n"},{"id":"135166","messageId":"20100220173910.GA4095@localhost","threadId":"22709","inReplyTo":"83d7aaa41002190225o3255248re1581a86e1346f28@mail.gmail.com","subject":"Re: How to create patches for a merge?","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2010-02-20T17:39:10Z","receivedAt":"2010-02-20T17:39:10Z","isPatch":false,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Fri, Feb 19, 2010 at 02:25:14AM -0800, Geoffrey Lee wrote:\n> On Thu, Feb 18, 2010 at 12:37 PM, Jeff King <peff@peff.net> wrote:\n> > On Thu, Feb 18, 2010 at 03:40:07AM -0800, Geoffrey Lee wrote:\n> >\n> >> When I use \"git format-patch\", it doesn't seem to include merges. How\n> >> can I perform a merge and then e-mail it to someone as a set of\n> >> patches?\n> >\n> > Is it important that it be patches, or simply that it go over email? In\n> > the latter case, you can use \"git bundle\" to create a set of commits,\n> > including merges, and send them to the remote.\n> \n> I was not aware of \"git bundle\". That does exactly what I need. Thanks!\n\nBelow is git-send-bdl, a small wrapper I use for git bundle. It creates\nbundles only for the commits which are not already known to the origin and\nmails them to a configured address. It requires mutt for sending emails (the\n-m option is just for show).  It should probably use sendmail. But maybe\nthis is still useful as a reference.\n\nHave fun,\nClemens\n---\n\n#!/bin/bash\n\nusage ()\n{\n\techo \"`basename $0`: [-t <address>] [-m <mailer>] [-r <remote>] [<repo>...]\" >&2\n\texit 1\n}\n\nif ! test -x `which getopt`\nthen\n\techo \"fatal: getopt required but not found\" >&2\n\texit 2\nfi\n\nOPT=`getopt -o et:m:r: -- \"$@\"`\ncode=$?\nif test $code -gt 0\nthen\n\tusage\n\texit 1\nfi\neval set -- \"$OPT\"\n\nmailer=${GIT_SEND_BDL_MAILER:-mutt}\nremote=origin\naddr=\nedit=\nwhile test \"$1\" != \"--\"\ndo\n\tcase \"$1\" in\n\t\t-r) remote=\"$2\"; shift;;\n\t\t-m) mailer=\"$2\"; shift;;\n\t\t-t) addr=\"$addr $2\"; shift;;\n\t\t-e) edit=YesPlease;;\n\t\t-h) usage;;\n\t\t*) echo \"unkown option: $1\" >&2; exit 2;;\n\tesac\n\tshift\ndone\nshift\n\nif test -z $addr\nthen\n\taddr=\"$GIT_SEND_BDL_TO\"\nfi\n\nif test $# -eq 0\nthen\n\tcdup=`git rev-parse --show-cdup 2>/dev/null`\n\tif test $? -gt 0\n\tthen\n\t\techo \"fatal: no repositories specified and none found\" >&2\n\t\tusage\n\tfi\n\tset -- \"$PWD/${cdup}\"\nfi\n\nif test -z \"$addr\"\nthen\n\techo \"fatal: no recipients specified\" >&2\n\tusage\nfi\n\nif ! test -x `which $mailer`\nthen\n\techo \"fatal: mailer not found: $mailer\" >&2\n\tusage\nfi\n\nbundle=()\nwhile test $# -gt 0\ndo\n\tpath=$1\n\tshift\n\tcd $path\n\tname=`basename \"$PWD\"`\n\techo \" * $name\"\n\ttarget=/tmp/${name}.git\n\tif ! git remote | grep -q \"^$remote\\$\"\n\tthen\n\t\techo error: unknown remote: $remote >&2\n\t\tcontinue\n\tfi\n\trefs=\"--branches\"\n\tremote_refs=`git show-ref | cut -f2 -d' ' | \\\n\t\t\tgrep ^refs/remotes/$remote/`\n\tif test -n \"$remote_refs\"\n\tthen\n\t\trefs=\"$refs --not $remote_refs\"\n\tfi\n\trefs=\"$refs --tags\"\n\tgit bundle create $target $refs\n\tcd - >/dev/null\n\tbundle[${#bundle[@]}]=$target\ndone\n\nattachments=\nfor i in ${bundle[@]}\ndo\n\tif test -f $i\n\tthen\n\t\tattachments=\"$attachments $i\"\n\tfi\ndone\n\nexec 3</dev/null\nif test -n \"$edit\"\nthen\n\texec 3<&0\nfi\n$mailer -s 'git bundles' -a $attachments -- $addr <&3\nret=$?\nexec 3<&-\nif test $ret -gt 0\nthen\n\techo \"fatal: mailer exited with status $ret\" >&2\n\texit 1\nfi\n\nrm -f ${bundle[@]}\n"}]}