{"thread":{"id":"39111","subject":"[BUG] \"git pull\" will regress between 'master' and 'pu'","startedAt":"2015-04-19T01:39:20Z","lastAt":"2015-05-03T01:57:30Z","messageCount":42,"participants":["Junio C Hamano","Jeff King","brian m. carlson","Johannes Schindelin","Paul Tan"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"259639","messageId":"xmqqbnikoq0n.fsf@gitster.dls.corp.google.com","threadId":"39111","inReplyTo":null,"subject":"[BUG] \"git pull\" will regress between 'master' and 'pu'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-19T01:39:20Z","receivedAt":"2015-04-19T01:39:20Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is primarily note-to-self; even though I haven't got around\nbisecting yet, I think I know I did some bad change myself.\n\n\"git pull $URL $tag\" seems to:\n\n * fail to invoke the editor without \"--edit\".\n * show the summary merge log message twice.\n"},{"id":"259647","messageId":"20150419130745.GA20476@peff.net","threadId":"39111","inReplyTo":"xmqqbnikoq0n.fsf@gitster.dls.corp.google.com","subject":"Re: [BUG] \"git pull\" will regress between 'master' and 'pu'","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-04-19T13:07:46Z","receivedAt":"2015-04-19T13:07:46Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Apr 18, 2015 at 06:39:20PM -0700, Junio C Hamano wrote:\n\n> This is primarily note-to-self; even though I haven't got around\n> bisecting yet, I think I know I did some bad change myself.\n> \n> \"git pull $URL $tag\" seems to:\n> \n>  * fail to invoke the editor without \"--edit\".\n>  * show the summary merge log message twice.\n\nI think that \"git merge -m $msg $commit\" is not quite the same as \"git\nmerge $msg HEAD $commit\".\n\nThe former suppresses the editor. This makes sense, as it's consistent\nwith \"commit -m\", etc. You can override that with \"--edit\".\n\nBut the latter also respects merge.log. Which also makes sense, because\nthe contents of \"-m\" are generally user-created, not the output of\nfmt-merge-msg. So it is merge's job to format the content appropriately.\n\nIt is tempting to \"solve\" both by dropping the call to git-fmt-merge-msg\nright before calling git-merge. Then \"git-merge\" will call fmt-merge-msg\nitself. However, we feed it only the sha1 of the merge-head, whereas our\nfmt-merge-msg call gets to see FETCH_HEAD. So we would lose the nice\n\"Merge tag 'v1.0' of git://...\" part of the message. Instead we get\n\"Merge tag '1234abcd'\".\n\nSo this is _almost_ enough:\n\ndiff --git a/git-pull.sh b/git-pull.sh\nindex 252969e..63493ee 100755\n--- a/git-pull.sh\n+++ b/git-pull.sh\n@@ -323,7 +323,7 @@ then\n \tfi\n fi\n \n-merge_name=$(git fmt-merge-msg $log_arg <\"$GIT_DIR/FETCH_HEAD\") || exit\n+merge_name=$(git fmt-merge-msg --no-log <\"$GIT_DIR/FETCH_HEAD\") || exit\n case \"$rebase\" in\n true)\n \teval=\"git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity\"\n@@ -334,7 +334,7 @@ true)\n \teval=\"git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only\"\n \teval=\"$eval $log_arg $strategy_args $merge_args $verbosity $progress\"\n \teval=\"$eval $gpg_sign_args\"\n-\teval=\"$eval -m \\\"\\$merge_name\\\" $merge_head\"\n+\teval=\"$eval --edit -m \\\"\\$merge_name\\\" $merge_head\"\n \t;;\n esac\n eval \"exec $eval\"\n\nBut that is starting to feel pretty hacky.  Moreover, both fmt-merge-msg\nand \"merge -m\" will verify the tag signature and output the tag message.\nI don't see a way to suppress that. So it really would be nice to be\nable to just drop the extra fmt-merge-msg call and have git-merge do it\nall internally, which would mean telling it to use FETCH_HEAD and not\n$merge_name.\n\nWhich I guess is just:\n\ndiff --git a/git-pull.sh b/git-pull.sh\nindex 252969e..15d9431 100755\n--- a/git-pull.sh\n+++ b/git-pull.sh\n@@ -323,7 +323,6 @@ then\n \tfi\n fi\n \n-merge_name=$(git fmt-merge-msg $log_arg <\"$GIT_DIR/FETCH_HEAD\") || exit\n case \"$rebase\" in\n true)\n \teval=\"git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity\"\n@@ -334,7 +333,7 @@ true)\n \teval=\"git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only\"\n \teval=\"$eval $log_arg $strategy_args $merge_args $verbosity $progress\"\n \teval=\"$eval $gpg_sign_args\"\n-\teval=\"$eval -m \\\"\\$merge_name\\\" $merge_head\"\n+\teval=\"$eval FETCH_HEAD\"\n \t;;\n esac\n eval \"exec $eval\"\n\nas we seem to special-case the name FETCH_HEAD. It assumes that\ngit-merge's parsing of FETCH_HEAD is the same as what we do in git-pull,\nbut that seems safe. Unfortunately we still have to compute $merge_head\nourselves here for the \"git pull --rebase\" case.\n\n-Peff\n"},{"id":"259650","messageId":"20150419173825.GD652025@vauxhall.crustytoothpaste.net","threadId":"39111","inReplyTo":"20150419130745.GA20476@peff.net","subject":"Re: [BUG] \"git pull\" will regress between 'master' and 'pu'","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2015-04-19T17:38:26Z","receivedAt":"2015-04-19T17:38:26Z","isPatch":false,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On Sun, Apr 19, 2015 at 09:07:46AM -0400, Jeff King wrote:\n> Which I guess is just:\n> \n> diff --git a/git-pull.sh b/git-pull.sh\n> index 252969e..15d9431 100755\n> --- a/git-pull.sh\n> +++ b/git-pull.sh\n> @@ -323,7 +323,6 @@ then\n>  \tfi\n>  fi\n>  \n> -merge_name=$(git fmt-merge-msg $log_arg <\"$GIT_DIR/FETCH_HEAD\") || exit\n>  case \"$rebase\" in\n>  true)\n>  \teval=\"git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity\"\n> @@ -334,7 +333,7 @@ true)\n>  \teval=\"git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only\"\n>  \teval=\"$eval $log_arg $strategy_args $merge_args $verbosity $progress\"\n>  \teval=\"$eval $gpg_sign_args\"\n> -\teval=\"$eval -m \\\"\\$merge_name\\\" $merge_head\"\n> +\teval=\"$eval FETCH_HEAD\"\n>  \t;;\n>  esac\n>  eval \"exec $eval\"\n> \n> as we seem to special-case the name FETCH_HEAD. It assumes that\n> git-merge's parsing of FETCH_HEAD is the same as what we do in git-pull,\n> but that seems safe. Unfortunately we still have to compute $merge_head\n> ourselves here for the \"git pull --rebase\" case.\n\nI agree that this is a better choice.  My concern with your other\nsuggestion is that it looks like it wouldn't honor the --no-edit flag or\nGIT_MERGE_AUTOEDIT=no.  That might break some use cases, such as\nnon-interactive applications.\n-- \nbrian m. carlson / brian with sandals: Houston, Texas, US\n+1 832 623 2791 | http://www.crustytoothpaste.net/~bmc | My opinion only\nOpenPGP: RSA v4 4096b: 88AC E9B2 9196 305B A994 7552 F1BA 225C 0223 B187\n"},{"id":"259651","messageId":"20150419181900.GA25649@peff.net","threadId":"39111","inReplyTo":"20150419173825.GD652025@vauxhall.crustytoothpaste.net","subject":"Re: [BUG] \"git pull\" will regress between 'master' and 'pu'","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-04-19T18:19:00Z","receivedAt":"2015-04-19T18:19:00Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Apr 19, 2015 at 05:38:26PM +0000, brian m. carlson wrote:\n\n> >  \teval=\"git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity\"\n> > @@ -334,7 +333,7 @@ true)\n> >  \teval=\"git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only\"\n> >  \teval=\"$eval $log_arg $strategy_args $merge_args $verbosity $progress\"\n> >  \teval=\"$eval $gpg_sign_args\"\n> > -\teval=\"$eval -m \\\"\\$merge_name\\\" $merge_head\"\n> > +\teval=\"$eval FETCH_HEAD\"\n> >  \t;;\n> >  esac\n> >  eval \"exec $eval\"\n> > \n> > as we seem to special-case the name FETCH_HEAD. It assumes that\n> > git-merge's parsing of FETCH_HEAD is the same as what we do in git-pull,\n> > but that seems safe. Unfortunately we still have to compute $merge_head\n> > ourselves here for the \"git pull --rebase\" case.\n> \n> I agree that this is a better choice.  My concern with your other\n> suggestion is that it looks like it wouldn't honor the --no-edit flag or\n> GIT_MERGE_AUTOEDIT=no.  That might break some use cases, such as\n> non-interactive applications.\n\nYeah, you're right. I think you could work around it by munging the\n$edit variable as appropriate. But the whole thing is still gross. We\nshould be able to convince \"git merge\" to do the fmt-merge-msg bit for\nus, and if not, then I think it needs to be extended.\n\n-Peff\n"},{"id":"259694","messageId":"xmqqmw22lj7r.fsf@gitster.dls.corp.google.com","threadId":"39111","inReplyTo":"20150419130745.GA20476@peff.net","subject":"Re: [BUG] \"git pull\" will regress between 'master' and 'pu'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-20T18:59:04Z","receivedAt":"2015-04-20T18:59:04Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> @@ -334,7 +333,7 @@ true)\n>  \teval=\"git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only\"\n>  \teval=\"$eval $log_arg $strategy_args $merge_args $verbosity $progress\"\n>  \teval=\"$eval $gpg_sign_args\"\n> -\teval=\"$eval -m \\\"\\$merge_name\\\" $merge_head\"\n> +\teval=\"$eval FETCH_HEAD\"\n>  \t;;\n>  esac\n>  eval \"exec $eval\"\n>\n> as we seem to special-case the name FETCH_HEAD. It assumes that\n> git-merge's parsing of FETCH_HEAD is the same as what we do in git-pull,\n> but that seems safe.\n\nUnfortunately, \"git merge\"'s parsing of FETCH_HEAD forgets that we\nmay be creating an Octopus.  Otherwise the above should work well.\n\n> Unfortunately we still have to compute $merge_head ourselves here\n> for the \"git pull --rebase\" case.\n\nThat is not that unfortunate, I would say.\n"},{"id":"259695","messageId":"20150420191041.GA14362@peff.net","threadId":"39111","inReplyTo":"xmqqmw22lj7r.fsf@gitster.dls.corp.google.com","subject":"Re: [BUG] \"git pull\" will regress between 'master' and 'pu'","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-04-20T19:10:41Z","receivedAt":"2015-04-20T19:10:41Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Apr 20, 2015 at 11:59:04AM -0700, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > @@ -334,7 +333,7 @@ true)\n> >  \teval=\"git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only\"\n> >  \teval=\"$eval $log_arg $strategy_args $merge_args $verbosity $progress\"\n> >  \teval=\"$eval $gpg_sign_args\"\n> > -\teval=\"$eval -m \\\"\\$merge_name\\\" $merge_head\"\n> > +\teval=\"$eval FETCH_HEAD\"\n> >  \t;;\n> >  esac\n> >  eval \"exec $eval\"\n> >\n> > as we seem to special-case the name FETCH_HEAD. It assumes that\n> > git-merge's parsing of FETCH_HEAD is the same as what we do in git-pull,\n> > but that seems safe.\n> \n> Unfortunately, \"git merge\"'s parsing of FETCH_HEAD forgets that we\n> may be creating an Octopus.  Otherwise the above should work well.\n\nThat sounds like a bug we should fix regardless.\n\n> > Unfortunately we still have to compute $merge_head ourselves here\n> > for the \"git pull --rebase\" case.\n> \n> That is not that unfortunate, I would say.\n\nI guess not. It is only a few lines of sed. And having the details there\ndoes let us customize the error cases. My main worry would just be a\nmaintenance one: that somebody modifies git-pull to calculate merge_head\ndifferently, but it turns out that we ignore it when calling git-merge.\nBut that's probably not that likely to matter in practice.\n\n-Peff\n"},{"id":"259697","messageId":"xmqqiocqli1c.fsf@gitster.dls.corp.google.com","threadId":"39111","inReplyTo":"20150420191041.GA14362@peff.net","subject":"Re: [BUG] \"git pull\" will regress between 'master' and 'pu'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-20T19:24:31Z","receivedAt":"2015-04-20T19:24:31Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Mon, Apr 20, 2015 at 11:59:04AM -0700, Junio C Hamano wrote:\n>\n>> Jeff King <peff@peff.net> writes:\n>> \n>> > @@ -334,7 +333,7 @@ true)\n>> >  \teval=\"git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only\"\n>> >  \teval=\"$eval $log_arg $strategy_args $merge_args $verbosity $progress\"\n>> >  \teval=\"$eval $gpg_sign_args\"\n>> > -\teval=\"$eval -m \\\"\\$merge_name\\\" $merge_head\"\n>> > +\teval=\"$eval FETCH_HEAD\"\n>> >  \t;;\n>> >  esac\n>> >  eval \"exec $eval\"\n>> >\n>> > as we seem to special-case the name FETCH_HEAD. It assumes that\n>> > git-merge's parsing of FETCH_HEAD is the same as what we do in git-pull,\n>> > but that seems safe.\n>> \n>> Unfortunately, \"git merge\"'s parsing of FETCH_HEAD forgets that we\n>> may be creating an Octopus.  Otherwise the above should work well.\n>\n> That sounds like a bug we should fix regardless.\n\nBut I am not sure how it should behave. \"git fetch $there A B C\"\nfollowed by \"git merge FETCH_HEAD\" merges only A, and I do not know\nif people have come to depend on this behaviour.\n\nI suspect there may be larger fallout from such a change, namely,\nwhat should \"git log FETCH_HEAD\" do?  Should it traverse the history\nstarting from all things that are not marked as not-for-merge, or\nshould it just say \"git rev-parse FETCH_HEAD\" and use only the first\none as the starting point?\n\nI would argue that it would be more consistent with how we envision\nthe \"git merge FETCH_HEAD\" should work if \"git log FETCH_HEAD\"\ntraversed from all fetched HEAD for merging, but surely it is a huge\npotential incompatibility.\n\nFor that matter, \"git rev-parse FETCH_HEAD\" and even get_sha1() should\nyield all fetched HEAD for merging if we want to be consistent.  I\nhaven't thought this through yet but it does not look pretty.\n"},{"id":"259699","messageId":"xmqq8udmlhu0.fsf@gitster.dls.corp.google.com","threadId":"39111","inReplyTo":"xmqqbnikoq0n.fsf@gitster.dls.corp.google.com","subject":"Re: [BUG] \"git pull\" will regress between 'master' and 'pu'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-20T19:28:55Z","receivedAt":"2015-04-20T19:28:55Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> This is primarily note-to-self; even though I haven't got around\n> bisecting yet, I think I know I did some bad change myself.\n>\n> \"git pull $URL $tag\" seems to:\n>\n>  * fail to invoke the editor without \"--edit\".\n>  * show the summary merge log message twice.\n\nWe seem to be making a good progress on the discussion on this\nspecific issue, but a larger tangent of this is that we do not seem\nto have test coverage to catch this regression.  As we are planning\nto rewrite \"git pull\", we need to make sure we have enough test\ncoverage to ensure that nothing will regress before doing so.\n\nThanks.\n"},{"id":"259727","messageId":"84c2d3dcb754d14a9f43deb7bbb6fd79@www.dscho.org","threadId":"39111","inReplyTo":"xmqq8udmlhu0.fsf@gitster.dls.corp.google.com","subject":"Re: [BUG] \"git pull\" will regress between 'master' and 'pu'","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2015-04-21T07:23:07Z","receivedAt":"2015-04-21T07:23:07Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn 2015-04-20 21:28, Junio C Hamano wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n>> This is primarily note-to-self; even though I haven't got around\n>> bisecting yet, I think I know I did some bad change myself.\n>>\n>> \"git pull $URL $tag\" seems to:\n>>\n>>  * fail to invoke the editor without \"--edit\".\n>>  * show the summary merge log message twice.\n> \n> We seem to be making a good progress on the discussion on this\n> specific issue, but a larger tangent of this is that we do not seem\n> to have test coverage to catch this regression.  As we are planning\n> to rewrite \"git pull\", we need to make sure we have enough test\n> coverage to ensure that nothing will regress before doing so.\n\nYes, the plan is to use code coverage tools to ensure that a decent amount of code paths/parameters is covered.\n\nCiao,\nDscho\n"},{"id":"260014","messageId":"1430025967-24479-1-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"xmqqiocqli1c.fsf@gitster.dls.corp.google.com","subject":"[PATCH 00/14] Teach \"git merge FETCH_HEAD\" octopus merges","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:25:53Z","receivedAt":"2015-04-26T05:25:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Jeff King <peff@peff.net> writes:\n>> On Mon, Apr 20, 2015 at 11:59:04AM -0700, Junio C Hamano wrote:\n>>\n>>> Unfortunately, \"git merge\"'s parsing of FETCH_HEAD forgets that we\n>>> may be creating an Octopus.  Otherwise the above should work well.\n>>\n>> That sounds like a bug we should fix regardless.\n>\n> But I am not sure how it should behave. \"git fetch $there A B C\"\n> followed by \"git merge FETCH_HEAD\" merges only A, and I do not know\n> if people have come to depend on this behaviour.\n>\n> I suspect there may be larger fallout from such a change, namely,\n> what should \"git log FETCH_HEAD\" do?  Should it traverse the history\n> starting from all things that are not marked as not-for-merge, or\n> should it just say \"git rev-parse FETCH_HEAD\" and use only the first\n> one as the starting point?\n\nSo, I thought we may want to try this and see how it goes.\n\nTentatively, I am saying that \"FETCH_HEAD\" is a magic token\nunderstood by \"git merge\", like \"git merge <msg> HEAD commits...\"\nsyntax was a magic that made \"git merge\" work differently from \"git\nmerge -m <msg> <commits>...\"; no changes to get_sha1() or anything\nheavy like that is intended.\n\n\nEarlier, we thought that it would just be the matter of turning\nexisting invocation of \"git merge <msg> HEAD $commits...\" in \"git\npull\" into \"git merge -m <msg> $commits...\" to deprecate the ugly\noriginal \"merge\" command line syntax.\n\nThis unfortunately failed for two reasons.\n\n * \"-m <msg>\" stops the editor from running; recent \"git pull\"\n   encourage the users to justify the merge in the log message,\n   and the auto-generated <msg> that comes from format-merge-msg\n   should still be shown to the user in the editor to be edited.\n\n * \"-m <msg>\" also adds auto-generated summary when merge.log\n   configuration is enabled, but \"git pull\" calls \"git merge\" with\n   the message _with_ that log already in there.\n\nInvoking \"git merge FETCH_HEAD\" (no messages fed by the caller) from\n\"git pull\" almost works.  \"git merge\" knows how to extract the name\nof the repository and the branch from FETCH_HEAD to use in the merge\nlog message it auto-generates.  However, this is done only for a\nsingle branch; if you did \"git pull $there topic-A topic-B\", and\nthen invoked \"git merge FETCH_HEAD\" from there, we would end up\nrecording a merge with only one branch, which is not what we want.\n\nThis teaches \"git merge FETCH_HEAD\" that FETCH_HEAD may describe\nmultiple branches that were fetched for merging.  With that, the\nlast step eradicates the \"merge <msg> HEAD <commit>...\" syntax from\nour codebase, finally.\n\nThis may be rough in a few places and some patches that are done as\npreparatory clean-up steps may want to be squashed into the patch\nthat follows them that implements the real change.\n\nThese patches are designed to apply on top of v2.2.2; I'll push them\nout on 'pu' later, on 'jc/merge' topic.\n\nJunio C Hamano (14):\n  merge: simplify code flow\n  t5520: style fixes\n  t5520: test pulling an octopus into an unborn branch\n  merge: clarify \"pulling into void\" special case\n  merge: do not check argc to determine number of remote heads\n  merge: small leakfix and code simplification\n  merge: clarify collect_parents() logic\n  merge: split reduce_parents() out of collect_parents()\n  merge: narrow scope of merge_names\n  merge: extract prepare_merge_message() logic out\n  merge: make collect_parents() auto-generate the merge message\n  merge: decide if we auto-generate the message early in\n    collect_parents()\n  merge: handle FETCH_HEAD internally\n  merge: deprecate 'git merge <message> HEAD <commit>' syntax\n\n Documentation/git-merge.txt   |   4 +\n builtin/merge.c               | 248 +++++++++++++++++++++++++++---------------\n git-cvsimport.perl            |   2 +-\n git-pull.sh                   |   3 +-\n t/t3402-rebase-merge.sh       |   2 +-\n t/t5520-pull.sh               |  31 +++---\n t/t6020-merge-df.sh           |   2 +-\n t/t6021-merge-criss-cross.sh  |   6 +-\n t/t9402-git-cvsserver-refs.sh |   2 +-\n 9 files changed, 188 insertions(+), 112 deletions(-)\n\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260012","messageId":"1430025967-24479-2-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 01/14] merge: simplify code flow","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:25:54Z","receivedAt":"2015-04-26T05:25:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"One of the first things cmd_merge() does is to see if the \"--abort\"\noption is given and run \"reset --merge\" and exit.  When the control\nreaches this point, we know \"--abort\" was not given.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex bebbe5b..8477878 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1165,15 +1165,15 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\toption_commit = 0;\n \t}\n \n-\tif (!abort_current_merge) {\n-\t\tif (!argc) {\n-\t\t\tif (default_to_upstream)\n-\t\t\t\targc = setup_with_upstream(&argv);\n-\t\t\telse\n-\t\t\t\tdie(_(\"No commit specified and merge.defaultToUpstream not set.\"));\n-\t\t} else if (argc == 1 && !strcmp(argv[0], \"-\"))\n-\t\t\targv[0] = \"@{-1}\";\n+\tif (!argc) {\n+\t\tif (default_to_upstream)\n+\t\t\targc = setup_with_upstream(&argv);\n+\t\telse\n+\t\t\tdie(_(\"No commit specified and merge.defaultToUpstream not set.\"));\n+\t} else if (argc == 1 && !strcmp(argv[0], \"-\")) {\n+\t\targv[0] = \"@{-1}\";\n \t}\n+\n \tif (!argc)\n \t\tusage_with_options(builtin_merge_usage,\n \t\t\tbuiltin_merge_options);\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260018","messageId":"1430025967-24479-3-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 02/14] t5520: style fixes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:25:55Z","receivedAt":"2015-04-26T05:25:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fix style funnies in early part of this test script that checks \"git\npull\" into an unborn branch.  The primary change is that 'chdir' to\na newly created empty test repository is now protected by being done\nin a subshell to make it more robust without having to chdir back to\nthe original place.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t5520-pull.sh | 22 ++++++----------------\n 1 file changed, 6 insertions(+), 16 deletions(-)\n\ndiff --git a/t/t5520-pull.sh b/t/t5520-pull.sh\nindex 227d293..5195a21 100755\n--- a/t/t5520-pull.sh\n+++ b/t/t5520-pull.sh\n@@ -9,36 +9,27 @@ modify () {\n \tmv \"$2.x\" \"$2\"\n }\n \n-D=`pwd`\n-\n test_expect_success setup '\n-\n \techo file >file &&\n \tgit add file &&\n \tgit commit -a -m original\n-\n '\n \n test_expect_success 'pulling into void' '\n-\tmkdir cloned &&\n-\tcd cloned &&\n-\tgit init &&\n-\tgit pull ..\n-'\n-\n-cd \"$D\"\n-\n-test_expect_success 'checking the results' '\n+\tgit init cloned &&\n+\t(\n+\t\tcd cloned &&\n+\t\tgit pull ..\n+\t) &&\n \ttest -f file &&\n \ttest -f cloned/file &&\n \ttest_cmp file cloned/file\n '\n \n test_expect_success 'pulling into void using master:master' '\n-\tmkdir cloned-uho &&\n+\tgit init cloned-uho &&\n \t(\n \t\tcd cloned-uho &&\n-\t\tgit init &&\n \t\tgit pull .. master:master\n \t) &&\n \ttest -f file &&\n@@ -71,7 +62,6 @@ test_expect_success 'pulling into void does not overwrite staged files' '\n \t)\n '\n \n-\n test_expect_success 'pulling into void does not remove new staged files' '\n \tgit init cloned-staged-new &&\n \t(\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260016","messageId":"1430025967-24479-4-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 03/14] t5520: test pulling an octopus into an unborn branch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:25:56Z","receivedAt":"2015-04-26T05:25:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The code comment for \"git merge\" in builtin/merge.c, we say\n\n    If the merged head is a valid one there is no reason\n    to forbid \"git merge\" into a branch yet to be born.\n    We do the same for \"git pull\".\n\nand t5520 does have an existing test for that behaviour.  However,\nthere was no test to make sure that 'git pull' to pull multiple\nbranches into an unborn branch must fail.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t5520-pull.sh | 9 +++++++++\n 1 file changed, 9 insertions(+)\n\ndiff --git a/t/t5520-pull.sh b/t/t5520-pull.sh\nindex 5195a21..7efd45b 100755\n--- a/t/t5520-pull.sh\n+++ b/t/t5520-pull.sh\n@@ -76,6 +76,15 @@ test_expect_success 'pulling into void does not remove new staged files' '\n \t)\n '\n \n+test_expect_success 'pulling into void must not create an octopus' '\n+\tgit init cloned-octopus &&\n+\t(\n+\t\tcd cloned-octopus &&\n+\t\ttest_must_fail git pull .. master master &&\n+\t\t! test -f file\n+\t)\n+'\n+\n test_expect_success 'test . as a remote' '\n \n \tgit branch copy master &&\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260015","messageId":"1430025967-24479-5-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 04/14] merge: clarify \"pulling into void\" special case","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:25:57Z","receivedAt":"2015-04-26T05:25:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Instead of having it as one of the three if/elseif/.. case arms,\ntest the condition and handle this special case upfront.  This makes\nit easier to follow the flow of logic.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 35 ++++++++++++++++++-----------------\n 1 file changed, 18 insertions(+), 17 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 8477878..878f82a 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1178,23 +1178,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(builtin_merge_usage,\n \t\t\tbuiltin_merge_options);\n \n-\t/*\n-\t * This could be traditional \"merge <msg> HEAD <commit>...\"  and\n-\t * the way we can tell it is to see if the second token is HEAD,\n-\t * but some people might have misused the interface and used a\n-\t * commit-ish that is the same as HEAD there instead.\n-\t * Traditional format never would have \"-m\" so it is an\n-\t * additional safety measure to check for it.\n-\t */\n-\n-\tif (!have_message && head_commit &&\n-\t    is_old_style_invocation(argc, argv, head_commit->object.sha1)) {\n-\t\tstrbuf_addstr(&merge_msg, argv[0]);\n-\t\thead_arg = argv[1];\n-\t\targv += 2;\n-\t\targc -= 2;\n-\t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n-\t} else if (!head_commit) {\n+\tif (!head_commit) {\n \t\tstruct commit *remote_head;\n \t\t/*\n \t\t * If the merged head is a valid one there is no reason\n@@ -1217,6 +1201,23 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\tupdate_ref(\"initial pull\", \"HEAD\", remote_head->object.sha1,\n \t\t\t   NULL, 0, UPDATE_REFS_DIE_ON_ERR);\n \t\tgoto done;\n+\t}\n+\n+\t/*\n+\t * This could be traditional \"merge <msg> HEAD <commit>...\"  and\n+\t * the way we can tell it is to see if the second token is HEAD,\n+\t * but some people might have misused the interface and used a\n+\t * commit-ish that is the same as HEAD there instead.\n+\t * Traditional format never would have \"-m\" so it is an\n+\t * additional safety measure to check for it.\n+\t */\n+\tif (!have_message &&\n+\t    is_old_style_invocation(argc, argv, head_commit->object.sha1)) {\n+\t\tstrbuf_addstr(&merge_msg, argv[0]);\n+\t\thead_arg = argv[1];\n+\t\targv += 2;\n+\t\targc -= 2;\n+\t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n \t} else {\n \t\tstruct strbuf merge_names = STRBUF_INIT;\n \n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260026","messageId":"1430025967-24479-6-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 05/14] merge: do not check argc to determine number of remote heads","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:25:58Z","receivedAt":"2015-04-26T05:25:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"To reject merging multiple commits into an unborn branch, we check\nargc, thinking that collect_parents() that reads the remaining\ncommand line arguments from <argc, argv> will give us the same\nnumber of commits as its input, i.e. argc.\n\nBecause what we really care about is the number of commits, let the\nfunction run and then make sure it returns only one commit instead.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 878f82a..1d4fbd3 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1185,9 +1185,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t * to forbid \"git merge\" into a branch yet to be born.\n \t\t * We do the same for \"git pull\".\n \t\t */\n-\t\tif (argc != 1)\n-\t\t\tdie(_(\"Can merge only exactly one commit into \"\n-\t\t\t\t\"empty head\"));\n \t\tif (squash)\n \t\t\tdie(_(\"Squash commit into empty head not supported yet\"));\n \t\tif (fast_forward == FF_NO)\n@@ -1197,6 +1194,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\tremote_head = remoteheads->item;\n \t\tif (!remote_head)\n \t\t\tdie(_(\"%s - not something we can merge\"), argv[0]);\n+\t\tif (remoteheads->next)\n+\t\t\tdie(_(\"Can merge only exactly one commit into empty head\"));\n \t\tread_empty(remote_head->object.sha1, 0);\n \t\tupdate_ref(\"initial pull\", \"HEAD\", remote_head->object.sha1,\n \t\t\t   NULL, 0, UPDATE_REFS_DIE_ON_ERR);\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260020","messageId":"1430025967-24479-7-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 06/14] merge: small leakfix and code simplification","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:25:59Z","receivedAt":"2015-04-26T05:25:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When parsing a merged object name like \"foo~20\" to formulate a merge\nsummary \"Merge branch foo (early part)\", a temporary strbuf is used,\nbut we forgot to deallocate it when we failed to find the named\nbranch.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 1d4fbd3..b2d0332 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -491,8 +491,7 @@ static void merge_name(const char *remote, struct strbuf *msg)\n \t}\n \tif (len) {\n \t\tstruct strbuf truname = STRBUF_INIT;\n-\t\tstrbuf_addstr(&truname, \"refs/heads/\");\n-\t\tstrbuf_addstr(&truname, remote);\n+\t\tstrbuf_addf(&truname, \"refs/heads/%s\", remote);\n \t\tstrbuf_setlen(&truname, truname.len - len);\n \t\tif (ref_exists(truname.buf)) {\n \t\t\tstrbuf_addf(msg,\n@@ -503,6 +502,7 @@ static void merge_name(const char *remote, struct strbuf *msg)\n \t\t\tstrbuf_release(&truname);\n \t\t\tgoto cleanup;\n \t\t}\n+\t\tstrbuf_release(&truname);\n \t}\n \n \tif (!strcmp(remote, \"FETCH_HEAD\") &&\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260017","messageId":"1430025967-24479-8-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 07/14] merge: clarify collect_parents() logic","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:26:00Z","receivedAt":"2015-04-26T05:26:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Clarify this small function in three ways.\n\n - The function initially collects all commits to be merged into a\n   commit_list \"remoteheads\"; the \"remotes\" pointer always points at\n   the tail of this list (either the remoteheads variable itself, or\n   the ->next slot of the element at the end of the list) to help\n   elongate the list by repeated calls to commit_list_insert().\n   Because the new element appended by commit_list_insert() will\n   always have its ->next slot NULLed out, there is no need for us\n   to assign NULL to *remotes to terminate the list at the end.\n\n - The variable \"head_subsumed\" always confused me every time I read\n   this code.  What is happening here is that we inspect what the\n   caller told us to merge (including the current HEAD) and come up\n   with the list of parents to be recorded for the resulting merge\n   commit, omitting commits that are ancestor of other commits.\n   This filtering may remove the current HEAD from the resulting\n   parent list---and we signal that fact with this variable, so that\n   we can later record it as the first parent when \"--no-ff\" is in\n   effect.\n\n - The \"parents\" list is created for this function by reduce_heads()\n   and was not deallocated after its use, even though the loop\n   control was written in such a way to allow us to do so by taking\n   the \"next\" element in a separate variable so that it can be used\n   in the next-step part of the loop control.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 13 +++++++++++--\n 1 file changed, 11 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex b2d0332..d2e36e2 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1061,11 +1061,19 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \t\t\t\t\t \"not something we can merge\");\n \t\tremotes = &commit_list_insert(commit, remotes)->next;\n \t}\n-\t*remotes = NULL;\n \n+\t/*\n+\t * Is the current HEAD reachable from another commit being\n+\t * merged?  If so we do not want to record it as a parent of\n+\t * the resulting merge, unless --no-ff is given.  We will flip\n+\t * this variable to 0 when we find HEAD among the independent\n+\t * tips being merged.\n+\t */\n+\t*head_subsumed = 1;\n+\n+\t/* Find what parents to record by checking independent ones. */\n \tparents = reduce_heads(remoteheads);\n \n-\t*head_subsumed = 1; /* we will flip this to 0 when we find it */\n \tfor (remoteheads = NULL, remotes = &remoteheads;\n \t     parents;\n \t     parents = next) {\n@@ -1075,6 +1083,7 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \t\t\t*head_subsumed = 0;\n \t\telse\n \t\t\tremotes = &commit_list_insert(commit, remotes)->next;\n+\t\tfree(parents);\n \t}\n \treturn remoteheads;\n }\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260013","messageId":"1430025967-24479-9-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 08/14] merge: split reduce_parents() out of collect_parents()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:26:01Z","receivedAt":"2015-04-26T05:26:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The latter does two separate things:\n\n - Parse the list of commits on the command line, and formulate the\n   list of commits to be merged (including the current HEAD);\n\n - Compute the list of parents to be recorded in the resulting merge\n   commit.\n\nSplit the latter into a separate helper function, so that we can\nlater supply the list commits to be merged from a different source\n(namely, FETCH_HEAD).\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 41 +++++++++++++++++++++++++----------------\n 1 file changed, 25 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex d2e36e2..054f052 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1044,23 +1044,11 @@ static int default_edit_option(void)\n \t\tst_stdin.st_mode == st_stdout.st_mode);\n }\n \n-static struct commit_list *collect_parents(struct commit *head_commit,\n-\t\t\t\t\t   int *head_subsumed,\n-\t\t\t\t\t   int argc, const char **argv)\n+static struct commit_list *reduce_parents(struct commit *head_commit,\n+\t\t\t\t\t  int *head_subsumed,\n+\t\t\t\t\t  struct commit_list *remoteheads)\n {\n-\tint i;\n-\tstruct commit_list *remoteheads = NULL, *parents, *next;\n-\tstruct commit_list **remotes = &remoteheads;\n-\n-\tif (head_commit)\n-\t\tremotes = &commit_list_insert(head_commit, remotes)->next;\n-\tfor (i = 0; i < argc; i++) {\n-\t\tstruct commit *commit = get_merge_parent(argv[i]);\n-\t\tif (!commit)\n-\t\t\thelp_unknown_ref(argv[i], \"merge\",\n-\t\t\t\t\t \"not something we can merge\");\n-\t\tremotes = &commit_list_insert(commit, remotes)->next;\n-\t}\n+\tstruct commit_list *parents, *next, **remotes = &remoteheads;\n \n \t/*\n \t * Is the current HEAD reachable from another commit being\n@@ -1088,6 +1076,27 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \treturn remoteheads;\n }\n \n+static struct commit_list *collect_parents(struct commit *head_commit,\n+\t\t\t\t\t   int *head_subsumed,\n+\t\t\t\t\t   int argc, const char **argv)\n+{\n+\tint i;\n+\tstruct commit_list *remoteheads = NULL;\n+\tstruct commit_list **remotes = &remoteheads;\n+\n+\tif (head_commit)\n+\t\tremotes = &commit_list_insert(head_commit, remotes)->next;\n+\tfor (i = 0; i < argc; i++) {\n+\t\tstruct commit *commit = get_merge_parent(argv[i]);\n+\t\tif (!commit)\n+\t\t\thelp_unknown_ref(argv[i], \"merge\",\n+\t\t\t\t\t \"not something we can merge\");\n+\t\tremotes = &commit_list_insert(commit, remotes)->next;\n+\t}\n+\n+\treturn reduce_parents(head_commit, head_subsumed, remoteheads);\n+}\n+\n int cmd_merge(int argc, const char **argv, const char *prefix)\n {\n \tunsigned char result_tree[20];\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260021","messageId":"1430025967-24479-10-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 09/14] merge: narrow scope of merge_names","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:26:02Z","receivedAt":"2015-04-26T05:26:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"In order to pass the list of parents to fmt_merge_msg(), cmd_merge()\nuses this strbuf to create something that look like FETCH_HEAD that\ndescribes commits that are being merged.  This is necessary only\nwhen we are creating the merge commit message ourselves, but was\ndone unconditionally.\n\nMove the variable and the logic to populate it to confine them in a\nblock that needs them.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 11 +++++++----\n 1 file changed, 7 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 054f052..d853c9d 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1236,8 +1236,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\targc -= 2;\n \t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n \t} else {\n-\t\tstruct strbuf merge_names = STRBUF_INIT;\n-\n \t\t/* We are invoked directly as the first-class UI. */\n \t\thead_arg = \"HEAD\";\n \n@@ -1247,11 +1245,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t * to the given message.\n \t\t */\n \t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n-\t\tfor (p = remoteheads; p; p = p->next)\n-\t\t\tmerge_name(merge_remote_util(p->item)->name, &merge_names);\n \n \t\tif (!have_message || shortlog_len) {\n+\t\t\tstruct strbuf merge_names = STRBUF_INIT;\n \t\t\tstruct fmt_merge_msg_opts opts;\n+\n+\t\t\tfor (p = remoteheads; p; p = p->next)\n+\t\t\t\tmerge_name(merge_remote_util(p->item)->name, &merge_names);\n+\n \t\t\tmemset(&opts, 0, sizeof(opts));\n \t\t\topts.add_title = !have_message;\n \t\t\topts.shortlog_len = shortlog_len;\n@@ -1260,6 +1261,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t\tfmt_merge_msg(&merge_names, &merge_msg, &opts);\n \t\t\tif (merge_msg.len)\n \t\t\t\tstrbuf_setlen(&merge_msg, merge_msg.len - 1);\n+\n+\t\t\tstrbuf_release(&merge_names);\n \t\t}\n \t}\n \n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260019","messageId":"1430025967-24479-11-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 10/14] merge: extract prepare_merge_message() logic out","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:26:03Z","receivedAt":"2015-04-26T05:26:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 26 +++++++++++++++-----------\n 1 file changed, 15 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex d853c9d..a972ed6 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1076,6 +1076,20 @@ static struct commit_list *reduce_parents(struct commit *head_commit,\n \treturn remoteheads;\n }\n \n+static void prepare_merge_message(struct strbuf *merge_names, struct strbuf *merge_msg)\n+{\n+\tstruct fmt_merge_msg_opts opts;\n+\n+\tmemset(&opts, 0, sizeof(opts));\n+\topts.add_title = !have_message;\n+\topts.shortlog_len = shortlog_len;\n+\topts.credit_people = (0 < option_edit);\n+\n+\tfmt_merge_msg(merge_names, merge_msg, &opts);\n+\tif (merge_msg->len)\n+\t\tstrbuf_setlen(merge_msg, merge_msg->len - 1);\n+}\n+\n static struct commit_list *collect_parents(struct commit *head_commit,\n \t\t\t\t\t   int *head_subsumed,\n \t\t\t\t\t   int argc, const char **argv)\n@@ -1248,20 +1262,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \n \t\tif (!have_message || shortlog_len) {\n \t\t\tstruct strbuf merge_names = STRBUF_INIT;\n-\t\t\tstruct fmt_merge_msg_opts opts;\n \n \t\t\tfor (p = remoteheads; p; p = p->next)\n \t\t\t\tmerge_name(merge_remote_util(p->item)->name, &merge_names);\n-\n-\t\t\tmemset(&opts, 0, sizeof(opts));\n-\t\t\topts.add_title = !have_message;\n-\t\t\topts.shortlog_len = shortlog_len;\n-\t\t\topts.credit_people = (0 < option_edit);\n-\n-\t\t\tfmt_merge_msg(&merge_names, &merge_msg, &opts);\n-\t\t\tif (merge_msg.len)\n-\t\t\t\tstrbuf_setlen(&merge_msg, merge_msg.len - 1);\n-\n+\t\t\tprepare_merge_message(&merge_names, &merge_msg);\n \t\t\tstrbuf_release(&merge_names);\n \t\t}\n \t}\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260022","messageId":"1430025967-24479-12-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 11/14] merge: make collect_parents() auto-generate the merge message","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:26:04Z","receivedAt":"2015-04-26T05:26:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 35 +++++++++++++++++++++--------------\n 1 file changed, 21 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex a972ed6..84ebb22 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1092,7 +1092,8 @@ static void prepare_merge_message(struct strbuf *merge_names, struct strbuf *mer\n \n static struct commit_list *collect_parents(struct commit *head_commit,\n \t\t\t\t\t   int *head_subsumed,\n-\t\t\t\t\t   int argc, const char **argv)\n+\t\t\t\t\t   int argc, const char **argv,\n+\t\t\t\t\t   struct strbuf *merge_msg)\n {\n \tint i;\n \tstruct commit_list *remoteheads = NULL;\n@@ -1108,7 +1109,19 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \t\tremotes = &commit_list_insert(commit, remotes)->next;\n \t}\n \n-\treturn reduce_parents(head_commit, head_subsumed, remoteheads);\n+\tremoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);\n+\n+\tif (merge_msg &&\n+\t    (!have_message || shortlog_len)) {\n+\t\tstruct strbuf merge_names = STRBUF_INIT;\n+\n+\t\tfor (p = remoteheads; p; p = p->next)\n+\t\t\tmerge_name(merge_remote_util(p->item)->name, &merge_names);\n+\t\tprepare_merge_message(&merge_names, merge_msg);\n+\t\tstrbuf_release(&merge_names);\n+\t}\n+\n+\treturn remoteheads;\n }\n \n int cmd_merge(int argc, const char **argv, const char *prefix)\n@@ -1222,7 +1235,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\tif (fast_forward == FF_NO)\n \t\t\tdie(_(\"Non-fast-forward commit does not make sense into \"\n \t\t\t    \"an empty head\"));\n-\t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n+\t\tremoteheads = collect_parents(head_commit, &head_subsumed,\n+\t\t\t\t\t      argc, argv, NULL);\n \t\tremote_head = remoteheads->item;\n \t\tif (!remote_head)\n \t\t\tdie(_(\"%s - not something we can merge\"), argv[0]);\n@@ -1248,7 +1262,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\thead_arg = argv[1];\n \t\targv += 2;\n \t\targc -= 2;\n-\t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n+\t\tremoteheads = collect_parents(head_commit, &head_subsumed,\n+\t\t\t\t\t      argc, argv, NULL);\n \t} else {\n \t\t/* We are invoked directly as the first-class UI. */\n \t\thead_arg = \"HEAD\";\n@@ -1258,16 +1273,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t * the standard merge summary message to be appended\n \t\t * to the given message.\n \t\t */\n-\t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n-\n-\t\tif (!have_message || shortlog_len) {\n-\t\t\tstruct strbuf merge_names = STRBUF_INIT;\n-\n-\t\t\tfor (p = remoteheads; p; p = p->next)\n-\t\t\t\tmerge_name(merge_remote_util(p->item)->name, &merge_names);\n-\t\t\tprepare_merge_message(&merge_names, &merge_msg);\n-\t\t\tstrbuf_release(&merge_names);\n-\t\t}\n+\t\tremoteheads = collect_parents(head_commit, &head_subsumed,\n+\t\t\t\t\t      argc, argv, &merge_msg);\n \t}\n \n \tif (!head_commit || !argc)\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260024","messageId":"1430025967-24479-13-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 12/14] merge: decide if we auto-generate the message early in collect_parents()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:26:05Z","receivedAt":"2015-04-26T05:26:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 16 +++++++++-------\n 1 file changed, 9 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 84ebb22..c7d9d6e 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1098,6 +1098,10 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \tint i;\n \tstruct commit_list *remoteheads = NULL;\n \tstruct commit_list **remotes = &remoteheads;\n+\tstruct strbuf merge_names = STRBUF_INIT, *autogen = NULL;\n+\n+\tif (merge_msg && (!have_message || shortlog_len))\n+\t\tautogen = &merge_names;\n \n \tif (head_commit)\n \t\tremotes = &commit_list_insert(head_commit, remotes)->next;\n@@ -1111,14 +1115,12 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \n \tremoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);\n \n-\tif (merge_msg &&\n-\t    (!have_message || shortlog_len)) {\n-\t\tstruct strbuf merge_names = STRBUF_INIT;\n-\n+\tif (autogen) {\n \t\tfor (p = remoteheads; p; p = p->next)\n-\t\t\tmerge_name(merge_remote_util(p->item)->name, &merge_names);\n-\t\tprepare_merge_message(&merge_names, merge_msg);\n-\t\tstrbuf_release(&merge_names);\n+\t\t\tmerge_name(merge_remote_util(p->item)->name, autogen);\n+\n+\t\tprepare_merge_message(autogen, merge_msg);\n+\t\tstrbuf_release(autogen);\n \t}\n \n \treturn remoteheads;\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260023","messageId":"1430025967-24479-14-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 13/14] merge: handle FETCH_HEAD internally","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:26:06Z","receivedAt":"2015-04-26T05:26:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The collect_parents() function now is responsible for\n\n 1. parsing the commits given on the command line into a list of\n    commits to be merged;\n\n 2. filtering these parents into independent ones; and\n\n 3. optionally calling fmt_merge_msg() via prepare_merge_message()\n    to prepare an auto-generated merge log message, using fake\n    contents that FETCH_HEAD would have had if these commits were\n    fetched from the current repository with \"git pull . $args...\"\n\nMake \"git merge FETCH_HEAD\" to be the same as the traditional\n\n    git merge \"$(git fmt-merge-msg <.git/FETCH_HEAD)\" $commits\n\ninvocation of the command in \"git pull\", where $commits are the ones\nthat appear in FETCH_HEAD that are not marked as not-for-merge, by\nmaking it do a bit more, specifically:\n\n - noticing \"FETCH_HEAD\" is the only \"commit\" on the command line\n   and picking the commits that are not marked as not-for-merge as\n   the list of commits to be merged (substitute for step #1 above);\n\n - letting the resulting list fed to step #2 above;\n\n - doing the step #3 above, using the contents of the FETCH_HEAD\n   instead of fake contents crafted from the list of commits parsed\n   in the step #1 above.\n\nNote that this changes the semantics.  \"git merge FETCH_HEAD\" has\nalways behaved as if the first commit in the FETCH_HEAD file were\ndirectly specified on the command line, creating a two-way merge\nwhose auto-generated merge log said \"merge commit xyz\".  With this\nchange, if the previous fetch was to grab multiple branches (e.g.\n\"git fetch $there topic-a topic-b\"), the new world order is to\ncreate an octopus, behaving as if \"git pull $there topic-a topic-b\"\nwere run.  This is a deliberate change to make that happen.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-merge.txt |   4 ++\n builtin/merge.c             | 105 ++++++++++++++++++++++++++++++--------------\n 2 files changed, 76 insertions(+), 33 deletions(-)\n\ndiff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt\nindex cf2c374..d9aa6b6 100644\n--- a/Documentation/git-merge.txt\n+++ b/Documentation/git-merge.txt\n@@ -104,6 +104,10 @@ commit or stash your changes before running 'git merge'.\n If no commit is given from the command line, merge the remote-tracking\n branches that the current branch is configured to use as its upstream.\n See also the configuration section of this manual page.\n++\n+When `FETCH_HEAD` (and no other commit) is specified, the branches\n+recorded in the `.git/FETCH_HEAD` file by the previous invocation\n+of `git fetch` for merging are merged to the current branch.\n \n \n PRE-MERGE CHECKS\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex c7d9d6e..42f9fcc 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -505,28 +505,6 @@ static void merge_name(const char *remote, struct strbuf *msg)\n \t\tstrbuf_release(&truname);\n \t}\n \n-\tif (!strcmp(remote, \"FETCH_HEAD\") &&\n-\t\t\t!access(git_path(\"FETCH_HEAD\"), R_OK)) {\n-\t\tconst char *filename;\n-\t\tFILE *fp;\n-\t\tstruct strbuf line = STRBUF_INIT;\n-\t\tchar *ptr;\n-\n-\t\tfilename = git_path(\"FETCH_HEAD\");\n-\t\tfp = fopen(filename, \"r\");\n-\t\tif (!fp)\n-\t\t\tdie_errno(_(\"could not open '%s' for reading\"),\n-\t\t\t\t  filename);\n-\t\tstrbuf_getline(&line, fp, '\\n');\n-\t\tfclose(fp);\n-\t\tptr = strstr(line.buf, \"\\tnot-for-merge\\t\");\n-\t\tif (ptr)\n-\t\t\tstrbuf_remove(&line, ptr-line.buf+1, 13);\n-\t\tstrbuf_addbuf(msg, &line);\n-\t\tstrbuf_release(&line);\n-\t\tgoto cleanup;\n-\t}\n-\n \tif (remote_head->util) {\n \t\tstruct merge_remote_desc *desc;\n \t\tdesc = merge_remote_util(remote_head);\n@@ -1090,6 +1068,60 @@ static void prepare_merge_message(struct strbuf *merge_names, struct strbuf *mer\n \t\tstrbuf_setlen(merge_msg, merge_msg->len - 1);\n }\n \n+static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge_names)\n+{\n+\tconst char *filename;\n+\tint fd, pos, npos;\n+\tstruct strbuf fetch_head_file = STRBUF_INIT;\n+\n+\tif (!merge_names)\n+\t\tmerge_names = &fetch_head_file;\n+\n+\tfilename = git_path(\"FETCH_HEAD\");\n+\tfd = open(filename, O_RDONLY);\n+\tif (fd < 0)\n+\t\tdie_errno(_(\"could not open '%s' for reading\"), filename);\n+\n+\tif (strbuf_read(merge_names, fd, 0) < 0)\n+\t\tdie_errno(_(\"could not read '%s'\"), filename);\n+\tif (close(fd) < 0)\n+\t\tdie_errno(_(\"could not close '%s'\"), filename);\n+\n+\tfor (pos = 0; pos < merge_names->len; pos = npos) {\n+\t\tunsigned char sha1[20];\n+\t\tchar *ptr;\n+\t\tstruct commit *commit;\n+\n+\t\tptr = strchr(merge_names->buf + pos, '\\n');\n+\t\tif (ptr)\n+\t\t\tnpos = ptr - merge_names->buf + 1;\n+\t\telse\n+\t\t\tnpos = merge_names->len;\n+\n+\t\tif (npos - pos < 40 + 2 ||\n+\t\t    get_sha1_hex(merge_names->buf + pos, sha1))\n+\t\t\tcommit = NULL; /* bad */\n+\t\telse if (memcmp(merge_names->buf + pos + 40, \"\\t\\t\", 2))\n+\t\t\tcontinue; /* not-for-merge */\n+\t\telse {\n+\t\t\tchar saved = merge_names->buf[pos + 40];\n+\t\t\tmerge_names->buf[pos + 40] = '\\0';\n+\t\t\tcommit = get_merge_parent(merge_names->buf + pos);\n+\t\t\tmerge_names->buf[pos + 40] = saved;\n+\t\t}\n+\t\tif (!commit) {\n+\t\t\tif (ptr)\n+\t\t\t\t*ptr = '\\0';\n+\t\t\tdie(\"not something we can merge in %s: %s\",\n+\t\t\t    filename, merge_names->buf + pos);\n+\t\t}\n+\t\tremotes = &commit_list_insert(commit, remotes)->next;\n+\t}\n+\n+\tif (merge_names == &fetch_head_file)\n+\t\tstrbuf_release(&fetch_head_file);\n+}\n+\n static struct commit_list *collect_parents(struct commit *head_commit,\n \t\t\t\t\t   int *head_subsumed,\n \t\t\t\t\t   int argc, const char **argv,\n@@ -1105,20 +1137,27 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \n \tif (head_commit)\n \t\tremotes = &commit_list_insert(head_commit, remotes)->next;\n-\tfor (i = 0; i < argc; i++) {\n-\t\tstruct commit *commit = get_merge_parent(argv[i]);\n-\t\tif (!commit)\n-\t\t\thelp_unknown_ref(argv[i], \"merge\",\n-\t\t\t\t\t \"not something we can merge\");\n-\t\tremotes = &commit_list_insert(commit, remotes)->next;\n-\t}\n \n-\tremoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);\n+\tif (argc == 1 && !strcmp(argv[0], \"FETCH_HEAD\")) {\n+\t\thandle_fetch_head(remotes, autogen);\n+\t\tremoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);\n+\t} else {\n+\t\tfor (i = 0; i < argc; i++) {\n+\t\t\tstruct commit *commit = get_merge_parent(argv[i]);\n+\t\t\tif (!commit)\n+\t\t\t\thelp_unknown_ref(argv[i], \"merge\",\n+\t\t\t\t\t\t \"not something we can merge\");\n+\t\t\tremotes = &commit_list_insert(commit, remotes)->next;\n+\t\t}\n+\t\tremoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);\n+\t\tif (autogen) {\n+\t\t\tstruct commit_list *p;\n+\t\t\tfor (p = remoteheads; p; p = p->next)\n+\t\t\t\tmerge_name(merge_remote_util(p->item)->name, autogen);\n+\t\t}\n+\t}\n \n \tif (autogen) {\n-\t\tfor (p = remoteheads; p; p = p->next)\n-\t\t\tmerge_name(merge_remote_util(p->item)->name, autogen);\n-\n \t\tprepare_merge_message(autogen, merge_msg);\n \t\tstrbuf_release(autogen);\n \t}\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260025","messageId":"1430025967-24479-15-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH 14/14] merge: deprecate 'git merge <message> HEAD <commit>' syntax","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-26T05:26:07Z","receivedAt":"2015-04-26T05:26:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We had this in \"git merge\" manual for eternity:\n\n    'git merge' <msg> HEAD <commit>...\n\n    [This] syntax (<msg> `HEAD` <commit>...) is supported for\n    historical reasons.  Do not use it from the command line or in\n    new scripts.  It is the same as `git merge -m <msg> <commit>...`.\n\nWith the update to \"git merge\" to make it understand what is\nrecorded in FETCH_HEAD directly, including Octopus merge cases, we\nnow can rewrite the use of this syntax in \"git pull\" with a simple\n\"git merge FETCH_HEAD\".\n\nAlso there are quite a few fallouts in the test scripts, and it\nturns out that \"git cvsimport\" also uses this old syntax to record\na merge.\n\nJudging from this result, I would not be surprised if dropping the\nsupport of the old syntax broke scripts people have written and been\nrelying on for the past ten years.  But at least we can start the\ndeprecation process by throwing a warning message when the syntax is\nused.\n\nWith luck, we might be able to drop the support in a few years.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c               | 1 +\n git-cvsimport.perl            | 2 +-\n git-pull.sh                   | 3 +--\n t/t3402-rebase-merge.sh       | 2 +-\n t/t6020-merge-df.sh           | 2 +-\n t/t6021-merge-criss-cross.sh  | 6 +++---\n t/t9402-git-cvsserver-refs.sh | 2 +-\n 7 files changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 42f9fcc..67fbfaf 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1299,6 +1299,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t */\n \tif (!have_message &&\n \t    is_old_style_invocation(argc, argv, head_commit->object.sha1)) {\n+\t\twarning(\"old-style 'git merge <msg> HEAD <commit>' is deprecated.\");\n \t\tstrbuf_addstr(&merge_msg, argv[0]);\n \t\thead_arg = argv[1];\n \t\targv += 2;\ndiff --git a/git-cvsimport.perl b/git-cvsimport.perl\nindex 73d367c..82ecb03 100755\n--- a/git-cvsimport.perl\n+++ b/git-cvsimport.perl\n@@ -1162,7 +1162,7 @@ sub commit {\n \t\tdie \"Fast-forward update failed: $?\\n\" if $?;\n \t}\n \telse {\n-\t\tsystem(qw(git merge cvsimport HEAD), \"$remote/$opt_o\");\n+\t\tsystem(qw(git merge -m cvsimport), \"$remote/$opt_o\");\n \t\tdie \"Could not merge $opt_o into the current branch.\\n\" if $?;\n \t}\n } else {\ndiff --git a/git-pull.sh b/git-pull.sh\nindex 4d4fc77..15d9431 100755\n--- a/git-pull.sh\n+++ b/git-pull.sh\n@@ -323,7 +323,6 @@ then\n \tfi\n fi\n \n-merge_name=$(git fmt-merge-msg $log_arg <\"$GIT_DIR/FETCH_HEAD\") || exit\n case \"$rebase\" in\n true)\n \teval=\"git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity\"\n@@ -334,7 +333,7 @@ true)\n \teval=\"git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only\"\n \teval=\"$eval $log_arg $strategy_args $merge_args $verbosity $progress\"\n \teval=\"$eval $gpg_sign_args\"\n-\teval=\"$eval \\\"\\$merge_name\\\" HEAD $merge_head\"\n+\teval=\"$eval FETCH_HEAD\"\n \t;;\n esac\n eval \"exec $eval\"\ndiff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh\nindex 5a27ec9..8f64505 100755\n--- a/t/t3402-rebase-merge.sh\n+++ b/t/t3402-rebase-merge.sh\n@@ -47,7 +47,7 @@ test_expect_success setup '\n '\n \n test_expect_success 'reference merge' '\n-\tgit merge -s recursive \"reference merge\" HEAD master\n+\tgit merge -s recursive -m \"reference merge\" master\n '\n \n PRE_REBASE=$(git rev-parse test-rebase)\ndiff --git a/t/t6020-merge-df.sh b/t/t6020-merge-df.sh\nindex 27c3d73..2af1bee 100755\n--- a/t/t6020-merge-df.sh\n+++ b/t/t6020-merge-df.sh\n@@ -24,7 +24,7 @@ test_expect_success 'prepare repository' '\n '\n \n test_expect_success 'Merge with d/f conflicts' '\n-\ttest_expect_code 1 git merge \"merge msg\" B master\n+\ttest_expect_code 1 git merge -m \"merge msg\" master\n '\n \n test_expect_success 'F/D conflict' '\ndiff --git a/t/t6021-merge-criss-cross.sh b/t/t6021-merge-criss-cross.sh\nindex d15b313..213deec 100755\n--- a/t/t6021-merge-criss-cross.sh\n+++ b/t/t6021-merge-criss-cross.sh\n@@ -48,7 +48,7 @@ echo \"1\n \" > file &&\n git commit -m \"C3\" file &&\n git branch C3 &&\n-git merge \"pre E3 merge\" B A &&\n+git merge -m \"pre E3 merge\" A &&\n echo \"1\n 2\n 3 changed in E3, branch B. New file size\n@@ -61,7 +61,7 @@ echo \"1\n \" > file &&\n git commit -m \"E3\" file &&\n git checkout A &&\n-git merge \"pre D8 merge\" A C3 &&\n+git merge -m \"pre D8 merge\" C3 &&\n echo \"1\n 2\n 3 changed in C3, branch B\n@@ -73,7 +73,7 @@ echo \"1\n 9\" > file &&\n git commit -m D8 file'\n \n-test_expect_success 'Criss-cross merge' 'git merge \"final merge\" A B'\n+test_expect_success 'Criss-cross merge' 'git merge -m \"final merge\" B'\n \n cat > file-expect <<EOF\n 1\ndiff --git a/t/t9402-git-cvsserver-refs.sh b/t/t9402-git-cvsserver-refs.sh\nindex 1e266ef..d00df08 100755\n--- a/t/t9402-git-cvsserver-refs.sh\n+++ b/t/t9402-git-cvsserver-refs.sh\n@@ -496,7 +496,7 @@ test_expect_success 'check [cvswork3] diff' '\n '\n \n test_expect_success 'merge early [cvswork3] b3 with b1' '\n-\t( cd gitwork3 && git merge \"message\" HEAD b1 ) &&\n+\t( cd gitwork3 && git merge -m \"message\" b1 ) &&\n \tgit fetch gitwork3 b3:b3 &&\n \tgit tag v3merged b3 &&\n \tgit push --tags gitcvs.git b3:b3\n-- \n2.4.0-rc3-238-g36f5934\n"},{"id":"260212","messageId":"1430342973-30344-1-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430025967-24479-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 00/15] Teach \"git merge FETCH_HEAD\" octopus merges","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:18Z","receivedAt":"2015-04-29T21:29:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This series is an attempt to make these two operations truly equivalent:\n\n    $ git pull . topic-a topic-b...\n\n    $ git fetch . topic-a topic-b...\n    $ git merge FETCH_HEAD\n\nCompared to the previous one ($gmane/267809), there are only a few\nminor changes:\n\n - The first patch is new; it adds tests to illustrate what the\n   current code does.  Accordingly, the penultimate patch is the\n   same as the previous, but updates the tests that expect failure\n   in this step to expect success.\n\n - One step failed to compile (the offending code was removed in a\n   later patch and the endgame did not break the build), which has\n   been corrected.\n\nJunio C Hamano (15):\n  merge: test the top-level merge driver\n  merge: simplify code flow\n  t5520: style fixes\n  t5520: test pulling an octopus into an unborn branch\n  merge: clarify \"pulling into void\" special case\n  merge: do not check argc to determine number of remote heads\n  merge: small leakfix and code simplification\n  merge: clarify collect_parents() logic\n  merge: split reduce_parents() out of collect_parents()\n  merge: narrow scope of merge_names\n  merge: extract prepare_merge_message() logic out\n  merge: make collect_parents() auto-generate the merge message\n  merge: decide if we auto-generate the message early in collect_parents()\n  merge: handle FETCH_HEAD internally\n  merge: deprecate 'git merge <message> HEAD <commit>' syntax\n\n Documentation/git-merge.txt   |   4 +\n builtin/merge.c               | 248 +++++++++++++++++++++++++++---------------\n git-cvsimport.perl            |   2 +-\n git-pull.sh                   |   3 +-\n t/t3033-merge-toplevel.sh     | 136 +++++++++++++++++++++++\n t/t3402-rebase-merge.sh       |   2 +-\n t/t5520-pull.sh               |  31 +++---\n t/t6020-merge-df.sh           |   2 +-\n t/t6021-merge-criss-cross.sh  |   6 +-\n t/t9402-git-cvsserver-refs.sh |   2 +-\n 10 files changed, 324 insertions(+), 112 deletions(-)\n create mode 100755 t/t3033-merge-toplevel.sh\n\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260211","messageId":"1430342973-30344-2-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 01/15] merge: test the top-level merge driver","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:19Z","receivedAt":"2015-04-29T21:29:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We seem to have tests for specific merge strategy backends\n(e.g. recursive), but not much test coverage for the \"git merge\"\nitself.  As I am planning to update the semantics of merging\n\"FETCH_HEAD\" in such a way that these two\n\n    git pull . topic_a topic_b...\n\nvs.\n\n    git fetch . topic_a topic_b...\n    git merge FETCH_HEAD\n\nare truly equivalent, let me add a few test cases to cover the\ntricky ones.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t3033-merge-toplevel.sh | 136 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 136 insertions(+)\n create mode 100755 t/t3033-merge-toplevel.sh\n\ndiff --git a/t/t3033-merge-toplevel.sh b/t/t3033-merge-toplevel.sh\nnew file mode 100755\nindex 0000000..9d92d3c\n--- /dev/null\n+++ b/t/t3033-merge-toplevel.sh\n@@ -0,0 +1,136 @@\n+#!/bin/sh\n+\n+test_description='\"git merge\" top-level frontend'\n+\n+. ./test-lib.sh\n+\n+t3033_reset () {\n+\tgit checkout -B master two &&\n+\tgit branch -f left three &&\n+\tgit branch -f right four\n+}\n+\n+test_expect_success setup '\n+\ttest_commit one &&\n+\tgit branch left &&\n+\tgit branch right &&\n+\ttest_commit two &&\n+\tgit checkout left &&\n+\ttest_commit three &&\n+\tgit checkout right &&\n+\ttest_commit four &&\n+\tgit checkout master\n+'\n+\n+# Local branches\n+\n+test_expect_success 'merge an octopus into void' '\n+\tt3033_reset &&\n+\tgit checkout --orphan test &&\n+\tgit rm -fr . &&\n+\ttest_must_fail git merge left right &&\n+\ttest_must_fail git rev-parse --verify HEAD &&\n+\tgit diff --quiet &&\n+\ttest_must_fail git rev-parse HEAD\n+'\n+\n+test_expect_success 'merge an octopus, fast-forward (ff)' '\n+\tt3033_reset &&\n+\tgit reset --hard one &&\n+\tgit merge left right &&\n+\t# one is ancestor of three (left) and four (right)\n+\ttest_must_fail git rev-parse --verify HEAD^3 &&\n+\tgit rev-parse HEAD^1 HEAD^2 | sort >actual &&\n+\tgit rev-parse three four | sort >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'merge octopus, non-fast-forward (ff)' '\n+\tt3033_reset &&\n+\tgit reset --hard one &&\n+\tgit merge --no-ff left right &&\n+\t# one is ancestor of three (left) and four (right)\n+\ttest_must_fail git rev-parse --verify HEAD^4 &&\n+\tgit rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual &&\n+\tgit rev-parse one three four | sort >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'merge octopus, fast-forward (does not ff)' '\n+\tt3033_reset &&\n+\tgit merge left right &&\n+\t# two (master) is not an ancestor of three (left) and four (right)\n+\ttest_must_fail git rev-parse --verify HEAD^4 &&\n+\tgit rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual &&\n+\tgit rev-parse two three four | sort >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'merge octopus, non-fast-forward' '\n+\tt3033_reset &&\n+\tgit merge --no-ff left right &&\n+\ttest_must_fail git rev-parse --verify HEAD^4 &&\n+\tgit rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual &&\n+\tgit rev-parse two three four | sort >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+# The same set with FETCH_HEAD\n+\n+test_expect_failure 'merge FETCH_HEAD octopus into void' '\n+\tt3033_reset &&\n+\tgit checkout --orphan test &&\n+\tgit rm -fr . &&\n+\tgit fetch . left right &&\n+\ttest_must_fail git merge FETCH_HEAD &&\n+\ttest_must_fail git rev-parse --verify HEAD &&\n+\tgit diff --quiet &&\n+\ttest_must_fail git rev-parse HEAD\n+'\n+\n+test_expect_failure 'merge FETCH_HEAD octopus fast-forward (ff)' '\n+\tt3033_reset &&\n+\tgit reset --hard one &&\n+\tgit fetch . left right &&\n+\tgit merge FETCH_HEAD &&\n+\t# one is ancestor of three (left) and four (right)\n+\ttest_must_fail git rev-parse --verify HEAD^3 &&\n+\tgit rev-parse HEAD^1 HEAD^2 | sort >actual &&\n+\tgit rev-parse three four | sort >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_failure 'merge FETCH_HEAD octopus non-fast-forward (ff)' '\n+\tt3033_reset &&\n+\tgit reset --hard one &&\n+\tgit fetch . left right &&\n+\tgit merge --no-ff FETCH_HEAD &&\n+\t# one is ancestor of three (left) and four (right)\n+\ttest_must_fail git rev-parse --verify HEAD^4 &&\n+\tgit rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual &&\n+\tgit rev-parse one three four | sort >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_failure 'merge FETCH_HEAD octopus fast-forward (does not ff)' '\n+\tt3033_reset &&\n+\tgit fetch . left right &&\n+\tgit merge FETCH_HEAD &&\n+\t# two (master) is not an ancestor of three (left) and four (right)\n+\ttest_must_fail git rev-parse --verify HEAD^4 &&\n+\tgit rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual &&\n+\tgit rev-parse two three four | sort >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_failure 'merge FETCH_HEAD octopus non-fast-forward' '\n+\tt3033_reset &&\n+\tgit fetch . left right &&\n+\tgit merge --no-ff FETCH_HEAD &&\n+\ttest_must_fail git rev-parse --verify HEAD^4 &&\n+\tgit rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual &&\n+\tgit rev-parse two three four | sort >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_done\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260224","messageId":"1430342973-30344-3-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 02/15] merge: simplify code flow","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:20Z","receivedAt":"2015-04-29T21:29:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"One of the first things cmd_merge() does is to see if the \"--abort\"\noption is given and run \"reset --merge\" and exit.  When the control\nreaches this point, we know \"--abort\" was not given.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex bebbe5b..8477878 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1165,15 +1165,15 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\toption_commit = 0;\n \t}\n \n-\tif (!abort_current_merge) {\n-\t\tif (!argc) {\n-\t\t\tif (default_to_upstream)\n-\t\t\t\targc = setup_with_upstream(&argv);\n-\t\t\telse\n-\t\t\t\tdie(_(\"No commit specified and merge.defaultToUpstream not set.\"));\n-\t\t} else if (argc == 1 && !strcmp(argv[0], \"-\"))\n-\t\t\targv[0] = \"@{-1}\";\n+\tif (!argc) {\n+\t\tif (default_to_upstream)\n+\t\t\targc = setup_with_upstream(&argv);\n+\t\telse\n+\t\t\tdie(_(\"No commit specified and merge.defaultToUpstream not set.\"));\n+\t} else if (argc == 1 && !strcmp(argv[0], \"-\")) {\n+\t\targv[0] = \"@{-1}\";\n \t}\n+\n \tif (!argc)\n \t\tusage_with_options(builtin_merge_usage,\n \t\t\tbuiltin_merge_options);\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260214","messageId":"1430342973-30344-4-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 03/15] t5520: style fixes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:21Z","receivedAt":"2015-04-29T21:29:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fix style funnies in early part of this test script that checks \"git\npull\" into an unborn branch.  The primary change is that 'chdir' to\na newly created empty test repository is now protected by being done\nin a subshell to make it more robust without having to chdir back to\nthe original place.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t5520-pull.sh | 22 ++++++----------------\n 1 file changed, 6 insertions(+), 16 deletions(-)\n\ndiff --git a/t/t5520-pull.sh b/t/t5520-pull.sh\nindex 227d293..5195a21 100755\n--- a/t/t5520-pull.sh\n+++ b/t/t5520-pull.sh\n@@ -9,36 +9,27 @@ modify () {\n \tmv \"$2.x\" \"$2\"\n }\n \n-D=`pwd`\n-\n test_expect_success setup '\n-\n \techo file >file &&\n \tgit add file &&\n \tgit commit -a -m original\n-\n '\n \n test_expect_success 'pulling into void' '\n-\tmkdir cloned &&\n-\tcd cloned &&\n-\tgit init &&\n-\tgit pull ..\n-'\n-\n-cd \"$D\"\n-\n-test_expect_success 'checking the results' '\n+\tgit init cloned &&\n+\t(\n+\t\tcd cloned &&\n+\t\tgit pull ..\n+\t) &&\n \ttest -f file &&\n \ttest -f cloned/file &&\n \ttest_cmp file cloned/file\n '\n \n test_expect_success 'pulling into void using master:master' '\n-\tmkdir cloned-uho &&\n+\tgit init cloned-uho &&\n \t(\n \t\tcd cloned-uho &&\n-\t\tgit init &&\n \t\tgit pull .. master:master\n \t) &&\n \ttest -f file &&\n@@ -71,7 +62,6 @@ test_expect_success 'pulling into void does not overwrite staged files' '\n \t)\n '\n \n-\n test_expect_success 'pulling into void does not remove new staged files' '\n \tgit init cloned-staged-new &&\n \t(\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260217","messageId":"1430342973-30344-5-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 04/15] t5520: test pulling an octopus into an unborn branch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:22Z","receivedAt":"2015-04-29T21:29:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The code comment for \"git merge\" in builtin/merge.c, we say\n\n    If the merged head is a valid one there is no reason\n    to forbid \"git merge\" into a branch yet to be born.\n    We do the same for \"git pull\".\n\nand t5520 does have an existing test for that behaviour.  However,\nthere was no test to make sure that 'git pull' to pull multiple\nbranches into an unborn branch must fail.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t5520-pull.sh | 9 +++++++++\n 1 file changed, 9 insertions(+)\n\ndiff --git a/t/t5520-pull.sh b/t/t5520-pull.sh\nindex 5195a21..7efd45b 100755\n--- a/t/t5520-pull.sh\n+++ b/t/t5520-pull.sh\n@@ -76,6 +76,15 @@ test_expect_success 'pulling into void does not remove new staged files' '\n \t)\n '\n \n+test_expect_success 'pulling into void must not create an octopus' '\n+\tgit init cloned-octopus &&\n+\t(\n+\t\tcd cloned-octopus &&\n+\t\ttest_must_fail git pull .. master master &&\n+\t\t! test -f file\n+\t)\n+'\n+\n test_expect_success 'test . as a remote' '\n \n \tgit branch copy master &&\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260213","messageId":"1430342973-30344-6-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 05/15] merge: clarify \"pulling into void\" special case","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:23Z","receivedAt":"2015-04-29T21:29:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Instead of having it as one of the three if/elseif/.. case arms,\ntest the condition and handle this special case upfront.  This makes\nit easier to follow the flow of logic.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 35 ++++++++++++++++++-----------------\n 1 file changed, 18 insertions(+), 17 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 8477878..878f82a 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1178,23 +1178,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(builtin_merge_usage,\n \t\t\tbuiltin_merge_options);\n \n-\t/*\n-\t * This could be traditional \"merge <msg> HEAD <commit>...\"  and\n-\t * the way we can tell it is to see if the second token is HEAD,\n-\t * but some people might have misused the interface and used a\n-\t * commit-ish that is the same as HEAD there instead.\n-\t * Traditional format never would have \"-m\" so it is an\n-\t * additional safety measure to check for it.\n-\t */\n-\n-\tif (!have_message && head_commit &&\n-\t    is_old_style_invocation(argc, argv, head_commit->object.sha1)) {\n-\t\tstrbuf_addstr(&merge_msg, argv[0]);\n-\t\thead_arg = argv[1];\n-\t\targv += 2;\n-\t\targc -= 2;\n-\t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n-\t} else if (!head_commit) {\n+\tif (!head_commit) {\n \t\tstruct commit *remote_head;\n \t\t/*\n \t\t * If the merged head is a valid one there is no reason\n@@ -1217,6 +1201,23 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\tupdate_ref(\"initial pull\", \"HEAD\", remote_head->object.sha1,\n \t\t\t   NULL, 0, UPDATE_REFS_DIE_ON_ERR);\n \t\tgoto done;\n+\t}\n+\n+\t/*\n+\t * This could be traditional \"merge <msg> HEAD <commit>...\"  and\n+\t * the way we can tell it is to see if the second token is HEAD,\n+\t * but some people might have misused the interface and used a\n+\t * commit-ish that is the same as HEAD there instead.\n+\t * Traditional format never would have \"-m\" so it is an\n+\t * additional safety measure to check for it.\n+\t */\n+\tif (!have_message &&\n+\t    is_old_style_invocation(argc, argv, head_commit->object.sha1)) {\n+\t\tstrbuf_addstr(&merge_msg, argv[0]);\n+\t\thead_arg = argv[1];\n+\t\targv += 2;\n+\t\targc -= 2;\n+\t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n \t} else {\n \t\tstruct strbuf merge_names = STRBUF_INIT;\n \n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260215","messageId":"1430342973-30344-7-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 06/15] merge: do not check argc to determine number of remote heads","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:24Z","receivedAt":"2015-04-29T21:29:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"To reject merging multiple commits into an unborn branch, we check\nargc, thinking that collect_parents() that reads the remaining\ncommand line arguments from <argc, argv> will give us the same\nnumber of commits as its input, i.e. argc.\n\nBecause what we really care about is the number of commits, let the\nfunction run and then make sure it returns only one commit instead.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 878f82a..1d4fbd3 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1185,9 +1185,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t * to forbid \"git merge\" into a branch yet to be born.\n \t\t * We do the same for \"git pull\".\n \t\t */\n-\t\tif (argc != 1)\n-\t\t\tdie(_(\"Can merge only exactly one commit into \"\n-\t\t\t\t\"empty head\"));\n \t\tif (squash)\n \t\t\tdie(_(\"Squash commit into empty head not supported yet\"));\n \t\tif (fast_forward == FF_NO)\n@@ -1197,6 +1194,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\tremote_head = remoteheads->item;\n \t\tif (!remote_head)\n \t\t\tdie(_(\"%s - not something we can merge\"), argv[0]);\n+\t\tif (remoteheads->next)\n+\t\t\tdie(_(\"Can merge only exactly one commit into empty head\"));\n \t\tread_empty(remote_head->object.sha1, 0);\n \t\tupdate_ref(\"initial pull\", \"HEAD\", remote_head->object.sha1,\n \t\t\t   NULL, 0, UPDATE_REFS_DIE_ON_ERR);\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260218","messageId":"1430342973-30344-8-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 07/15] merge: small leakfix and code simplification","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:25Z","receivedAt":"2015-04-29T21:29:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When parsing a merged object name like \"foo~20\" to formulate a merge\nsummary \"Merge branch foo (early part)\", a temporary strbuf is used,\nbut we forgot to deallocate it when we failed to find the named\nbranch.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 1d4fbd3..b2d0332 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -491,8 +491,7 @@ static void merge_name(const char *remote, struct strbuf *msg)\n \t}\n \tif (len) {\n \t\tstruct strbuf truname = STRBUF_INIT;\n-\t\tstrbuf_addstr(&truname, \"refs/heads/\");\n-\t\tstrbuf_addstr(&truname, remote);\n+\t\tstrbuf_addf(&truname, \"refs/heads/%s\", remote);\n \t\tstrbuf_setlen(&truname, truname.len - len);\n \t\tif (ref_exists(truname.buf)) {\n \t\t\tstrbuf_addf(msg,\n@@ -503,6 +502,7 @@ static void merge_name(const char *remote, struct strbuf *msg)\n \t\t\tstrbuf_release(&truname);\n \t\t\tgoto cleanup;\n \t\t}\n+\t\tstrbuf_release(&truname);\n \t}\n \n \tif (!strcmp(remote, \"FETCH_HEAD\") &&\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260222","messageId":"1430342973-30344-9-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 08/15] merge: clarify collect_parents() logic","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:26Z","receivedAt":"2015-04-29T21:29:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Clarify this small function in three ways.\n\n - The function initially collects all commits to be merged into a\n   commit_list \"remoteheads\"; the \"remotes\" pointer always points at\n   the tail of this list (either the remoteheads variable itself, or\n   the ->next slot of the element at the end of the list) to help\n   elongate the list by repeated calls to commit_list_insert().\n   Because the new element appended by commit_list_insert() will\n   always have its ->next slot NULLed out, there is no need for us\n   to assign NULL to *remotes to terminate the list at the end.\n\n - The variable \"head_subsumed\" always confused me every time I read\n   this code.  What is happening here is that we inspect what the\n   caller told us to merge (including the current HEAD) and come up\n   with the list of parents to be recorded for the resulting merge\n   commit, omitting commits that are ancestor of other commits.\n   This filtering may remove the current HEAD from the resulting\n   parent list---and we signal that fact with this variable, so that\n   we can later record it as the first parent when \"--no-ff\" is in\n   effect.\n\n - The \"parents\" list is created for this function by reduce_heads()\n   and was not deallocated after its use, even though the loop\n   control was written in such a way to allow us to do so by taking\n   the \"next\" element in a separate variable so that it can be used\n   in the next-step part of the loop control.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 13 +++++++++++--\n 1 file changed, 11 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex b2d0332..d2e36e2 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1061,11 +1061,19 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \t\t\t\t\t \"not something we can merge\");\n \t\tremotes = &commit_list_insert(commit, remotes)->next;\n \t}\n-\t*remotes = NULL;\n \n+\t/*\n+\t * Is the current HEAD reachable from another commit being\n+\t * merged?  If so we do not want to record it as a parent of\n+\t * the resulting merge, unless --no-ff is given.  We will flip\n+\t * this variable to 0 when we find HEAD among the independent\n+\t * tips being merged.\n+\t */\n+\t*head_subsumed = 1;\n+\n+\t/* Find what parents to record by checking independent ones. */\n \tparents = reduce_heads(remoteheads);\n \n-\t*head_subsumed = 1; /* we will flip this to 0 when we find it */\n \tfor (remoteheads = NULL, remotes = &remoteheads;\n \t     parents;\n \t     parents = next) {\n@@ -1075,6 +1083,7 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \t\t\t*head_subsumed = 0;\n \t\telse\n \t\t\tremotes = &commit_list_insert(commit, remotes)->next;\n+\t\tfree(parents);\n \t}\n \treturn remoteheads;\n }\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260219","messageId":"1430342973-30344-10-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 09/15] merge: split reduce_parents() out of collect_parents()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:27Z","receivedAt":"2015-04-29T21:29:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The latter does two separate things:\n\n - Parse the list of commits on the command line, and formulate the\n   list of commits to be merged (including the current HEAD);\n\n - Compute the list of parents to be recorded in the resulting merge\n   commit.\n\nSplit the latter into a separate helper function, so that we can\nlater supply the list commits to be merged from a different source\n(namely, FETCH_HEAD).\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 41 +++++++++++++++++++++++++----------------\n 1 file changed, 25 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex d2e36e2..054f052 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1044,23 +1044,11 @@ static int default_edit_option(void)\n \t\tst_stdin.st_mode == st_stdout.st_mode);\n }\n \n-static struct commit_list *collect_parents(struct commit *head_commit,\n-\t\t\t\t\t   int *head_subsumed,\n-\t\t\t\t\t   int argc, const char **argv)\n+static struct commit_list *reduce_parents(struct commit *head_commit,\n+\t\t\t\t\t  int *head_subsumed,\n+\t\t\t\t\t  struct commit_list *remoteheads)\n {\n-\tint i;\n-\tstruct commit_list *remoteheads = NULL, *parents, *next;\n-\tstruct commit_list **remotes = &remoteheads;\n-\n-\tif (head_commit)\n-\t\tremotes = &commit_list_insert(head_commit, remotes)->next;\n-\tfor (i = 0; i < argc; i++) {\n-\t\tstruct commit *commit = get_merge_parent(argv[i]);\n-\t\tif (!commit)\n-\t\t\thelp_unknown_ref(argv[i], \"merge\",\n-\t\t\t\t\t \"not something we can merge\");\n-\t\tremotes = &commit_list_insert(commit, remotes)->next;\n-\t}\n+\tstruct commit_list *parents, *next, **remotes = &remoteheads;\n \n \t/*\n \t * Is the current HEAD reachable from another commit being\n@@ -1088,6 +1076,27 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \treturn remoteheads;\n }\n \n+static struct commit_list *collect_parents(struct commit *head_commit,\n+\t\t\t\t\t   int *head_subsumed,\n+\t\t\t\t\t   int argc, const char **argv)\n+{\n+\tint i;\n+\tstruct commit_list *remoteheads = NULL;\n+\tstruct commit_list **remotes = &remoteheads;\n+\n+\tif (head_commit)\n+\t\tremotes = &commit_list_insert(head_commit, remotes)->next;\n+\tfor (i = 0; i < argc; i++) {\n+\t\tstruct commit *commit = get_merge_parent(argv[i]);\n+\t\tif (!commit)\n+\t\t\thelp_unknown_ref(argv[i], \"merge\",\n+\t\t\t\t\t \"not something we can merge\");\n+\t\tremotes = &commit_list_insert(commit, remotes)->next;\n+\t}\n+\n+\treturn reduce_parents(head_commit, head_subsumed, remoteheads);\n+}\n+\n int cmd_merge(int argc, const char **argv, const char *prefix)\n {\n \tunsigned char result_tree[20];\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260220","messageId":"1430342973-30344-11-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 10/15] merge: narrow scope of merge_names","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:28Z","receivedAt":"2015-04-29T21:29:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"In order to pass the list of parents to fmt_merge_msg(), cmd_merge()\nuses this strbuf to create something that look like FETCH_HEAD that\ndescribes commits that are being merged.  This is necessary only\nwhen we are creating the merge commit message ourselves, but was\ndone unconditionally.\n\nMove the variable and the logic to populate it to confine them in a\nblock that needs them.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 11 +++++++----\n 1 file changed, 7 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 054f052..d853c9d 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1236,8 +1236,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\targc -= 2;\n \t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n \t} else {\n-\t\tstruct strbuf merge_names = STRBUF_INIT;\n-\n \t\t/* We are invoked directly as the first-class UI. */\n \t\thead_arg = \"HEAD\";\n \n@@ -1247,11 +1245,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t * to the given message.\n \t\t */\n \t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n-\t\tfor (p = remoteheads; p; p = p->next)\n-\t\t\tmerge_name(merge_remote_util(p->item)->name, &merge_names);\n \n \t\tif (!have_message || shortlog_len) {\n+\t\t\tstruct strbuf merge_names = STRBUF_INIT;\n \t\t\tstruct fmt_merge_msg_opts opts;\n+\n+\t\t\tfor (p = remoteheads; p; p = p->next)\n+\t\t\t\tmerge_name(merge_remote_util(p->item)->name, &merge_names);\n+\n \t\t\tmemset(&opts, 0, sizeof(opts));\n \t\t\topts.add_title = !have_message;\n \t\t\topts.shortlog_len = shortlog_len;\n@@ -1260,6 +1261,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t\tfmt_merge_msg(&merge_names, &merge_msg, &opts);\n \t\t\tif (merge_msg.len)\n \t\t\t\tstrbuf_setlen(&merge_msg, merge_msg.len - 1);\n+\n+\t\t\tstrbuf_release(&merge_names);\n \t\t}\n \t}\n \n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260216","messageId":"1430342973-30344-12-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 11/15] merge: extract prepare_merge_message() logic out","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:29Z","receivedAt":"2015-04-29T21:29:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 26 +++++++++++++++-----------\n 1 file changed, 15 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex d853c9d..a972ed6 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1076,6 +1076,20 @@ static struct commit_list *reduce_parents(struct commit *head_commit,\n \treturn remoteheads;\n }\n \n+static void prepare_merge_message(struct strbuf *merge_names, struct strbuf *merge_msg)\n+{\n+\tstruct fmt_merge_msg_opts opts;\n+\n+\tmemset(&opts, 0, sizeof(opts));\n+\topts.add_title = !have_message;\n+\topts.shortlog_len = shortlog_len;\n+\topts.credit_people = (0 < option_edit);\n+\n+\tfmt_merge_msg(merge_names, merge_msg, &opts);\n+\tif (merge_msg->len)\n+\t\tstrbuf_setlen(merge_msg, merge_msg->len - 1);\n+}\n+\n static struct commit_list *collect_parents(struct commit *head_commit,\n \t\t\t\t\t   int *head_subsumed,\n \t\t\t\t\t   int argc, const char **argv)\n@@ -1248,20 +1262,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \n \t\tif (!have_message || shortlog_len) {\n \t\t\tstruct strbuf merge_names = STRBUF_INIT;\n-\t\t\tstruct fmt_merge_msg_opts opts;\n \n \t\t\tfor (p = remoteheads; p; p = p->next)\n \t\t\t\tmerge_name(merge_remote_util(p->item)->name, &merge_names);\n-\n-\t\t\tmemset(&opts, 0, sizeof(opts));\n-\t\t\topts.add_title = !have_message;\n-\t\t\topts.shortlog_len = shortlog_len;\n-\t\t\topts.credit_people = (0 < option_edit);\n-\n-\t\t\tfmt_merge_msg(&merge_names, &merge_msg, &opts);\n-\t\t\tif (merge_msg.len)\n-\t\t\t\tstrbuf_setlen(&merge_msg, merge_msg.len - 1);\n-\n+\t\t\tprepare_merge_message(&merge_names, &merge_msg);\n \t\t\tstrbuf_release(&merge_names);\n \t\t}\n \t}\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260223","messageId":"1430342973-30344-13-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 12/15] merge: make collect_parents() auto-generate the merge message","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:30Z","receivedAt":"2015-04-29T21:29:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 36 ++++++++++++++++++++++--------------\n 1 file changed, 22 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex a972ed6..9f98538 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1092,7 +1092,8 @@ static void prepare_merge_message(struct strbuf *merge_names, struct strbuf *mer\n \n static struct commit_list *collect_parents(struct commit *head_commit,\n \t\t\t\t\t   int *head_subsumed,\n-\t\t\t\t\t   int argc, const char **argv)\n+\t\t\t\t\t   int argc, const char **argv,\n+\t\t\t\t\t   struct strbuf *merge_msg)\n {\n \tint i;\n \tstruct commit_list *remoteheads = NULL;\n@@ -1108,7 +1109,20 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \t\tremotes = &commit_list_insert(commit, remotes)->next;\n \t}\n \n-\treturn reduce_parents(head_commit, head_subsumed, remoteheads);\n+\tremoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);\n+\n+\tif (merge_msg &&\n+\t    (!have_message || shortlog_len)) {\n+\t\tstruct strbuf merge_names = STRBUF_INIT;\n+\t\tstruct commit_list *p;\n+\n+\t\tfor (p = remoteheads; p; p = p->next)\n+\t\t\tmerge_name(merge_remote_util(p->item)->name, &merge_names);\n+\t\tprepare_merge_message(&merge_names, merge_msg);\n+\t\tstrbuf_release(&merge_names);\n+\t}\n+\n+\treturn remoteheads;\n }\n \n int cmd_merge(int argc, const char **argv, const char *prefix)\n@@ -1222,7 +1236,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\tif (fast_forward == FF_NO)\n \t\t\tdie(_(\"Non-fast-forward commit does not make sense into \"\n \t\t\t    \"an empty head\"));\n-\t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n+\t\tremoteheads = collect_parents(head_commit, &head_subsumed,\n+\t\t\t\t\t      argc, argv, NULL);\n \t\tremote_head = remoteheads->item;\n \t\tif (!remote_head)\n \t\t\tdie(_(\"%s - not something we can merge\"), argv[0]);\n@@ -1248,7 +1263,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\thead_arg = argv[1];\n \t\targv += 2;\n \t\targc -= 2;\n-\t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n+\t\tremoteheads = collect_parents(head_commit, &head_subsumed,\n+\t\t\t\t\t      argc, argv, NULL);\n \t} else {\n \t\t/* We are invoked directly as the first-class UI. */\n \t\thead_arg = \"HEAD\";\n@@ -1258,16 +1274,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t * the standard merge summary message to be appended\n \t\t * to the given message.\n \t\t */\n-\t\tremoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);\n-\n-\t\tif (!have_message || shortlog_len) {\n-\t\t\tstruct strbuf merge_names = STRBUF_INIT;\n-\n-\t\t\tfor (p = remoteheads; p; p = p->next)\n-\t\t\t\tmerge_name(merge_remote_util(p->item)->name, &merge_names);\n-\t\t\tprepare_merge_message(&merge_names, &merge_msg);\n-\t\t\tstrbuf_release(&merge_names);\n-\t\t}\n+\t\tremoteheads = collect_parents(head_commit, &head_subsumed,\n+\t\t\t\t\t      argc, argv, &merge_msg);\n \t}\n \n \tif (!head_commit || !argc)\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260221","messageId":"1430342973-30344-14-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 13/15] merge: decide if we auto-generate the message early in collect_parents()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:31Z","receivedAt":"2015-04-29T21:29:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c | 16 +++++++++-------\n 1 file changed, 9 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 9f98538..eb3be68 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1098,6 +1098,10 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \tint i;\n \tstruct commit_list *remoteheads = NULL;\n \tstruct commit_list **remotes = &remoteheads;\n+\tstruct strbuf merge_names = STRBUF_INIT, *autogen = NULL;\n+\n+\tif (merge_msg && (!have_message || shortlog_len))\n+\t\tautogen = &merge_names;\n \n \tif (head_commit)\n \t\tremotes = &commit_list_insert(head_commit, remotes)->next;\n@@ -1111,15 +1115,13 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \n \tremoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);\n \n-\tif (merge_msg &&\n-\t    (!have_message || shortlog_len)) {\n-\t\tstruct strbuf merge_names = STRBUF_INIT;\n+\tif (autogen) {\n \t\tstruct commit_list *p;\n-\n \t\tfor (p = remoteheads; p; p = p->next)\n-\t\t\tmerge_name(merge_remote_util(p->item)->name, &merge_names);\n-\t\tprepare_merge_message(&merge_names, merge_msg);\n-\t\tstrbuf_release(&merge_names);\n+\t\t\tmerge_name(merge_remote_util(p->item)->name, autogen);\n+\n+\t\tprepare_merge_message(autogen, merge_msg);\n+\t\tstrbuf_release(autogen);\n \t}\n \n \treturn remoteheads;\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260225","messageId":"1430342973-30344-15-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 14/15] merge: handle FETCH_HEAD internally","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:32Z","receivedAt":"2015-04-29T21:29:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The collect_parents() function now is responsible for\n\n 1. parsing the commits given on the command line into a list of\n    commits to be merged;\n\n 2. filtering these parents into independent ones; and\n\n 3. optionally calling fmt_merge_msg() via prepare_merge_message()\n    to prepare an auto-generated merge log message, using fake\n    contents that FETCH_HEAD would have had if these commits were\n    fetched from the current repository with \"git pull . $args...\"\n\nMake \"git merge FETCH_HEAD\" to be the same as the traditional\n\n    git merge \"$(git fmt-merge-msg <.git/FETCH_HEAD)\" $commits\n\ninvocation of the command in \"git pull\", where $commits are the ones\nthat appear in FETCH_HEAD that are not marked as not-for-merge, by\nmaking it do a bit more, specifically:\n\n - noticing \"FETCH_HEAD\" is the only \"commit\" on the command line\n   and picking the commits that are not marked as not-for-merge as\n   the list of commits to be merged (substitute for step #1 above);\n\n - letting the resulting list fed to step #2 above;\n\n - doing the step #3 above, using the contents of the FETCH_HEAD\n   instead of fake contents crafted from the list of commits parsed\n   in the step #1 above.\n\nNote that this changes the semantics.  \"git merge FETCH_HEAD\" has\nalways behaved as if the first commit in the FETCH_HEAD file were\ndirectly specified on the command line, creating a two-way merge\nwhose auto-generated merge log said \"merge commit xyz\".  With this\nchange, if the previous fetch was to grab multiple branches (e.g.\n\"git fetch $there topic-a topic-b\"), the new world order is to\ncreate an octopus, behaving as if \"git pull $there topic-a topic-b\"\nwere run.  This is a deliberate change to make that happen, and\ncan be seen in the changes to t3033 tests.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-merge.txt |   4 ++\n builtin/merge.c             | 106 ++++++++++++++++++++++++++++++--------------\n t/t3033-merge-toplevel.sh   |  10 ++---\n 3 files changed, 81 insertions(+), 39 deletions(-)\n\ndiff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt\nindex cf2c374..d9aa6b6 100644\n--- a/Documentation/git-merge.txt\n+++ b/Documentation/git-merge.txt\n@@ -104,6 +104,10 @@ commit or stash your changes before running 'git merge'.\n If no commit is given from the command line, merge the remote-tracking\n branches that the current branch is configured to use as its upstream.\n See also the configuration section of this manual page.\n++\n+When `FETCH_HEAD` (and no other commit) is specified, the branches\n+recorded in the `.git/FETCH_HEAD` file by the previous invocation\n+of `git fetch` for merging are merged to the current branch.\n \n \n PRE-MERGE CHECKS\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex eb3be68..42f9fcc 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -505,28 +505,6 @@ static void merge_name(const char *remote, struct strbuf *msg)\n \t\tstrbuf_release(&truname);\n \t}\n \n-\tif (!strcmp(remote, \"FETCH_HEAD\") &&\n-\t\t\t!access(git_path(\"FETCH_HEAD\"), R_OK)) {\n-\t\tconst char *filename;\n-\t\tFILE *fp;\n-\t\tstruct strbuf line = STRBUF_INIT;\n-\t\tchar *ptr;\n-\n-\t\tfilename = git_path(\"FETCH_HEAD\");\n-\t\tfp = fopen(filename, \"r\");\n-\t\tif (!fp)\n-\t\t\tdie_errno(_(\"could not open '%s' for reading\"),\n-\t\t\t\t  filename);\n-\t\tstrbuf_getline(&line, fp, '\\n');\n-\t\tfclose(fp);\n-\t\tptr = strstr(line.buf, \"\\tnot-for-merge\\t\");\n-\t\tif (ptr)\n-\t\t\tstrbuf_remove(&line, ptr-line.buf+1, 13);\n-\t\tstrbuf_addbuf(msg, &line);\n-\t\tstrbuf_release(&line);\n-\t\tgoto cleanup;\n-\t}\n-\n \tif (remote_head->util) {\n \t\tstruct merge_remote_desc *desc;\n \t\tdesc = merge_remote_util(remote_head);\n@@ -1090,6 +1068,60 @@ static void prepare_merge_message(struct strbuf *merge_names, struct strbuf *mer\n \t\tstrbuf_setlen(merge_msg, merge_msg->len - 1);\n }\n \n+static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge_names)\n+{\n+\tconst char *filename;\n+\tint fd, pos, npos;\n+\tstruct strbuf fetch_head_file = STRBUF_INIT;\n+\n+\tif (!merge_names)\n+\t\tmerge_names = &fetch_head_file;\n+\n+\tfilename = git_path(\"FETCH_HEAD\");\n+\tfd = open(filename, O_RDONLY);\n+\tif (fd < 0)\n+\t\tdie_errno(_(\"could not open '%s' for reading\"), filename);\n+\n+\tif (strbuf_read(merge_names, fd, 0) < 0)\n+\t\tdie_errno(_(\"could not read '%s'\"), filename);\n+\tif (close(fd) < 0)\n+\t\tdie_errno(_(\"could not close '%s'\"), filename);\n+\n+\tfor (pos = 0; pos < merge_names->len; pos = npos) {\n+\t\tunsigned char sha1[20];\n+\t\tchar *ptr;\n+\t\tstruct commit *commit;\n+\n+\t\tptr = strchr(merge_names->buf + pos, '\\n');\n+\t\tif (ptr)\n+\t\t\tnpos = ptr - merge_names->buf + 1;\n+\t\telse\n+\t\t\tnpos = merge_names->len;\n+\n+\t\tif (npos - pos < 40 + 2 ||\n+\t\t    get_sha1_hex(merge_names->buf + pos, sha1))\n+\t\t\tcommit = NULL; /* bad */\n+\t\telse if (memcmp(merge_names->buf + pos + 40, \"\\t\\t\", 2))\n+\t\t\tcontinue; /* not-for-merge */\n+\t\telse {\n+\t\t\tchar saved = merge_names->buf[pos + 40];\n+\t\t\tmerge_names->buf[pos + 40] = '\\0';\n+\t\t\tcommit = get_merge_parent(merge_names->buf + pos);\n+\t\t\tmerge_names->buf[pos + 40] = saved;\n+\t\t}\n+\t\tif (!commit) {\n+\t\t\tif (ptr)\n+\t\t\t\t*ptr = '\\0';\n+\t\t\tdie(\"not something we can merge in %s: %s\",\n+\t\t\t    filename, merge_names->buf + pos);\n+\t\t}\n+\t\tremotes = &commit_list_insert(commit, remotes)->next;\n+\t}\n+\n+\tif (merge_names == &fetch_head_file)\n+\t\tstrbuf_release(&fetch_head_file);\n+}\n+\n static struct commit_list *collect_parents(struct commit *head_commit,\n \t\t\t\t\t   int *head_subsumed,\n \t\t\t\t\t   int argc, const char **argv,\n@@ -1105,21 +1137,27 @@ static struct commit_list *collect_parents(struct commit *head_commit,\n \n \tif (head_commit)\n \t\tremotes = &commit_list_insert(head_commit, remotes)->next;\n-\tfor (i = 0; i < argc; i++) {\n-\t\tstruct commit *commit = get_merge_parent(argv[i]);\n-\t\tif (!commit)\n-\t\t\thelp_unknown_ref(argv[i], \"merge\",\n-\t\t\t\t\t \"not something we can merge\");\n-\t\tremotes = &commit_list_insert(commit, remotes)->next;\n-\t}\n \n-\tremoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);\n+\tif (argc == 1 && !strcmp(argv[0], \"FETCH_HEAD\")) {\n+\t\thandle_fetch_head(remotes, autogen);\n+\t\tremoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);\n+\t} else {\n+\t\tfor (i = 0; i < argc; i++) {\n+\t\t\tstruct commit *commit = get_merge_parent(argv[i]);\n+\t\t\tif (!commit)\n+\t\t\t\thelp_unknown_ref(argv[i], \"merge\",\n+\t\t\t\t\t\t \"not something we can merge\");\n+\t\t\tremotes = &commit_list_insert(commit, remotes)->next;\n+\t\t}\n+\t\tremoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);\n+\t\tif (autogen) {\n+\t\t\tstruct commit_list *p;\n+\t\t\tfor (p = remoteheads; p; p = p->next)\n+\t\t\t\tmerge_name(merge_remote_util(p->item)->name, autogen);\n+\t\t}\n+\t}\n \n \tif (autogen) {\n-\t\tstruct commit_list *p;\n-\t\tfor (p = remoteheads; p; p = p->next)\n-\t\t\tmerge_name(merge_remote_util(p->item)->name, autogen);\n-\n \t\tprepare_merge_message(autogen, merge_msg);\n \t\tstrbuf_release(autogen);\n \t}\ndiff --git a/t/t3033-merge-toplevel.sh b/t/t3033-merge-toplevel.sh\nindex 9d92d3c..46aadc4 100755\n--- a/t/t3033-merge-toplevel.sh\n+++ b/t/t3033-merge-toplevel.sh\n@@ -77,7 +77,7 @@ test_expect_success 'merge octopus, non-fast-forward' '\n \n # The same set with FETCH_HEAD\n \n-test_expect_failure 'merge FETCH_HEAD octopus into void' '\n+test_expect_success 'merge FETCH_HEAD octopus into void' '\n \tt3033_reset &&\n \tgit checkout --orphan test &&\n \tgit rm -fr . &&\n@@ -88,7 +88,7 @@ test_expect_failure 'merge FETCH_HEAD octopus into void' '\n \ttest_must_fail git rev-parse HEAD\n '\n \n-test_expect_failure 'merge FETCH_HEAD octopus fast-forward (ff)' '\n+test_expect_success 'merge FETCH_HEAD octopus fast-forward (ff)' '\n \tt3033_reset &&\n \tgit reset --hard one &&\n \tgit fetch . left right &&\n@@ -100,7 +100,7 @@ test_expect_failure 'merge FETCH_HEAD octopus fast-forward (ff)' '\n \ttest_cmp expect actual\n '\n \n-test_expect_failure 'merge FETCH_HEAD octopus non-fast-forward (ff)' '\n+test_expect_success 'merge FETCH_HEAD octopus non-fast-forward (ff)' '\n \tt3033_reset &&\n \tgit reset --hard one &&\n \tgit fetch . left right &&\n@@ -112,7 +112,7 @@ test_expect_failure 'merge FETCH_HEAD octopus non-fast-forward (ff)' '\n \ttest_cmp expect actual\n '\n \n-test_expect_failure 'merge FETCH_HEAD octopus fast-forward (does not ff)' '\n+test_expect_success 'merge FETCH_HEAD octopus fast-forward (does not ff)' '\n \tt3033_reset &&\n \tgit fetch . left right &&\n \tgit merge FETCH_HEAD &&\n@@ -123,7 +123,7 @@ test_expect_failure 'merge FETCH_HEAD octopus fast-forward (does not ff)' '\n \ttest_cmp expect actual\n '\n \n-test_expect_failure 'merge FETCH_HEAD octopus non-fast-forward' '\n+test_expect_success 'merge FETCH_HEAD octopus non-fast-forward' '\n \tt3033_reset &&\n \tgit fetch . left right &&\n \tgit merge --no-ff FETCH_HEAD &&\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260226","messageId":"1430342973-30344-16-git-send-email-gitster@pobox.com","threadId":"39111","inReplyTo":"1430342973-30344-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 15/15] merge: deprecate 'git merge <message> HEAD <commit>' syntax","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-29T21:29:33Z","receivedAt":"2015-04-29T21:29:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We had this in \"git merge\" manual for eternity:\n\n    'git merge' <msg> HEAD <commit>...\n\n    [This] syntax (<msg> `HEAD` <commit>...) is supported for\n    historical reasons.  Do not use it from the command line or in\n    new scripts.  It is the same as `git merge -m <msg> <commit>...`.\n\nWith the update to \"git merge\" to make it understand what is\nrecorded in FETCH_HEAD directly, including Octopus merge cases, we\nnow can rewrite the use of this syntax in \"git pull\" with a simple\n\"git merge FETCH_HEAD\".\n\nAlso there are quite a few fallouts in the test scripts, and it\nturns out that \"git cvsimport\" also uses this old syntax to record\na merge.\n\nJudging from this result, I would not be surprised if dropping the\nsupport of the old syntax broke scripts people have written and been\nrelying on for the past ten years.  But at least we can start the\ndeprecation process by throwing a warning message when the syntax is\nused.\n\nWith luck, we might be able to drop the support in a few years.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/merge.c               | 1 +\n git-cvsimport.perl            | 2 +-\n git-pull.sh                   | 3 +--\n t/t3402-rebase-merge.sh       | 2 +-\n t/t6020-merge-df.sh           | 2 +-\n t/t6021-merge-criss-cross.sh  | 6 +++---\n t/t9402-git-cvsserver-refs.sh | 2 +-\n 7 files changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 42f9fcc..67fbfaf 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1299,6 +1299,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t */\n \tif (!have_message &&\n \t    is_old_style_invocation(argc, argv, head_commit->object.sha1)) {\n+\t\twarning(\"old-style 'git merge <msg> HEAD <commit>' is deprecated.\");\n \t\tstrbuf_addstr(&merge_msg, argv[0]);\n \t\thead_arg = argv[1];\n \t\targv += 2;\ndiff --git a/git-cvsimport.perl b/git-cvsimport.perl\nindex 73d367c..82ecb03 100755\n--- a/git-cvsimport.perl\n+++ b/git-cvsimport.perl\n@@ -1162,7 +1162,7 @@ sub commit {\n \t\tdie \"Fast-forward update failed: $?\\n\" if $?;\n \t}\n \telse {\n-\t\tsystem(qw(git merge cvsimport HEAD), \"$remote/$opt_o\");\n+\t\tsystem(qw(git merge -m cvsimport), \"$remote/$opt_o\");\n \t\tdie \"Could not merge $opt_o into the current branch.\\n\" if $?;\n \t}\n } else {\ndiff --git a/git-pull.sh b/git-pull.sh\nindex 4d4fc77..15d9431 100755\n--- a/git-pull.sh\n+++ b/git-pull.sh\n@@ -323,7 +323,6 @@ then\n \tfi\n fi\n \n-merge_name=$(git fmt-merge-msg $log_arg <\"$GIT_DIR/FETCH_HEAD\") || exit\n case \"$rebase\" in\n true)\n \teval=\"git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity\"\n@@ -334,7 +333,7 @@ true)\n \teval=\"git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only\"\n \teval=\"$eval $log_arg $strategy_args $merge_args $verbosity $progress\"\n \teval=\"$eval $gpg_sign_args\"\n-\teval=\"$eval \\\"\\$merge_name\\\" HEAD $merge_head\"\n+\teval=\"$eval FETCH_HEAD\"\n \t;;\n esac\n eval \"exec $eval\"\ndiff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh\nindex 5a27ec9..8f64505 100755\n--- a/t/t3402-rebase-merge.sh\n+++ b/t/t3402-rebase-merge.sh\n@@ -47,7 +47,7 @@ test_expect_success setup '\n '\n \n test_expect_success 'reference merge' '\n-\tgit merge -s recursive \"reference merge\" HEAD master\n+\tgit merge -s recursive -m \"reference merge\" master\n '\n \n PRE_REBASE=$(git rev-parse test-rebase)\ndiff --git a/t/t6020-merge-df.sh b/t/t6020-merge-df.sh\nindex 27c3d73..2af1bee 100755\n--- a/t/t6020-merge-df.sh\n+++ b/t/t6020-merge-df.sh\n@@ -24,7 +24,7 @@ test_expect_success 'prepare repository' '\n '\n \n test_expect_success 'Merge with d/f conflicts' '\n-\ttest_expect_code 1 git merge \"merge msg\" B master\n+\ttest_expect_code 1 git merge -m \"merge msg\" master\n '\n \n test_expect_success 'F/D conflict' '\ndiff --git a/t/t6021-merge-criss-cross.sh b/t/t6021-merge-criss-cross.sh\nindex d15b313..213deec 100755\n--- a/t/t6021-merge-criss-cross.sh\n+++ b/t/t6021-merge-criss-cross.sh\n@@ -48,7 +48,7 @@ echo \"1\n \" > file &&\n git commit -m \"C3\" file &&\n git branch C3 &&\n-git merge \"pre E3 merge\" B A &&\n+git merge -m \"pre E3 merge\" A &&\n echo \"1\n 2\n 3 changed in E3, branch B. New file size\n@@ -61,7 +61,7 @@ echo \"1\n \" > file &&\n git commit -m \"E3\" file &&\n git checkout A &&\n-git merge \"pre D8 merge\" A C3 &&\n+git merge -m \"pre D8 merge\" C3 &&\n echo \"1\n 2\n 3 changed in C3, branch B\n@@ -73,7 +73,7 @@ echo \"1\n 9\" > file &&\n git commit -m D8 file'\n \n-test_expect_success 'Criss-cross merge' 'git merge \"final merge\" A B'\n+test_expect_success 'Criss-cross merge' 'git merge -m \"final merge\" B'\n \n cat > file-expect <<EOF\n 1\ndiff --git a/t/t9402-git-cvsserver-refs.sh b/t/t9402-git-cvsserver-refs.sh\nindex 1e266ef..d00df08 100755\n--- a/t/t9402-git-cvsserver-refs.sh\n+++ b/t/t9402-git-cvsserver-refs.sh\n@@ -496,7 +496,7 @@ test_expect_success 'check [cvswork3] diff' '\n '\n \n test_expect_success 'merge early [cvswork3] b3 with b1' '\n-\t( cd gitwork3 && git merge \"message\" HEAD b1 ) &&\n+\t( cd gitwork3 && git merge -m \"message\" b1 ) &&\n \tgit fetch gitwork3 b3:b3 &&\n \tgit tag v3merged b3 &&\n \tgit push --tags gitcvs.git b3:b3\n-- \n2.4.0-rc3-300-g052d062\n"},{"id":"260309","messageId":"CACRoPnR+OHp1ho-az=C8tE=bczX5h1yEvSozGXVTShB09q1-dg@mail.gmail.com","threadId":"39111","inReplyTo":"1430342973-30344-4-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 03/15] t5520: style fixes","fromName":"Paul Tan","fromEmail":"pyokagan@gmail.com","sentAt":"2015-05-01T08:35:54Z","receivedAt":"2015-05-01T08:35:54Z","isPatch":true,"sender":{"key":"pyokagan@gmail.com","avatar":"https://avatars.githubusercontent.com/u/109479?v=4"},"body":"Hi Junio,\n\nOn Thu, Apr 30, 2015 at 5:29 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Fix style funnies in early part of this test script that checks \"git\n> pull\" into an unborn branch.  The primary change is that 'chdir' to\n> a newly created empty test repository is now protected by being done\n> in a subshell to make it more robust without having to chdir back to\n> the original place.\n> diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh\n> index 227d293..5195a21 100755\n> --- a/t/t5520-pull.sh\n> +++ b/t/t5520-pull.sh\n>  test_expect_success 'pulling into void' '\n> -       mkdir cloned &&\n> -       cd cloned &&\n> -       git init &&\n> -       git pull ..\n> -'\n> -\n> -cd \"$D\"\n> -\n> -test_expect_success 'checking the results' '\n> +       git init cloned &&\n> +       (\n> +               cd cloned &&\n> +               git pull ..\n> +       ) &&\n>         test -f file &&\n>         test -f cloned/file &&\n>         test_cmp file cloned/file\n>  '\n>\n>  test_expect_success 'pulling into void using master:master' '\n> -       mkdir cloned-uho &&\n> +       git init cloned-uho &&\n>         (\n>                 cd cloned-uho &&\n> -               git init &&\n>                 git pull .. master:master\n>         ) &&\n>         test -f file &&\n> @@ -71,7 +62,6 @@ test_expect_success 'pulling into void does not overwrite staged files' '\n>         )\n\nI'm currently studying the t5520 tests in order to improve test\ncoverage of git-pull.sh, and I find it hard to understand whenever\ntests depend on the tests before them in subtle ways.\n\nJust wondering, would it be good to clean up the created repos in the\nabove tests to make it clear that they won't be used anymore?\nSomething like:\n\n    git init cloned &&\n    test_when_finished \"rm -rf cloned\" &&\n    ...\n\nThanks,\nPaul\n"},{"id":"260444","messageId":"xmqq7fsqxw1h.fsf@gitster.dls.corp.google.com","threadId":"39111","inReplyTo":"CACRoPnR+OHp1ho-az=C8tE=bczX5h1yEvSozGXVTShB09q1-dg@mail.gmail.com","subject":"Re: [PATCH v2 03/15] t5520: style fixes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-05-03T01:57:30Z","receivedAt":"2015-05-03T01:57:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Paul Tan <pyokagan@gmail.com> writes:\n\n> Just wondering, would it be good to clean up the created repos in the\n> above tests to make it clear that they won't be used anymore?\n> Something like:\n>\n>     git init cloned &&\n>     test_when_finished \"rm -rf cloned\" &&\n>     ...\n\nIt might be a good idea when you are doing the wholesale style fix\nof the entire script. That was not a part of the scope of my series,\nso I kept my changes to the minimum and made my additions in line\nwith the existing tests (i.e. new one-time-use repository that is\njust left behind without being used by others).\n\nHaving said that, when it is very clear that each of the new\ndirectories are for one-time-use (like the use of them in 5520), I\ntend to prefer leaving them around, if only to make it easier to\ninsert \"exit\", go there and manually inspect the situation, which\nwill become necessary when the tests start failing.\n"}]}