{"thread":{"id":"4000","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","startedAt":"2006-04-29T16:51:51Z","lastAt":"2006-05-02T07:08:49Z","messageCount":16,"participants":["linux@horizon.com","Linus Torvalds","Jakub Narebski","Junio C Hamano","Sam Vilain","Martin Langhoff"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"19256","messageId":"20060429165151.2570.qmail@science.horizon.com","threadId":"4000","inReplyTo":null,"subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"","fromEmail":"linux@horizon.com","sentAt":"2006-04-29T16:51:51Z","receivedAt":"2006-04-29T16:51:51Z","isPatch":true,"sender":{"key":"linux@horizon.com","avatar":null},"body":"Boy, this is an interesting discussion!\nOn the one hand, it seems \"obvious\" to me that extra links might be\nuseful.  But Linus's minimalist points have a lot of merit.\n\nI have to agree, it's important to think of a single practical use before\nadding the feature.  So let's do a little brainstorming...\n\n\nFor just referring to another commit, there's no problem putting\nit in the body.  A sensible porcelain GUI will, when it seems something\nthat looks like an object identifier in a comment, and that object\nidentifier exists, make it a clickable link.  So a comment like:\n\n\"This fixes the same problem as <commit>, but is a cleaner\n(albeit more invasive) fix.\"\n\nWould do the right thing: the user reading it could easily jump\nto the other comment.  A \"header\" link as opposed to a \"comment\"\nlink just has the property of being unambiguous.  No heuristic\nwill guess that a link should exist when there isn't.\n\nSo, what is that property useful for?\n\n\nNow, one thing that porcelains provide, in addition to \"parent\" links,\nis \"child\" links.  Useful.  But it could be done with commit comment\nlinks as well, and it's not clear that having the link in the commit\nheader as opposed to the comment would help much.  You still have to\nfind and uncompress part of each commit to generate the history\ntree.  Does uncompressing the rest of it and running a heuristic\nover the text for really cost that much?\n\nI'm not convinced it's needed for that feature.  (I'd sooner argue for\nnever compressing commit objects in packs on the grounds that the\nrepeated uncompression while browsing is worth saving more than the\nrelatively minor disk space.)\n\n\nSo to be valuable, and inadvisable to express with a specially\nformatted comment, it has to be something that would be Very Bad\nto get wrong.  What qualifies?\n\nMaybe some merge algorithm information?  If the merge could be told that\nthis change \"is the same\" as that change, so it can be skipped when\ncherry-picking that branch, and the information was wrong, that could\ncause lots of problems.\n\nBut given that git-cherry already uses (imperfect) heuristics to\ndetect already-merged patches, and they seem to work well enough, is\nthat a strong enough argument?  Is there some other merge application\nwhere it would help?\n\n\nNow, the \"this other object should exist in the repository, and it's an\nerror if you can't fetch it\" link obviously needs to be unambiguously\ndistinguished from, say, a reference to the (Linux kernel) dodecapus merge\nin a git tree checkin comment.  But, as Linus says, what reason is there\nfor including it?  What do you need the commit in the repository for?\n\nWell, the only reason that you need ANY commit in the repository is\nbecause it's part of history, and comparing it with other versions is\nmeaningful.  So what trees, not already in the ancestry graph of a\ngiven commit, are useful to compare to?  In particular, useful for some\nautomated process; manual comparisons can always be done manually.\n\n\nNothing's jumping out at me.  Any suggestions?\n"},{"id":"19259","messageId":"Pine.LNX.4.64.0604291006270.3701@g5.osdl.org","threadId":"4000","inReplyTo":"20060429165151.2570.qmail@science.horizon.com","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-04-29T17:35:35Z","receivedAt":"2006-04-29T17:35:35Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 29 Apr 2006, linux@horizon.com wrote:\n> \n> Well, the only reason that you need ANY commit in the repository is\n> because it's part of history, and comparing it with other versions is\n> meaningful.  So what trees, not already in the ancestry graph of a\n> given commit, are useful to compare to?  In particular, useful for some\n> automated process; manual comparisons can always be done manually.\n> \n> Nothing's jumping out at me.  Any suggestions?\n\nThe only thing that I've ever wondered about is the \"base commit of a \nmerge\".\n\nNow, the thing is, we can always compute it. That's true _iff_ we've \nmerged using the standard merge mechanism, but it wasn't always true \nhistorically (eg the original merges were computed with the original \n\"git-merge-base\" algorithm, which just picked the _first_ merge base it \nwould find, while these days we use multiple ones for criss-cross merges).\n\nSo I would not totally object if a merge algorithm added a\n\n\tmerge-base <sha1>\n\nnotation. But while it _could_ be just a \"note merge-base <sha1>\", it \nshould _not_ be a \"link <sha1> merge-base\".\n\nLet me explain why I think there are differences between those three \noptions, and why I actually think that two of them are \"valid\" ideas, \nwhile the third one is not.\n\n - Case 1: the\n\n\tmerge-base <sha1>\n\n   is a \"valid\" idea (where there might of course be more than one <sha1>, \n   and possibly more than one \"merge-base\" line: you'd have to have some \n   rule for what happens for a recursive merge), although it has the \n   generally big down-side of being redundant information in all current \n   setups.\n\n   It's redundant, but at the same time it's information that in _theory_ \n   might not be redundant, because I can see a situation where a merge was \n   forced by manually specifying a merge base (eg a special merge like the \n   original \"gitk\" merge, merging two initially unrelated projects \n   together).\n\n   In theory. So it could be real information for a merge commit. And we'd \n   enforce some kind of real semantics for it - and it would have a really \n   solid technical meaning: assuming we define the multi-merge-base \n   semantics properly it would NEVER have any question about \"what are \n   best practices?\" or \"what does this mean?\".\n\n   So this \"case 1\" actually has technical consequences, but you can, for \n   example, actually _check_ them. You can make fsck literally complain if \n   the merge base doesn't make sense. There's a clear \"technical \n   violation\", which might not be entirely trivial to figure out, but \n   thanks to it having a good meaning and a strict definition, it's \n   _there_.\n\nNow, in all honesty, I don't think \"case 1\" is a _good_ thing to do. I'm \njust saying that I wouldn't be as upset about it as I've been over this \n\"link\" discussion. The reason I think \"case 1\" sucks is simply that I \nthink you can in _practice_ get all the benefits much better with \"case \n2\", even if that one doesn't imply any actual git semantics:\n\n - Case 2: the\n\n\tnote merge-base <sha1>\n\n   thing is _also_ a perfectly valid idea, because now it's also very \n   well-defined: the \"note\" part tells you that git doesn't actually \n   impose any semantics what-so-ever on it, so it's really just a comment, \n   and as in case 1 above, once you see it as a comment, the _meaning_ of \n   it is immediately clear. It's literally just a note from the merge \n   algorithm saying \"I used this as a merge base\".\n\n   The \"note\" syntax actually has a huge advantage. When you see it as a \n   comment from the merge algorithm, you immediately think it might also \n   be a good idea to add a few other notes. So a merge commit might \n   actually have\n\n\tnote merge-algorithm recursive\n\tnote merge-conflicts none\n\tnote merge-base <sha1>\n\n   all make total sense. It's telling you what the algorithm used was, and \n   that it didn't neen any manual fixups. It's also telling you that none \n   of this has _any_ impact what-so-ever from a \"git semantics\" angle, and \n   that this is nothing but a note for anybody who starts digging into it.\n\nSo now I've shown _two_ examples of some kind of header that I think \nactually makes sense, and that I would not argue against on those grounds. \nEspecially the \"note\" thing I think is fine. So why, oh why, do I hate the \n\"link\" thing so much?\n\n - Case 3: the\n\n\tlink <sha1> merge-base\n\n   thing is a horrible and nasty thing that we should never ever support.\n\n   Why? Because it's literally designed to both have some semantic meaning \n   (\"git will fetch the <sha1> and use it for connectivity analysis\") \n   _and_ at the same time the whole syntax it's designed to _not_ have any \n   real meaning (\"you can have any kind of link, and I don't know what \n   it actually means from a conceptual standpoint\").\n\n   So it has a meaning from an _implementation_ angle, but at the same \n   time it does not have a \"higher cause\". That is EVIL. When they say \n   \"The road to hell is paved with good intentions\", the implication there \n   is not that good intentions is bad per se, but that you should \n   understand that there are \"Unintended Consequences\".\n\n   And if you cannot limit the thing to a very _specific_ higher-level \n   meaning, you by definition will have those \"unintended consequences\".\n\nIn short, the difference between three headers that on the face of it say \nexactly the same thing: \"merge-base <sha1>\", \"note merge-base <sha1>\", and \n\"link merge-base <sha1>\" is not that they have different syntax (hey, even \nthe syntax itself is almost identical), but exactly the fact that they \nhave different implications and _meaning_.\n\nTwo of the three have no unintended consequences. One (\"note\") has no \ntechnical \"consequences\" at _all_, by definition. The other \"merge-base\" \nhas no technical \"unintended\" at all, because it's throught through, and \nhas been fully defined.\n\nThe third? \"unintended consequences\". It doesn't have a clear definition \n(\"It's cool. You can use it for any link you want\"). So pretty much BY \nDESIGN, it's set up so that you don't know what the consequences of it \nwill be for a project.\n\nAnd that's why \"case 3\" it's bad. Even though it looks very much like the \ntwo other ones.\n\n\t\t\tLinus\n"},{"id":"19260","messageId":"e309vq$m2r$1@sea.gmane.org","threadId":"4000","inReplyTo":"Pine.LNX.4.64.0604291006270.3701@g5.osdl.org","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-04-29T18:07:36Z","receivedAt":"2006-04-29T18:07:36Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Linus Torvalds wrote:\n\n>  - Case 1: the\n> \n>         merge-base <sha1>\n[...]\n>  - Case 2: the\n> \n>         note merge-base <sha1>\n[...]\n>  - Case 3: the\n> \n>         link <sha1> merge-base\n[...]\n\n> In short, the difference between three headers that on the face of it say\n> exactly the same thing: \"merge-base <sha1>\", \"note merge-base <sha1>\", and\n> \"link merge-base <sha1>\" is not that they have different syntax (hey, even\n> the syntax itself is almost identical), but exactly the fact that they\n> have different implications and _meaning_.\n> \n> Two of the three have no unintended consequences. One (\"note\") has no\n> technical \"consequences\" at _all_, by definition. The other \"merge-base\"\n> has no technical \"unintended\" at all, because it's throught through, and\n> has been fully defined.\n> \n> The third? \"unintended consequences\". It doesn't have a clear definition\n> (\"It's cool. You can use it for any link you want\"). So pretty much BY\n> DESIGN, it's set up so that you don't know what the consequences of it\n> will be for a project.\n> \n> And that's why \"case 3\" it's bad. Even though it looks very much like the\n> two other ones.\n\nIF (and that is big if) git commit header will be extended to have some\nextra \"link\" (enforcing connectivity) headers, like proposed \"bind\" for\nsubprojects, \"prev\" for pu-like union branches, \"merge-base\" for merges,\nthere would be repeated work on enforcing connectivity. Hence generic\n\"link\" header (formerly \"related\") proposal. Having fsck report broken\nlinks (or not), having purge removing commits (objects) reachable only via\n\"link\" headers, having pull download commits via \"link\" headers... have I\nforgot anything? It _seems_ that this part is common, and does not depend\non semantics.\n\nBut with \"links\" (connectivity headers) there always would be some other\nconsequences. For example info/grafts deals for now only with commit\nparents, and extending the format could be difficult.\n\nAnd of course if we want connectivity, this is for some reason, so the\n\"link\" has some other consequences, for example \"prev\" and \"merge-base\" for\nmerging, \"bind\" for checkout, merge (but differently), etc.\n\n\nI think that if it is 'helper' information (i.e. information which is\nhelpful, but we can do without it) and of no real importance to user then\nuse \"note\". If it is of importance to user (for example \"cherrypick\" or\n\"reverted\") and of use to git, then repeat such info in \"note\" header to\navoid relying on parsing free-form part aka. commit comment. If\nconnectivity is needed... hmmm...\n\n-- \nJakub Narebski\nWarsaw, Poland\n"},{"id":"19261","messageId":"e30b48$ovk$1@sea.gmane.org","threadId":"4000","inReplyTo":"20060429165151.2570.qmail@science.horizon.com","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-04-29T18:27:02Z","receivedAt":"2006-04-29T18:27:02Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Sat, 29 Apr 2006, linux@horizon.com wrote:\n> \n> Well, the only reason that you need ANY commit in the repository is\n> because it's part of history, and comparing it with other versions is\n> meaningful.  So what trees, not already in the ancestry graph of a\n> given commit, are useful to compare to?  In particular, useful for some\n> automated process; manual comparisons can always be done manually.\n> \n> Nothing's jumping out at me.  Any suggestions?\n\nSee below.\n\nNot necessary all those require connectivity.\nMost of them are not my ideas.\n\n * \"prior\" - heads that represent topic branch merges\n\n    This is the \"pu\" branch case, where the head is a merge of several\n    topic branches that is continually moved forward.\n\n    topic branches     head\n      ,___.   ,___.\n     | TA1 | | TB1 |\n      `---'   `---'    ,__.\n         ^\\_____^\\____| H1 |\n                       `--'\n\n    + some topic branch changes and a republish:\n\n      ,___.   ,___.\n     | TA1 | | TB1 |\n      `---'   `---'^   ,__.\n        |^\\_____^\\____| H1 |\n        |       |      `--'\n      ,_|_.   ,_|_.      P\n     | TA2 | | TB2 |     |\n      `---'   `---'^     |\n        ^       ^        |\n      ,_|_.     |        |\n     | TA3 |    |        |\n      `---'     |      ,__.\n         ^\\______\\____| H2 |\n                       `--'\n\n    key:  ^ = parent   P = prior\n\n\n * \"bind\" - for subprojects\n\n   bind links from master project commit to externally managed embedded\n   third-party project, for example Linux kernel for some mainly userspace\n   project, or library or engine for some application. Additionally it\n   provides root dir where to attach subproject.\n\n \n * \"original\" for rebase\n\n   before rebase:\n\n             A---B---C topic\n            /\n           /\n          /\n     D---E---F---G master\n\n   after rebase\n\n              ------A---B---C\n             /      ^   ^   ^ \n            /       :   :   :\n           /        A'--B'--C' topic\n          /       /\n     D---E---F---G master\n\n\n   where ':' denotes \"original\" link. Note that old branch is not pointed by\n   any head, and would be pruned without connectivity\n\n\n * \"original\" or \"cherrypick\" for cherry-picking\n\n            A--------B---C bugfix\n           /         ^\n          /          :\n     D---E---F---G---B'---H main\n\n\n * \"revert\" for reverting commits\n\n-- \nJakub Narebski\n"},{"id":"19263","messageId":"7vlkto6uym.fsf@assigned-by-dhcp.cox.net","threadId":"4000","inReplyTo":"e309vq$m2r$1@sea.gmane.org","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-04-29T19:30:09Z","receivedAt":"2006-04-29T19:30:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> IF (and that is big if) git commit header will be extended to have some\n> extra \"link\" (enforcing connectivity) headers, like proposed \"bind\" for\n> subprojects, \"prev\" for pu-like union branches, \"merge-base\" for merges,\n> there would be repeated work on enforcing connectivity. Hence generic\n> \"link\" header (formerly \"related\") proposal.\n\nThe \"link <sha1> <type> <meta>\" header extension was done\nprimarily for that reason this way.  I carried it in my \"pu\"\nbranch for a few days but Linus convinced me privately that it\nwas a bad idea, so it is not merged in \"pu\" anymore.  Just to\nmake it easy for people to view what we are discussing, I pushed\nthe branch head to jc/bind-2 topic branch, but the code will\n_not_ be merged.\n\nThe code in commit.c to recognize and link the releated objects\npointed by the \"link\" header to the commit looked like below\n(see 11bbee26 commit on that branch):\n\n+       optr = &item->links;\n+       while (!memcmp(bufptr, \"link \", 5)) {\n+               struct object *object;\n+\n+               if (!get_sha1_hex(bufptr + 5, parent) &&\n+                   bufptr[45] == ' ' &&\n+                   (object = lookup_unknown_object(parent)) != NULL) {\n+                       struct object_list *l = xmalloc(sizeof(*l));\n+                       l->item = object;\n+                       l->next = *optr;\n+                       l->name = NULL;\n+                       *optr = l;\n+                       optr = &l->next;\n+                       n_refs++;\n+                       bufptr += 45;\n+               }\n+               else\n+                       return error(\"bad link in commit %s\",\n+                                    sha1_to_hex(item->object.sha1));\n+               while (*bufptr++ != '\\n')\n+                       ; /* skip over subdirectory name */\n+       }\n\nBut if your are going to introduce \"merge-base\" and similar\nheaders that have impact to connectivity traversal code, you can\neasily change the !memcmp(buptr, \"link \", 5) with a sequence of\n\"memcmp(foo) || memcmp(bar) || ...\", and use the \"l->name\" field\nto point at the header itself, so that the user of the resulting\ncommit object can easily tell what kind of link-like header it\nis, and enforce further semantics that are specific to each kind\nof such header on it.  The revision traversal change that was\ndone in a later commit (7091fd commit) does not have to change.\n\nThe code sharing aspect you brought up is a very important\nissue.  This is revision traversal, which is really the central\npart of git and needs deep thought to touch without breaking, so\nwe would like to avoid risking breaking it by repeatedly\ntouching it.  But that can be done without making the recorded\nheader something like \"link <sha1> <type> <metainfo>\" which is\ntoo generic.\n"},{"id":"19264","messageId":"7viros1585.fsf@assigned-by-dhcp.cox.net","threadId":"4000","inReplyTo":"e30b48$ovk$1@sea.gmane.org","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-04-29T20:44:58Z","receivedAt":"2006-04-29T20:44:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n>  * \"prior\" - heads that represent topic branch merges\n\nThis is not any different from usual \"parent\" at all (but you\nhave to think about it a bit to realize it).\n\nBefore talking about making a new commit object that links to\nother related commits, let's first talk about what it means to\nupdate the branch head ($GIT_DIR/refs/heads/<branch>) from\ncommit A to commit B.  Understanding what it means is more\nfundamental.\n\nA git \"branch\" points at the tip of one possible history of a\ndevelopment.  As the often-used word \"topic branch\" tells you, a\n\"branch\", i.e. that history, has a specific purpose.  The\npurpose of my \"master\" branch is to give reasonably stable new\nfeature set and bugfixes, \"next\" to give testable ones, and \"pu\"\nto collect remaining bits that are worthy of discussion.\n\nWhen your branch head points at commit A and you update the head\nto point at a different commit B, you are making this statement:\n\n\tThe commit B suits the purpose of the branch better\n\tthan the commit A.\n\nNotice there may or may not be ancestry relation between these\ntwo commits at this point of the discussion.  B may be a direct\nchild of commit A, a merge that has A as its first parent, a\nmerge that has A as its one of its parent (but not necessarily\nthe first), or a Nth-generation descendant if the update was a\nfast forward merge from another branch.  It might even be an\nancestor if the update rewinds the history.\n\nAmong the above cases (and there may be others), in only two\ncases you actually create a new commit to record that\nstatement [*1*].\n\nThe simplest case is when commit B is a direct, single-parent\nchild of commit A, and that statement is in your commit log\nmessage.  \"I started out from the commit A, and the result is\nthis tree.  The result suits what I am doing better than the\nprevious commit and I made the world a better place.\" -- the \"I\nstarted out from the commit A\" part is on the parent header and\nthe rest is in the free-text.\n\nWhen you are creating a merge of N parents, the principle is the\nsame.  Although in pure core-git terms all parents are equal, in\npractice, the first parent has somewhat special meaning to you.\nWhen the parents of commit B are A and X, you started out from\nthe commit A.  Then what are other parents?  You can read such a\ncommit this way:\n\n\tI started out from commit A and came up with this tree,\n\twhich suits my purpose better.  While doing so, I have\n\talso considered what X has; and this result, commit B,\n\tsuits my purpose better than X, too.\n\nThis is why a later merge with another branch that further\nbuilds on top of X works so well.\n\n    ----A----B\n            /\n       ----X----Y\n\nIf somebody built Y on X independently from us, when we merge\nwith Y, we say the merge base is X because B says \"I've already\nconsidered what X has\" to do a 3-way merge.  While that is what\nhappens at the mechanical level, what is happening at the\nphilosophical level is we are taking \"I consider that B is\nbetter than X\", part of the message seriously, which means \"I\nwant to keep changes I made between X B\".  Also the other person\nwho made Y made a similar statement that she considers Y is\nbetter than X, and we try to preserve the changes between X and\nY in the automated part of the merge while preparing the tree to\ncommit the merge between B and Y.\n\nOnce you start reading the commit parent to mean \" considering\nwhat all of these commits have, what this new commit has suits\nmy purpose better\", it becomes clear that the \"previous\" pointer\nfor a branch like my \"pu\" is just another \"parent\".\n\nI rebuild \"pu\" from the tip of then-current \"next\", and merge\nother topics in, and discard the previous \"pu\".  So it results\nin this kind of graph:\n\n                         o---o---o---o---o (updated \"pu\")\n                        /   /   /   /  \n        ---o---o---o---o\n            \\               \\   \\   \\   \\\n             o---------------o---o---o---o (previous \"pu\")\n\nBut theoretically, I could include the previous \"pu\" tip as one\nof the parents of the updated \"pu\" branch.\n\nAt the mechanical level, I start from then-current \"next\" and\nmerge each topic branch one-by-one on top of it.  But at the\nphilosophical level, what I am doing is to publish material that\nshows a set of proposed changes that are more appropriate for\nreview by the curious than the previous round of \"pu\" head used\nto have.  So the previous \"pu\" _is_ in the consideration while I\npublish the updated \"pu\", although it is _not_ recorded anywhere.\n\nAfter I come up with a fully merged tree, I could make a fake\nOctopus that has the previous \"pu\" as its first parent and each\nof the topic branch heads merged as second and subsequent\nparents, with the resulting tree.  That would be more \"honest\"\nat the philosophical level.\n\nI am not going to actually suggest anybody doing this as a good\npractice, but we can make such a commit with the current tool\nlike this:\n\n        git checkout pu\n\tgit tag -f prev-pu\t\t;# remember where we were\n\tgit reset --hard next\t\t;# start at next\n        git pull . topic-1\t\t;# merge all remaining topics\n        git pull . topic-2\t\t;# ...\n        git pull . topic-3\n        ...\n        git tag -f next-pu\t\t;# this tree is what we want\n        git reset --hard prev-pu\t;# start from previous\n        git pull --no-commit -s ours . next topic-1 topic-2 ...\n\tgit read-tree -m -u next-pu\t;# record a merge whose first\n\tgit commit\t\t\t;# parent is previous pu and\n\t\t\t\t\t;# has all the topics merged.\n        \n\n[Footnote]\n\n*1* IOW, we _are_ losing some information by not recording the\nfact that fast-forward was done while doing so.  \n\nThat record should _not_ be in the commit chain.  At the\nmechanical level, recording that in the commit chain means two\ncriss-crossing branches never converge at the commit chain\nlevel, which is already bad.  At the philosophical level, the\ncommit chain is a mesh of many possible \"global\" histories, and\nthe record that somebody (a particular branch in a particular\nrepository) was at what point in the mesh at given time does not\nbelong there.\n\nBut from the repository-owner's point of view, that _might_ be a\nuseful information to keep.  I am just saying this preemptively\nso that if somebody wants to record it, that should not be\nrecorded in the commit object.\n"},{"id":"19265","messageId":"e30k0n$ij5$1@sea.gmane.org","threadId":"4000","inReplyTo":"7viros1585.fsf@assigned-by-dhcp.cox.net","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-04-29T20:58:45Z","receivedAt":"2006-04-29T20:58:45Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano wrote:\n\n> Jakub Narebski <jnareb@gmail.com> writes:\n> \n>>  * \"prior\" - heads that represent topic branch merges\n> \n> This is not any different from usual \"parent\" at all (but you\n> have to think about it a bit to realize it).\n[cut]\nThanks for an explanation.\n\nI would say that \"prior\" is not THAT different from usual \"parent\",\nrather than it is not ANY different.\n\nMy doubts about recording previous head of a \"union\" (pu-like) branch \nis that for merge (e.g. 'pu' to 'next', cherrypick to/from 'pu', 'pu'\nrebase) is that for merge algorithm all parents are equivalent, with\neventual exception of first which can be treated special ('ours').\n\n-- \nJakub Narebski\nWarsaw, Poland\n"},{"id":"19289","messageId":"e32kkf$amc$1@sea.gmane.org","threadId":"4000","inReplyTo":"e30k0n$ij5$1@sea.gmane.org","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-04-30T15:21:37Z","receivedAt":"2006-04-30T15:21:37Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Jakub Narebski wrote:\n\n> Junio C Hamano wrote:\n> \n>> Jakub Narebski <jnareb@gmail.com> writes:\n>> \n>>>  * \"prior\" - heads that represent topic branch merges\n>> \n>> This is not any different from usual \"parent\" at all (but you\n>> have to think about it a bit to realize it).\n> [cut]\n> Thanks for an explanation.\n> \n> I would say that \"prior\" is not THAT different from usual \"parent\",\n> rather than it is not ANY different.\n> \n> My doubts about recording previous head of a \"union\" (pu-like) branch\n> is that for merge (e.g. 'pu' to 'next', cherrypick to/from 'pu', 'pu'\n> rebase) is that for merge algorithm all parents are equivalent, with\n> eventual exception of first which can be treated special ('ours').\n\nAdditionally with \"prior\" (or at least some convention on which of parents\nis to prior head of \"union (pu-like) branch) I think we could fast-forward\nsuch branches...\n\n-- \nJakub Narebski\nWarsaw, Poland\n"},{"id":"19311","messageId":"7vfyjuwt0v.fsf@assigned-by-dhcp.cox.net","threadId":"4000","inReplyTo":"e32kkf$amc$1@sea.gmane.org","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-04-30T23:19:44Z","receivedAt":"2006-04-30T23:19:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n>>> This is not any different from usual \"parent\" at all (but you\n>>> have to think about it a bit to realize it).\n>> \n>> I would say that \"prior\" is not THAT different from usual \"parent\",\n>> rather than it is not ANY different.\n>> \n>> My doubts about recording previous head of a \"union\" (pu-like) branch\n>> is that for merge (e.g. 'pu' to 'next', cherrypick to/from 'pu', 'pu'\n>> rebase) is that for merge algorithm all parents are equivalent, with\n>> eventual exception of first which can be treated special ('ours').\n>\n> Additionally with \"prior\" (or at least some convention on which of parents\n> is to prior head of \"union (pu-like) branch) I think we could fast-forward\n> such branches...\n\nThis is why I said you have to think about it a bit to realize\nthat the \"prior\" is not _ANY_ different from the ordinary parent\nfor something like \"pu\".\n\nWe can fast-forward if (1) you pulled from \"pu\" the last time,\nand (2) you haven't added anything on top of it on your own, and\n(3) you pull from \"pu\" again, if the previous \"pu\" (i.e. your\n\"pu\") is a parent of the updated \"pu\".  We do not need \"prior\"\nfor that.  The old \"pu\" being _one_ _of_ the parents, not even\nnecessarily be the first one, would do just fine.\n\nIf you have built on top of the last \"pu\", obviously we do not\nwant to fast-forward with or without \"prior\".\n\nYour doubts about the merge is also unfounded.  The current \"pu\"\nhead is (against my own recommendation not to do so) a hydra\ncap.  It is a direct child of the previous \"pu\" that merges all\nthe leftover bits along with what was in 'next' when the commit\nwas made, so you could do something like this to experiment:\n\n\tgit branch test-1 pu^1\n\techo >>Makefile '# End of Makefile'\n        git commit -m 'build on top of previous \"pu\"' Makefile\n        git pull . pu ;# Merge whatever happened in \"pu\"\n        \n"},{"id":"19313","messageId":"445550C4.5020800@vilain.net","threadId":"4000","inReplyTo":"7viros1585.fsf@assigned-by-dhcp.cox.net","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2006-05-01T00:05:24Z","receivedAt":"2006-05-01T00:05:24Z","isPatch":true,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Junio C Hamano wrote:\n\n>> * \"prior\" - heads that represent topic branch merges\n>>    \n>>\n>\n>This is not any different from usual \"parent\" at all (but you\n>have to think about it a bit to realize it).\n> [...]\n>Once you start reading the commit parent to mean \" considering\n>what all of these commits have, what this new commit has suits\n>my purpose better\", it becomes clear that the \"previous\" pointer\n>for a branch like my \"pu\" is just another \"parent\".\n>  \n>\n\nHow can you look back at the merge history and determine which of these\nscenarios is the case?\n\nIt still looks like to me that you are recording two distinct types of\nparent using the same type of link.  You're now just expanding the\ndefinition of parent so they look to be the same.\n\nActually it might be alright if you have an extra merge commit object. \nie, make a complete merge of the new tips, then make a second merge that\nmerges the two heads.  It's still a little bit of a research topic to\nlook at that mess and figure out which type of relationship each parent\nactually is, but if you really want to decide that is that and done is\ndone then I guess we'll all just have to live with it or fork.\n\nSam.\n"},{"id":"19314","messageId":"7v8xpmva9x.fsf@assigned-by-dhcp.cox.net","threadId":"4000","inReplyTo":"7vfyjuwt0v.fsf@assigned-by-dhcp.cox.net","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-01T00:50:02Z","receivedAt":"2006-05-01T00:50:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> We can fast-forward if (1) you pulled from \"pu\" the last time,\n> and (2) you haven't added anything on top of it on your own, and\n> (3) you pull from \"pu\" again, if the previous \"pu\" (i.e. your\n> \"pu\") is a parent of the updated \"pu\".  We do not need \"prior\"\n> for that.  The old \"pu\" being _one_ _of_ the parents, not even\n> necessarily be the first one, would do just fine.\n\nThis part may want a bit more elaboration.  \n\nOften, we see in the Linus kernel tree a fast forward of his tip\nfrom a recent commit Linus made to bunch of networking commits\nmade by David S Miller.  For example, Linus fast forwarded to\n18118c from David's tree before making this commit:\n\n    commit 454ac778459bc70f0a9818a6a8fd974ced11de66\n    Merge: 18118cd... 301dc3e...\n    Author:     Linus Torvalds <torvalds@g5.osdl.org>\n    AuthorDate: Mon Apr 24 20:08:08 2006 -0700\n    Commit:     Linus Torvalds <torvalds@g5.osdl.org>\n    CommitDate: Mon Apr 24 20:08:08 2006 -0700\n\nThe first parent of this commit is one not made by Linus; that\nis how we can tell he fast forwarded.  We cannot easily tell\nwhere the tip of Linus tree was before he made this fast forward\n(it is not recorded anywhere), but if we look at 18118c commit:\n\n    commit 18118cdbfd1f855e09ee511d764d6c9df3d4f952\n    Author:     Patrick McHardy <kaber@trash.net>\n    AuthorDate: Mon Apr 24 17:18:59 2006 -0700\n    Commit:     David S. Miller <davem@sunset.davemloft.net>\n    CommitDate: Mon Apr 24 17:27:34 2006 -0700\n\n        [NETFILTER]: ipt action: use xt_check_target for basic verification\n\nwe could sort-of make a guess, by looking at merge-base of\n18118c and 301dc3.  By looking at\n\n\tgitk 6b426e..18118c 454ac7\n\nwe can tell that David \"forked\" from Linus at 6b426e commit.\n\nWhat does it mean for Linus to fast-forward to the tip of David?\nEarlier I said that each branch has a purpose, and replacing the\ncurrent tip commit of the branch with another commit is a\nstatement by the repository owner that the new commit suits the\npurpose of the branch better.\n\nTo David, the commits he has in the chain between 6b426e to\n18118c obviously suited the purpose of his tree better, and that\nwas why these commits were made.  And the fact Linus fast\nforwarded to the tip of David is an implicit statement by Linus\nthat that results suits the purpose of Linus tree better as well\ncompared to his old tip, presumably 6b426e.\n\nEarlier I suggested (or at least may have sounded as if I was\nsuggesting) that not recording that statement in fast-forward\nsituation was a bad thing, but that is not necessarily so.\nHaving 18118c commit as part of the history that leads to the\ntip is enough as such a statement by Linus.\n\nNow, David's tree has a tendency to be extra clean (no merges\nbut straight commits on top of then-current tip of Linus), but\nif he had his own merge from Linus's tree, such a commit would\nhave had a commit from Linus tree as its second parent.  If\nLinus tip remained at that \"second parent\" commit until David is\ndone and asked Linus to pull, it would result in a fast forward\nvia non-first-parent ancestry.  But even if that happened, the\nabove discussion still applies.\n"},{"id":"19315","messageId":"4455638A.3070802@vilain.net","threadId":"4000","inReplyTo":"7v8xpmva9x.fsf@assigned-by-dhcp.cox.net","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2006-05-01T01:25:30Z","receivedAt":"2006-05-01T01:25:30Z","isPatch":true,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Junio C Hamano wrote:\n\n>>We can fast-forward if (1) you pulled from \"pu\" the last time,\n>>and (2) you haven't added anything on top of it on your own, and\n>>(3) you pull from \"pu\" again, if the previous \"pu\" (i.e. your\n>>\"pu\") is a parent of the updated \"pu\".  We do not need \"prior\"\n>>for that.  The old \"pu\" being _one_ _of_ the parents, not even\n>>necessarily be the first one, would do just fine.\n>>    \n>>\n>\n>This part may want a bit more elaboration.  \n>\n>Often, we see in the Linus kernel tree a fast forward of his tip\n>from a recent commit Linus made to bunch of networking commits\n>made by David S Miller.  For example, Linus fast forwarded to\n>18118c from David's tree before making this commit:\n> [...]\n>To David, the commits he has in the chain between 6b426e to\n>18118c obviously suited the purpose of his tree better, and that\n>was why these commits were made.  And the fact Linus fast\n>forwarded to the tip of David is an implicit statement by Linus\n>that that results suits the purpose of Linus tree better as well\n>compared to his old tip, presumably 6b426e.\n>  \n>\n\nAha, now I see reason in the madness. So, the \"prior\" head is not stored\nin the trees, and tracking the progress of actual head transitions is\nloosely defined / a research topic. But demonstrably derivable. That\nworks for me.\n\nSam.\n"},{"id":"19317","messageId":"e343l1$2pj$1@sea.gmane.org","threadId":"4000","inReplyTo":"4455638A.3070802@vilain.net","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-05-01T04:44:06Z","receivedAt":"2006-05-01T04:44:06Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Take a look at complexity of that explanation. And the need for additional\ncommit. That balanced against all the headaches of having connectivity\nheader other than \"parent\".\n\nPerhaps it would be better (and easier) just to say\n\n   note prior parent^1\n\nor\n\n   note prior <sha1>\n\nrepeating <sha1> found in parent.\n\n\nJust a thought.\n\n-- \nJakub Narebski\nWarsaw, Poland\n"},{"id":"19320","messageId":"7vlktms02x.fsf@assigned-by-dhcp.cox.net","threadId":"4000","inReplyTo":"4455638A.3070802@vilain.net","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-01T06:58:30Z","receivedAt":"2006-05-01T06:58:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sam Vilain <sam@vilain.net> writes:\n\n> Junio C Hamano wrote:\n>\n>>To David, the commits he has in the chain between 6b426e to\n>>18118c obviously suited the purpose of his tree better, and that\n>>was why these commits were made.  And the fact Linus fast\n>>forwarded to the tip of David is an implicit statement by Linus\n>>that that results suits the purpose of Linus tree better as well\n>>compared to his old tip, presumably 6b426e.\n>\n> Aha, now I see reason in the madness. So, the \"prior\" head is not stored\n> in the trees, and tracking the progress of actual head transitions is\n> loosely defined / a research topic. But demonstrably derivable. That\n> works for me.\n\nI do not think there is any madness involved here, but I should\npoint out that the above example happens to work only because\nLinus and David are two different people.  If Linus did the\nDavid's work in a separate repository, or even in the same\nrepository but on a separate branch, people following the Linus\ntip might still want to know about the fast-forward, but that is\nsomething you cannot truly tell by the digging like what I did\nin the previous message.\n\nThat is why I earlier said this:\n\n    *1* IOW, we _are_ losing some information by not recording the\n    fact that fast-forward was done while doing so.  \n\n    That record should _not_ be in the commit chain.  At the\n    mechanical level, recording that in the commit chain means two\n    criss-crossing branches never converge at the commit chain\n    level, which is already bad.  At the philosophical level, the\n    commit chain is a mesh of many possible \"global\" histories, and\n    the record that somebody (a particular branch in a particular\n    repository) was at what point in the mesh at given time does not\n    belong there.\n\n    But from the repository-owner's point of view, that _might_ be a\n    useful information to keep.  I am just saying this preemptively\n    so that if somebody wants to record it, that should not be\n    recorded in the commit object.\n\nI do not think the commit object is the place to record it, even\nwith a purely-comment field like \"note prior\".  The commit\nancestry DAG is global in nature, and the information under\ndiscussion, \"before pointing at this commit, the branch that\nmade this commit happened to point at this other commit\", is\nnot.  That information describes only one-branch's view of the\nworld, and would not work in the fast-forward case because no\nnew commit is created.  An important property of a fast-forward\nis that we do not create an extra commit object that makes it\nimpossible for two criss-crossing branches to ever converge.\n\nOn the other hand, a \"note\" field that records on which branch\nof which repository each commit was made (you need to give each\nrepository-branch an UUID) when you do create a new commit would\nbe a sensible thing to have if somebody cares deeply enough.  It\nis an information that is global in nature, and with that, you\ncould do the digging like I did without relying on the committer\nidentity, but instead using the branch identity.\n"},{"id":"19342","messageId":"4456A616.6070402@vilain.net","threadId":"4000","inReplyTo":"7vlktms02x.fsf@assigned-by-dhcp.cox.net","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2006-05-02T00:21:42Z","receivedAt":"2006-05-02T00:21:42Z","isPatch":true,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Junio C Hamano wrote:\n\n>>Aha, now I see reason in the madness. So, the \"prior\" head is not stored\n>>in the trees, and tracking the progress of actual head transitions is\n>>loosely defined / a research topic. But demonstrably derivable. That\n>>works for me.\n>>    \n>>\n>I do not think there is any madness involved here, but I should\n>  \n>\n\nSorry, it was a figure of speech. It's more like, what appeared to be\nmadness no longer looks so.\n\n>point out that the above example happens to work only because\n>Linus and David are two different people.  If Linus did the\n>David's work in a separate repository, or even in the same\n>repository but on a separate branch, people following the Linus\n>tip might still want to know about the fast-forward, but that is\n>something you cannot truly tell by the digging like what I did\n>in the previous message.\n>\n>That is why I earlier said this:\n>\n>    *1* IOW, we _are_ losing some information by not recording the\n>    fact that fast-forward was done while doing so.  \n>\n>    That record should _not_ be in the commit chain.  At the\n>    mechanical level, recording that in the commit chain means two\n>    criss-crossing branches never converge at the commit chain\n>    level, which is already bad.\n>  \n>\n\nHere I'm a little bit confused still. Surely criss-crossing branches\nalready don't converge unless the commits are in the same order.\n\nOh, I see. Even if they *are* in the same order, the commit IDs would\nend up different due to these extra headers.\n\n>  At the philosophical level, the\n>    commit chain is a mesh of many possible \"global\" histories, and\n>    the record that somebody (a particular branch in a particular\n>    repository) was at what point in the mesh at given time does not\n>    belong there.\n>\n>    But from the repository-owner's point of view, that _might_ be a\n>    useful information to keep.  I am just saying this preemptively\n>    so that if somebody wants to record it, that should not be\n>    recorded in the commit object.\n>  \n>\n\nThat makes sense.\n\n>On the other hand, a \"note\" field that records on which branch\n>of which repository each commit was made (you need to give each\n>repository-branch an UUID) when you do create a new commit would\n>be a sensible thing to have if somebody cares deeply enough.  It\n>is an information that is global in nature, and with that, you\n>could do the digging like I did without relying on the committer\n>identity, but instead using the branch identity.\n>  \n>\n\nThat sounds reasonable. The UUID doesn't need to replicate, either, just\ntag the commits that were made against it.\n\nThis extra information falls into the informational, \"forensic\" history\ntracing category. ie, we don't know now whether we'll need it, but we'll\nstore it anyway just to be sure to not make later operations impossible.\n\nI think the large remaining question is around what conventions apply to\nthe use of the \"note\" field. We have perhaps the first example of a well\nformed piece of \"forensic\" information that belongs in the commit chain\nand could possibly be added by plumbing. I can't think of any more of\nthose, but the rename/copy tracking case is a bit different. In this\ncase, it doesn't belong in the plumbing, yet you want a reasonable\nconvention for storing this information to apply. Also the other cases\noutlined in the original post might do well to have a common convention\nso that the information is more portable between porcelain.\n\nSam.\n"},{"id":"19348","messageId":"46a038f90605020008y7f4193d5vb35ec00e3aeb4b90@mail.gmail.com","threadId":"4000","inReplyTo":"4456A616.6070402@vilain.net","subject":"Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and","fromName":"Martin Langhoff","fromEmail":"martin.langhoff@gmail.com","sentAt":"2006-05-02T07:08:49Z","receivedAt":"2006-05-02T07:08:49Z","isPatch":true,"sender":{"key":"martin.langhoff@gmail.com","avatar":"https://gravatar.com/avatar/1e3f311b6c4c15836501901ca58f8c0b0667246488084ba524d8bc9867e22fd9?d=mp&s=160"},"body":"On 5/2/06, Sam Vilain <sam@vilain.net> wrote:\n> Here I'm a little bit confused still. Surely criss-crossing branches\n> already don't converge unless the commits are in the same order.\n\nThey do under GIT. No matter how much you criss-cross, every time you\nidentify a merge base for the next merge, you are identifying the last\ncommit in common on both branches.\n\nWhile maybe you didn't have that commit being the tip of a head in\nyour repo, it _is_ the last common point. If your criss-crossing is\nmessy and a few commits are out of order or cherry picked, git-merge\nhas a good chance of spotting it. The whole mechanism tends pulls\nquite consistently towards convergence.\n\nIf the notes in the commit msg aren't consistent and we lose the\nnatural tendency towards convergence that's a major drawback. On the\nother hand, if two branches have exchanged patches \"out of band\",\ngit-merge still gets it right most of the time, so perhaps slightly\ndifferent headers in the commit messages are tolerable?\n\nJunio had written:\n> >On the other hand, a \"note\" field that records on which branch\n> >of which repository each commit was made (you need to give each\n> >repository-branch an UUID) when you do create a new commit would\n> >be a sensible thing to have if somebody cares deeply enough.\n\nI really don't like that -- goes against the grain of really simple,\nportable repos. I cp -pr repo{,_tmp} all the time to do risky merges\nor save a heavy download from a remote server. Let me run away from\nthis idea... quick before Linus kills us all ;-)\n\nI did feel a couple of times the need of remembering where I had\nchecked this in -- but it went away quite quickly, must have been a\nleftover of my Arch days ;-). And it actually got solved by agreeing\nwithin my team to a commit message format pretty much like what's used\nin the kernel. Because the truth is that most of my heads and branches\nhave very \"local\" names.\n\ncheers,\n\n\n\nmartin\n"}]}