{"thread":{"id":"3071","subject":"Question on empty commit","startedAt":"2006-01-14T02:18:00Z","lastAt":"2006-01-16T23:32:07Z","messageCount":6,"participants":["Luben Tuikov","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"14644","messageId":"20060114021800.4688.qmail@web31803.mail.mud.yahoo.com","threadId":"3071","inReplyTo":null,"subject":"Question on empty commit","fromName":"Luben Tuikov","fromEmail":"ltuikov@yahoo.com","sentAt":"2006-01-14T02:18:00Z","receivedAt":"2006-01-14T02:18:00Z","isPatch":false,"sender":{"key":"ltuikov@yahoo.com","avatar":null},"body":"Hi,\n\nScenario:\n\ntrunk remote\n  |\n  \\/\ntrunk local\n     \\\n      `--> tree A\n               \\\n                `--> tree B\n\n         Figure 1.\n\nThis is the dependecny since project B depends on project A\nintroduced in tree A.  And merging is done as follows\n(branch per directory; everything but HEAD and index is shared):\n\ncd trunk && git pull trunk\ncd ../treeA && git merge \"merge trunk\" HEAD trunk\ncd ../treeB && git merge \"merge tree A\" HEAD treeA\n\nBut this isn't the only way to do it since tree B depends\nonly on the introduced into tree A project A, and both\nproject A and project B depend on the trunk, as follows:\n\ntrunk remote\n  |\n  \\/\ntrunk local\n  \\  \\\n   \\  `--> tree A\n    \\          \\\n     `--------> `--> tree B\n\n         Figure 2.\n\nSo at point in time t where tree B had been synced with tree A,\nand tree A had been synced with trunk, but trunk had _not_ been\nsynced with remote trunk, a merge was done following Figure 2:\n\ncd trunk && git pull trunk\ncd ../treeA && git merge \"merge trunk\" HEAD trunk\ncd ../treeB && git merge \"merge trunk\" HEAD trunk\ngit merge \"merge tree A\" HEAD treeA\n\nNow the last merge introduced an empty commit, since\ntree A and tree B had been in sync (only local and\nremote trunk had been out of sync).  While it was expected\nthat no commit would be introduced since they were in sync.\n\nWas the empty commit correct behavior?\n\nThanks,\n   Luben\n"},{"id":"14681","messageId":"7vmzhx7ref.fsf@assigned-by-dhcp.cox.net","threadId":"3071","inReplyTo":"20060114021800.4688.qmail@web31803.mail.mud.yahoo.com","subject":"Re: Question on empty commit","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-15T09:48:56Z","receivedAt":"2006-01-15T09:48:56Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Luben Tuikov <ltuikov@yahoo.com> writes:\n\n> Now the last merge introduced an empty commit, since\n> tree A and tree B had been in sync (only local and\n> remote trunk had been out of sync).  While it was expected\n> that no commit would be introduced since they were in sync.\n>\n> Was the empty commit correct behavior?\n\nI do not quite follow you, but immediately before the \"empty\ncommit\" (I presume you mean the last \"git merge\" that merges\ntreeA head in treeB), you say \"the treeA and treeB had been in\nsync\".  What do you exactly mean?  The tree object in the head\ncommits in treeA branch and treeB branch were identical?\n\nIf that is the case, the commit being empty is the correct\nbehaviour, because there is no difference in the set of files\nintroduced by that commit.  And the commit being made is also\nthe correct behaviour, because those two branches have different\ndevelopment history, and the commit is what binds them together.\n"},{"id":"14747","messageId":"20060116215856.6618.qmail@web31805.mail.mud.yahoo.com","threadId":"3071","inReplyTo":"7vmzhx7ref.fsf@assigned-by-dhcp.cox.net","subject":"Re: Question on empty commit","fromName":"Luben Tuikov","fromEmail":"ltuikov@yahoo.com","sentAt":"2006-01-16T21:58:56Z","receivedAt":"2006-01-16T21:58:56Z","isPatch":false,"sender":{"key":"ltuikov@yahoo.com","avatar":null},"body":"--- Junio C Hamano <junkio@cox.net> wrote:\n\n> Luben Tuikov <ltuikov@yahoo.com> writes:\n> \n> > Now the last merge introduced an empty commit, since\n> > tree A and tree B had been in sync (only local and\n> > remote trunk had been out of sync).  While it was expected\n> > that no commit would be introduced since they were in sync.\n> >\n> > Was the empty commit correct behavior?\n> \n> I do not quite follow you, but immediately before the \"empty\n> commit\" (I presume you mean the last \"git merge\" that merges\n> treeA head in treeB), you say \"the treeA and treeB had been in\n> sync\".\n\nMeaning that merging Tree A into Tree B would introduce 0 changes\nto Tree B.\n\n> What do you exactly mean?  The tree object in the head\n> commits in treeA branch and treeB branch were identical?\n\nThey cannot be, since Tree B contains Project B, which is not\npresent in Tree A, but it depends on Project A in Tree A.\n\n> If that is the case, the commit being empty is the correct\n> behaviour, because there is no difference in the set of files\n> introduced by that commit.  And the commit being made is also\n> the correct behaviour, because those two branches have different\n> development history, and the commit is what binds them together.\n\nSo a new commit object, with 0 files changed was the correct behavior\nafter all?\n\nI'd expect that there would be no commit object whatsoever since\nthose trees had been synced before.  I.e. the only thing which changed\nwas the trunk and that trunk was synced to Tree A and Tree B separately.\n\nThanks,\n    Luben\n"},{"id":"14750","messageId":"20060116225749.90052.qmail@web31812.mail.mud.yahoo.com","threadId":"3071","inReplyTo":"20060116215856.6618.qmail@web31805.mail.mud.yahoo.com","subject":"Re: Question on empty commit","fromName":"Luben Tuikov","fromEmail":"ltuikov@yahoo.com","sentAt":"2006-01-16T22:57:49Z","receivedAt":"2006-01-16T22:57:49Z","isPatch":false,"sender":{"key":"ltuikov@yahoo.com","avatar":null},"body":"--- Luben Tuikov <ltuikov@yahoo.com> wrote:\n> --- Junio C Hamano <junkio@cox.net> wrote:\n> \n> > Luben Tuikov <ltuikov@yahoo.com> writes:\n> > \n> > > Now the last merge introduced an empty commit, since\n> > > tree A and tree B had been in sync (only local and\n> > > remote trunk had been out of sync).  While it was expected\n> > > that no commit would be introduced since they were in sync.\n> > >\n> > > Was the empty commit correct behavior?\n> > \n> > I do not quite follow you, but immediately before the \"empty\n> > commit\" (I presume you mean the last \"git merge\" that merges\n> > treeA head in treeB), you say \"the treeA and treeB had been in\n> > sync\".\n> \n> Meaning that merging Tree A into Tree B would introduce 0 changes\n> to Tree B.\n> \n> > What do you exactly mean?  The tree object in the head\n> > commits in treeA branch and treeB branch were identical?\n> \n> They cannot be, since Tree B contains Project B, which is not\n> present in Tree A, but it depends on Project A in Tree A.\n> \n> > If that is the case, the commit being empty is the correct\n> > behaviour, because there is no difference in the set of files\n> > introduced by that commit.  And the commit being made is also\n> > the correct behaviour, because those two branches have different\n> > development history, and the commit is what binds them together.\n> \n> So a new commit object, with 0 files changed was the correct behavior\n> after all?\n> \n> I'd expect that there would be no commit object whatsoever since\n> those trees had been synced before.  I.e. the only thing which changed\n> was the trunk and that trunk was synced to Tree A and Tree B separately.\n> \n> Thanks,\n>     Luben\n\nOk, so what I'm seeing is that git history records what the _user did_\nas opposed to _what happened to the code_.\n\nIs it possible to have an env var to control this \"feature\".  I.e. if\nthe result is 0 lines 0 files changed, then do not update the index and/or\nthe git database.\n\nThanks Junio,\n    Luben\n"},{"id":"14751","messageId":"7vy81fok42.fsf@assigned-by-dhcp.cox.net","threadId":"3071","inReplyTo":"20060116215856.6618.qmail@web31805.mail.mud.yahoo.com","subject":"Re: Question on empty commit","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-16T22:58:53Z","receivedAt":"2006-01-16T22:58:53Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Luben Tuikov <ltuikov@yahoo.com> writes:\n\n>> I do not quite follow you, but immediately before the \"empty\n>> commit\" (I presume you mean the last \"git merge\" that merges\n>> treeA head in treeB), you say \"the treeA and treeB had been in\n>> sync\".\n>\n> Meaning that merging Tree A into Tree B would introduce 0 changes\n> to Tree B.\n\nYou had two separate development tracks treeA and treeB, and the\nentire merge result is taken from treeB because it had all the\nchanges from the common upstream already and there was no\ndevelopment in treeA on its own:\n\n          treeB ---------o--o--o--*--o--o---*--o..?\n                                 /         /     .\n                                /         /     .\n          common upstream ---- / --o--o--o--o  .\n                              /           \\   . \n                             /             \\ .\n          treeA ------o--o--o---------------*\n                                    ^\n                                    |\n                     No commit on this segment.\n\n                o are commits, * are merge commits.\n\nand we are trying to merge the last commit on treeA line into\nthe tip of treeB.  The last merge commit on the treeB line of\ndevelopment would introduce zero change from treeB's point of\nview, because there is nothing new treeB would get by merging\nwith treeA.\n\nBefore the '?' mergepoint, what is known about treeA and treeB\nwas that treeB contained everything up to the third from the\nleft 'o' commit on treeA line.  We now noticed that treeA has\nsome changes since then (i.e. all the good stuff from the common\nupstream), and merge even has noticed that these changes happen\nto be already what treeB already had and you did not have to\nhand resolve (or you might have had to; I dunno).  Making a\ncommit for '?' merge records the fact that these two tips are in\nsync.  IOW, earlier treeB did not know about the merge commit at\nthe tip of treeA; now it does.\n\nAfter this sync, if you try to merge again with treeA, no merge\ncommit would be made, of course.  Now you are truly up-to-date.\n\nWhen git talks about a branch being up-to-date wrt another\nbranch, it is not about \"all of the patches that the other line\nhas have been applied to our tree\" (we are not a patchset based\nsystem like darcs).  It is about commit ancestry, IOW, \"in the\npast we have merged with them, and all the commits that line has\nright now are what we have already examined when we made that\nmerge\" is what we mean by us being up-to-date wrt them.\n\nFast-forward is the other way around but the principle is the\nsame.  We are fast-forward to them not because we have applied\nall the patches they have and we have more.  We are fast-forward\nbecause we have seen all of their commits in the past and\nrecorded in our commit ancestry chain that fact as a merge, and\nin addition we have one or more commits on top of that merge\ncommit.  That is when we are fast-forward wrt to them.\n"},{"id":"14752","messageId":"7v8xtfn408.fsf@assigned-by-dhcp.cox.net","threadId":"3071","inReplyTo":"20060116225749.90052.qmail@web31812.mail.mud.yahoo.com","subject":"Re: Question on empty commit","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-16T23:32:07Z","receivedAt":"2006-01-16T23:32:07Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Luben Tuikov <ltuikov@yahoo.com> writes:\n\n> Ok, so what I'm seeing is that git history records what the _user did_\n> as opposed to _what happened to the code_.\n>\n> Is it possible to have an env var to control this \"feature\".  I.e. if\n> the result is 0 lines 0 files changed, then do not update the index and/or\n> the git database.\n\nGood question.  We could go stronger than that, and say it would\nmake more sense not to make that commit by default, except when\nthe merge was done with \"ours\" strategy (it explicitly asks for\nan empty commit to make it stand out that trees were in sync at\nthat point), or the merge was manually resolved and the result\nhappens to match what treeB already had.\n\nWhy?\n\n          treeB ---------o--o--o--*--o--o---*--o..?\n                                 /         /     .\n                                /         /     .\n          common upstream ---- / --o--o--o--o  .\n                              /           \\   . \n                             /             \\ .\n          treeA ------o--o--o---------------*\n                                    ^\n                                    |\n                     No commit on this segment.\n\n                o are commits, * are merge commits.\n\nAt point '?' we can choose not to make a merge.  You could,\nafter seeing such an empty merge, emulate this behaviour by\ndoing \"git reset --hard HEAD^\" yourself.  Then some time later,\nwhen treeA truly has something new to offer treeB, the next\nmerge attempt will create a true merge commit at '!':\n\n          treeB ---------o--o--o--*--o--o---*--o--?--o--o--!\n                                 /         /     .        /\n                                /         /     .        /\n          common upstream ---- / --o--o--o--o  .        /\n                              /           \\   .        /\n                             /             \\ .        / \n          treeA ------o--o--o---------------*--o--o--o\n\nWhen we have the last two 'o' commits on treeB development\ntrack, creating '?' merge _might_ have some value, because we\ncan clearly see that those two new 'o' commits on treeB are\ncompatible with the '*' merge commit on treeA track.  Without\nthe merge at '?' we would not be able to tell that, so in that\nsense it is a small plus to have '?' merge commit, and it may\neven help bisection bug hunting.  But in practice it may not\nmatter and just clutter your history.\n\nEspecially if we did not have the last two 'o' commits on treeB\nline, making an empty merge commit at '?' would mostly be\npointless.\n\n\n          treeB ---------o--o--o--*--o--o---*--o--?--------!\n                                 /         /     .        /\n                                /         /     .        /\n          common upstream ---- / --o--o--o--o  .        /\n                              /           \\   .        /\n                             /             \\ .        / \n          treeA ------o--o--o---------------*--o--o--o\n\nBut unfortunately we cannot tell if we are going to build on top\nof '?' before we merge with treeA again next time at '!', when\nwe are at point '?', so we could have an option or environment\nvariable to control this \"feature\", but unless you can predict\nthe future at point '?', deciding whether to use that option\nwould be rather difficult.\n"}]}