{"thread":{"id":"33466","subject":"Premerging topics (was: [RFD] annnotating a pair of commit objects?)","startedAt":"2013-04-10T20:35:20Z","lastAt":"2013-04-29T22:19:18Z","messageCount":16,"participants":["Antoine Pelisse","Johan Herland","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"213837","messageId":"CALWbr2wocjqs1mpa+yuQ_Zw8m+SX24q6Pby3E3v3-jd-0w1pvQ@mail.gmail.com","threadId":"33466","inReplyTo":null,"subject":"Premerging topics (was: [RFD] annnotating a pair of commit objects?)","fromName":"Antoine Pelisse","fromEmail":"apelisse@gmail.com","sentAt":"2013-04-10T20:35:20Z","receivedAt":"2013-04-10T20:35:20Z","isPatch":false,"sender":{"key":"apelisse@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1929644?v=4"},"body":"The goal is to propose a structure for storing and pre-merging pairs of commits.\n\nData-structure\n==============\n\nWe could use a note ref to store the pre-merge information. Each commit\nwould be annotated with a blob containing the list of pre-merges (one\nsha1 per line with sha1 pointing to a merge commit). The commit on the\nother side of a merge would also be annotated.\n\nThe choice of the refname could be done like we do with notes:\n- Have a default value\n- Have a default value configured in config\n- Use a specific value when merging/creating the pre-merges\n\nHere are my concerns:\n\nPros\n----\n1. Notes allow dynamic annotation a commit\n2. If we manage to fix 4, we can easily download all pre-merges from a\nremote host by fetching the ref (or clean by deleting the ref).\n3. Conflicts on pre-merge notes could probably be resolved by concatenation.\n\nCons\n----\n4. Checking connectivity means opening the blob and parsing it\n5. Regular notes and pre-merge notes have to be handled separately\nbecause of 4.\n\nI'm hoping we can keep the pros and avoid the cons, but I'm kind of\nstuck here. Help would be really appreciated (or maybe this is a totally\nwrong direction, and I would also like to know ;)\n\nMerging (Using what we saved)\n=============================\nThe goal is to merge branches J and B using existing pre-merges.\n\nE0. Create an empty stack S\nE1. Create set of commits 'J..B' and 'B..J' (that is probably already done)\nE2. For each commit C in smallest(J..B, B..J), execute E3\nE3. For each premerge P in notes-premerge(C), execute E4\nE4. If one of both parents of P belongs to biggest(J..B, B..J), stack P in S\nE5. Merge J and B using all pre-merges from S\n\nLet's consider that |J..B| is smaller than |B..J|.\nE0 is executed only once\nE1 is O(|J..B| + |B..J|)\nE2 is O(|J..B|)\nE3 is O(|J..B| x the average number of pre-merge per commits P_avg)\nE4 is executed for each parent (let's say it's two/constant, after all\nthe topic is \"pair\" of commits), so still O(|J..B| x P_avg)\nE5 I don't know (how it can be done, and what would be the resulting\ntime complexity)\n\nSo the time cost for steps E0 to E4 is O(|J..B| + |B..J| x P_avg)\n\nTools (Save the pre-merges)\n===========================\n\nOf course we need several tools to maintain the list of premerges, and\nto easily compute them. For example, it would be nice to be able to do\nsomething like:\n\n    $ git pre-merge topicA topicB topicC\n\nto find, resolve and store all interactions between the topics. We could\nthen easily derive to something that would allow to pre-merge a new\ntopic with all topics already merged in master..pu (for example).\n\nAnyway, this task is left for latter.\n"},{"id":"215064","messageId":"CALWbr2ys4G=Dz+gOqT7-qxjX6KL5FqgfEJqrfmqUmW9HzGLESg@mail.gmail.com","threadId":"33466","inReplyTo":"CALWbr2wocjqs1mpa+yuQ_Zw8m+SX24q6Pby3E3v3-jd-0w1pvQ@mail.gmail.com","subject":"Re: Premerging topics (was: [RFD] annnotating a pair of commit objects?)","fromName":"Antoine Pelisse","fromEmail":"apelisse@gmail.com","sentAt":"2013-04-22T09:23:37Z","receivedAt":"2013-04-22T09:23:37Z","isPatch":false,"sender":{"key":"apelisse@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1929644?v=4"},"body":"Any comment on that ? I think anyone using a \"Topic Workflow\" could\nuse that feature and that it would be a nice addition to the project.\nMaybe I'm totally wrong in the proposal below (please tell me !), but\nthere are some unanswered question that prevents me from starting (and\nI'd really like this to be discussed before actually starting).\n\nOn Wed, Apr 10, 2013 at 10:35 PM, Antoine Pelisse <apelisse@gmail.com> wrote:\n>\n> The goal is to propose a structure for storing and pre-merging pairs of commits.\n>\n> Data-structure\n> ==============\n>\n> We could use a note ref to store the pre-merge information. Each commit\n> would be annotated with a blob containing the list of pre-merges (one\n> sha1 per line with sha1 pointing to a merge commit). The commit on the\n> other side of a merge would also be annotated.\n>\n> The choice of the refname could be done like we do with notes:\n> - Have a default value\n> - Have a default value configured in config\n> - Use a specific value when merging/creating the pre-merges\n>\n> Here are my concerns:\n>\n> Pros\n> ----\n> 1. Notes allow dynamic annotation a commit\n> 2. If we manage to fix 4, we can easily download all pre-merges from a\n> remote host by fetching the ref (or clean by deleting the ref).\n> 3. Conflicts on pre-merge notes could probably be resolved by concatenation.\n>\n> Cons\n> ----\n> 4. Checking connectivity means opening the blob and parsing it\n> 5. Regular notes and pre-merge notes have to be handled separately\n> because of 4.\n>\n> I'm hoping we can keep the pros and avoid the cons, but I'm kind of\n> stuck here. Help would be really appreciated (or maybe this is a totally\n> wrong direction, and I would also like to know ;)\n>\n> Merging (Using what we saved)\n> =============================\n> The goal is to merge branches J and B using existing pre-merges.\n>\n> E0. Create an empty stack S\n> E1. Create set of commits 'J..B' and 'B..J' (that is probably already done)\n> E2. For each commit C in smallest(J..B, B..J), execute E3\n> E3. For each premerge P in notes-premerge(C), execute E4\n> E4. If one of both parents of P belongs to biggest(J..B, B..J), stack P in S\n> E5. Merge J and B using all pre-merges from S\n>\n> Let's consider that |J..B| is smaller than |B..J|.\n> E0 is executed only once\n> E1 is O(|J..B| + |B..J|)\n> E2 is O(|J..B|)\n> E3 is O(|J..B| x the average number of pre-merge per commits P_avg)\n> E4 is executed for each parent (let's say it's two/constant, after all\n> the topic is \"pair\" of commits), so still O(|J..B| x P_avg)\n> E5 I don't know (how it can be done, and what would be the resulting\n> time complexity)\n>\n> So the time cost for steps E0 to E4 is O(|J..B| + |B..J| x P_avg)\n>\n> Tools (Save the pre-merges)\n> ===========================\n>\n> Of course we need several tools to maintain the list of premerges, and\n> to easily compute them. For example, it would be nice to be able to do\n> something like:\n>\n>     $ git pre-merge topicA topicB topicC\n>\n> to find, resolve and store all interactions between the topics. We could\n> then easily derive to something that would allow to pre-merge a new\n> topic with all topics already merged in master..pu (for example).\n>\n> Anyway, this task is left for latter.\n"},{"id":"215198","messageId":"CALKQrgfO9fd+EEA=Vwe94tJbxkX89uDmMHm9rj6L=d4x7JJjaQ@mail.gmail.com","threadId":"33466","inReplyTo":"CALWbr2wocjqs1mpa+yuQ_Zw8m+SX24q6Pby3E3v3-jd-0w1pvQ@mail.gmail.com","subject":"Re: Premerging topics (was: [RFD] annnotating a pair of commit objects?)","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-04-23T06:34:42Z","receivedAt":"2013-04-23T06:34:42Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Wed, Apr 10, 2013 at 10:35 PM, Antoine Pelisse <apelisse@gmail.com> wrote:\n> The goal is to propose a structure for storing and pre-merging pairs of commits.\n>\n> Data-structure\n> ==============\n>\n> We could use a note ref to store the pre-merge information. Each commit\n> would be annotated with a blob containing the list of pre-merges (one\n> sha1 per line with sha1 pointing to a merge commit). The commit on the\n> other side of a merge would also be annotated.\n> The choice of the refname could be done like we do with notes:\n> - Have a default value\n> - Have a default value configured in config\n> - Use a specific value when merging/creating the pre-merges\n>\n> Here are my concerns:\n>\n> Pros\n> ----\n> 1. Notes allow dynamic annotation a commit\n> 2. If we manage to fix 4, we can easily download all pre-merges from a\n> remote host by fetching the ref (or clean by deleting the ref).\n> 3. Conflicts on pre-merge notes could probably be resolved by concatenation.\n>\n> Cons\n> ----\n> 4. Checking connectivity means opening the blob and parsing it\n\nCan you solve this problem with a tree object, instead of inventing a\nspecially-formatted blob?\n\nI.e. given pre-merge info P for a merge between commits A and B: A is\nannotated by a tree object that contains all pre-merges where A is\ninvolved. Each entry in the tree object has a filename and a blob\nSHA1; we store other commit involved in this pre-merge (B) in the\nfilename, and the pre-merge data (P) in the blob SHA1.\n\nConversely, B is annotated with a tree object containing all pre-merge\nentries concerning B, and within there, is an entry called A, pointing\nto the same P.\n\nYou still need \"special handling\" in that you have to know that\n\"refs/notes/pre-merge\" (or whatever it's called) stores tree objects\ninstead of blobs, and how to interpret the contents of those trees,\nbut you'll need such knowledge in any case.\n\nA nice side-effect of using tree objects to store pre-merge entries,\nis that you can do a tree-level merge of them, and it'll do the Right\nThing (assuming two-way merge with no common history), i.e. perform a\nunion merge, and leave you to handle conflicts of individual\npre-merges (i.e. you'll only get conflicts when both sides offer\ndifferent pre-merge data for A + B).\n\n> 5. Regular notes and pre-merge notes have to be handled separately\n> because of 4.\n\nSort of, but you get that for any automated usage of notes for a\nspecific purpose. Just look at the notes-cache mechanism in\nnotes-cache.{h,c}. That's another example of functionality layered on\ntop of notes that makes assumptions on how its notes trees are\nstructured.\n\n> I'm hoping we can keep the pros and avoid the cons, but I'm kind of\n> stuck here. Help would be really appreciated (or maybe this is a totally\n> wrong direction, and I would also like to know ;)\n>\n> Merging (Using what we saved)\n> =============================\n> The goal is to merge branches J and B using existing pre-merges.\n>\n> E0. Create an empty stack S\n> E1. Create set of commits 'J..B' and 'B..J' (that is probably already done)\n> E2. For each commit C in smallest(J..B, B..J), execute E3\n> E3. For each premerge P in notes-premerge(C), execute E4\n> E4. If one of both parents of P belongs to biggest(J..B, B..J), stack P in S\n\nI don't think _both_ parents of P can belong to biggest(J..B, B..J).\nAFAICS J..B and B..J must always be completely disjoint sets of\ncommits (this is easier to see when you consider that \"A..B\" is\nequivalent to \"B ^A\" for any commits A and B), and in E2/E3, you have\nalready made sure that P has a parent in one of them. There is then no\nway that the same parent can occur in the other set, so you have at\nmost _one_ parent in the other set.\n\n> E5. Merge J and B using all pre-merges from S\n\nThis is where things get complicated... :)\n\nFirst there is one important thing that I have not seen a decision on\nyet (maybe this was discussed in an earlier thread?):\n\nGiven pre-merge data P for commit A and B, does P encode the merge of\nthe entire history up to A with the entire history up to B, or does it\nonly encode the merging of the changes introduced in A with the\nchanges introduced in B? In other words, are we merging snapshots or\ndiffs?\n\nIn the former case, we only need to find the most recent commits A and\nB on their respective branches - for which P exists - and then execute\nthat one P (or at most two Ps, if there is a criss-cross pre-merge\nsituation). In the other case, however, we need to enumerate all Ps\nthat apply to the two branches, and find a way to execute them\nchronologically, dealing with missing Ps and conflicting Ps along the\nway. IMHO, only the former approach seems practically solvable.\n\nSo you do not need to enumerate all Ps in J..B vs. B..J, you only need\nto find the _most_ _recent_ P, and execute that one.\n\n> Let's consider that |J..B| is smaller than |B..J|.\n> E0 is executed only once\n> E1 is O(|J..B| + |B..J|)\n> E2 is O(|J..B|)\n> E3 is O(|J..B| x the average number of pre-merge per commits P_avg)\n> E4 is executed for each parent (let's say it's two/constant, after all\n> the topic is \"pair\" of commits), so still O(|J..B| x P_avg)\n> E5 I don't know (how it can be done, and what would be the resulting\n> time complexity)\n>\n> So the time cost for steps E0 to E4 is O(|J..B| + |B..J| x P_avg)\n>\n> Tools (Save the pre-merges)\n> ===========================\n>\n> Of course we need several tools to maintain the list of premerges, and\n> to easily compute them. For example, it would be nice to be able to do\n> something like:\n>\n>     $ git pre-merge topicA topicB topicC\n>\n> to find, resolve and store all interactions between the topics.\n\nLet's leave out octopus merges for now, and only concentrate on two\nbranches at a time.\n\n\nHope this helps,\n\n...Johan\n\n\nPS: Could you also use this mechanism to store rerere information?\n\n\n> We could\n> then easily derive to something that would allow to pre-merge a new\n> topic with all topics already merged in master..pu (for example).\n> Anyway, this task is left for latter.\n\n--\nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"215230","messageId":"CALWbr2x5HDU2t7hpSCkZnuKjTJ1KxYC0v50wsDPT0fm4LyvzWw@mail.gmail.com","threadId":"33466","inReplyTo":"CALKQrgfO9fd+EEA=Vwe94tJbxkX89uDmMHm9rj6L=d4x7JJjaQ@mail.gmail.com","subject":"Re: Premerging topics (was: [RFD] annnotating a pair of commit objects?)","fromName":"Antoine Pelisse","fromEmail":"apelisse@gmail.com","sentAt":"2013-04-23T14:51:39Z","receivedAt":"2013-04-23T14:51:39Z","isPatch":false,"sender":{"key":"apelisse@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1929644?v=4"},"body":"On Tue, Apr 23, 2013 at 8:34 AM, Johan Herland <johan@herland.net> wrote:\n> On Wed, Apr 10, 2013 at 10:35 PM, Antoine Pelisse <apelisse@gmail.com> wrote:\n>> Data-structure\n>> ==============\n>> We could use a note ref to store the pre-merge information. Each commit\n>> would be annotated with a blob containing the list of pre-merges (one\n>> sha1 per line with sha1 pointing to a merge commit). The commit on the\n>> other side of a merge would also be annotated.\n>> The choice of the refname could be done like we do with notes:\n>> - Have a default value\n>> - Have a default value configured in config\n>> - Use a specific value when merging/creating the pre-merges\n>>[snipped]\n>> Cons\n>> ----\n>> 4. Checking connectivity means opening the blob and parsing it\n>\n> Can you solve this problem with a tree object, instead of inventing a\n> specially-formatted blob?\n\nThat looks like a good idea.\n\n> I.e. given pre-merge info P for a merge between commits A and B: A is\n> annotated by a tree object that contains all pre-merges where A is\n> involved. Each entry in the tree object has a filename and a blob\n> SHA1; we store other commit involved in this pre-merge (B) in the\n> filename, and the pre-merge data (P) in the blob SHA1.\n\nBut P is a commit(/merge with two parents), not a blob. Can we have trees\npointing to commits instead of blobs ?\n\n> A nice side-effect of using tree objects to store pre-merge entries,\n> is that you can do a tree-level merge of them, and it'll do the Right\n> Thing (assuming two-way merge with no common history), i.e. perform a\n> union merge, and leave you to handle conflicts of individual\n> pre-merges (i.e. you'll only get conflicts when both sides offer\n> different pre-merge data for A + B).\n\nI'm definitely not sure what you mean here, especially with \"tree-level\nmerge\". Also I think we could be doing three-way merges. But I'm\nno merge-strategies expert, so I'm kind of confused.\n\n>> 5. Regular notes and pre-merge notes have to be handled separately\n>> because of 4.\n>\n> Sort of, but you get that for any automated usage of notes for a\n> specific purpose. Just look at the notes-cache mechanism in\n> notes-cache.{h,c}. That's another example of functionality layered on\n> top of notes that makes assumptions on how its notes trees are\n> structured.\n\nThanks, I will have a look at it.\n\n>> The goal is to merge branches J and B using existing pre-merges.\n>>\n>> E0. Create an empty stack S\n>> E1. Create set of commits 'J..B' and 'B..J' (that is probably already done)\n>> E2. For each commit C in smallest(J..B, B..J), execute E3\n>> E3. For each premerge P in notes-premerge(C), execute E4\n>> E4. If one of both parents of P belongs to biggest(J..B, B..J), stack P in S\n>\n> I don't think _both_ parents of P can belong to biggest(J..B, B..J).\n> AFAICS J..B and B..J must always be completely disjoint sets of\n> commits (this is easier to see when you consider that \"A..B\" is\n> equivalent to \"B ^A\" for any commits A and B), and in E2/E3, you have\n> already made sure that P has a parent in one of them. There is then no\n> way that the same parent can occur in the other set, so you have at\n> most _one_ parent in the other set.\n\nI agree with that. After step E3, one of the parent belongs to one of\nthe two branches. Step E4 makes sure the other parent belongs to the other\nbranch (and not another unrelated branch).\n\n>> E5. Merge J and B using all pre-merges from S\n>\n> This is where things get complicated... :)\n>\n> First there is one important thing that I have not seen a decision on\n> yet (maybe this was discussed in an earlier thread?):\n>\n> Given pre-merge data P for commit A and B, does P encode the merge of\n> the entire history up to A with the entire history up to B, or does it\n> only encode the merging of the changes introduced in A with the\n> changes introduced in B? In other words, are we merging snapshots or\n> diffs?\n>\n> In the former case, we only need to find the most recent commits A and\n> B on their respective branches - for which P exists - and then execute\n> that one P (or at most two Ps, if there is a criss-cross pre-merge\n> situation). In the other case, however, we need to enumerate all Ps\n> that apply to the two branches, and find a way to execute them\n> chronologically, dealing with missing Ps and conflicting Ps along the\n> way. IMHO, only the former approach seems practically solvable.\n>\n> So you do not need to enumerate all Ps in J..B vs. B..J, you only need\n> to find the _most_ _recent_ P, and execute that one.\n\nIndeed, we only need to know the most recent. That's a good point.\n\n       B1   B2    B3\n    O---o---o-----o\n    |      / \\      \\\n    |    P1  P2     M\n    |    /    |     /\n     \\__o_____o___o\n       J1   J2  J3\n\nIn this use-case, we can use P1 to compute P2, and then we only need P2\nto compute the real merge M. The idea would be to use P1 as an implicit\nthird parent to the pre-merge P2, and then P2 as an implicit third\nparent to the real merge M.\n\n>>     $ git pre-merge topicA topicB topicC\n>>\n>> to find, resolve and store all interactions between the topics.\n>\n> Let's leave out octopus merges for now, and only concentrate on two\n> branches at a time.\n\nI was not thinking about octopus merge here, but an easy way to\npre-merge many topic in a \"single step\", so it could be used like this:\n\n    $ git pre-merge $(git for-each-ref refs/heads/??/*)\n\nAnd that would pre-merge each pair of branches between each other. That\nis: \"n choose 2\" (with n the number of branches given)\n\n> Hope this helps,\n\nIt does, thanks !\n\n> PS: Could you also use this mechanism to store rerere information?\n\nThat's one of the primary goal. The problem it would solves are:\n- You could apply pre-merges even on clean merges, while rerere focuses\non conflict resolution. (typical use case is: somebody renames a\nfunction in one topic, somebody decides to use that function in another\ntopic. You won't have a conflict in this situation but the code no\nlonger compiles.)\n- You could easily pull/push pre-merges while today there is not built-in\nmechanism to exchange/remote-save rerere's\n\nCheers,\nAntoine\n"},{"id":"215231","messageId":"7vwqrtl2mk.fsf@alter.siamese.dyndns.org","threadId":"33466","inReplyTo":"CALKQrgfO9fd+EEA=Vwe94tJbxkX89uDmMHm9rj6L=d4x7JJjaQ@mail.gmail.com","subject":"Re: Premerging topics","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-23T14:53:39Z","receivedAt":"2013-04-23T14:53:39Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Herland <johan@herland.net> writes:\n\n> Can you solve this problem with a tree object, instead of inventing a\n> specially-formatted blob?\n\nHmm.  What problem are you guys trying to solve?\n\nI think Michael's use of a merge commit to record a merge result is\nsufficient as a means to record how to recreate an evil merge.\n\n  http://thread.gmane.org/gmane.comp.version-control.git/212570/focus=212578\n\nFWIW, in the [RFD], I wasn't asking for ideas on that part.  When\nrebuiling 'pu', I use an even simpler solution to have rerere\nautoresolve the mechanical part of the merge, and then cherry-pick a\nseparate commit from refs/merge-fix/ hierarchy on the result, and it\nworks perfectly fine (this is done by the 'Reintegrate' script on\nthe 'todo' branch; see Documentation/howto/maintain-git.txt).\n\nWhen topic A is closer to be done than topic B (in other words, when\nI merge topic B to an integration branch, topic A is already merged\nthere), and these topics have semantic conflicts (e.g. A renames a\nfunction foo() to bar(), while B adds a new callsite of foo()), a\nmechanical merge of B may succeed without any textual conflict (or\nif there is, rerere can resolve it), but a semantic fix-up needs to\ndo \"s/foo/bar/g\" on the result.\n\nI would do something like this for the first time:\n\n\t... while on 'pu', A has already been merged ...\n        git merge B ;# may conflict\n        edit textual conflicts away\n        git rerere ;# remember the textual resolution\n        git commit ;# commit _without_ semantics adjustment\n        edit semantic conflict away, i.e. s/foo/bar/g\n        git commit\n        git update-ref refs/merge-fix/B\n\nAfter that, next time I rebuild 'pu', when the automated procedure\nprocesses B, it would \"git merge B\", \"git rerere\", make sure textual\nconflicts are gone, and \"git cherry-pick refs/merge-fix/B\".  To make\nsure this would work, what I typically do immediately after doing\nall of the above is:\n\n\tgit reset --hard HEAD^^\n\nto drop the fix-up commit and merge of B, and actually tell the\nautomated procedure to process B.  It should recreate the evil merge\nusing the information I just recorded.\n\nSo \"how a recipe to recreate an evil merge is recorded\", as far as I\nam concerned, is an already solved problem.\n\nThe part of the existing solution I was not happy was deciding when\nto use which \"merge-fix\" commit to cherry-pick.  If I start merging\ntopic B before topic A, the \"merge-fix/B\" needs to be renamed to\n\"merge-fix/A\" in the above.  Otherwise, when B is merged to 'pu',\nthere is no 'A' merged to it yet, so merge-fix that munges its new\ncall to foo() to call bar() instead will _break_ things [*1*].\n\nAnd that was why I wanted to have a data structure that is quick to\nquery to answer \"I am about to merge B.  Does the history already\nhave an A for which I have recorded a merge-fix for <A,B> pair?\"\n\n\n[Footnote]\n\n*1* If A has other kinds of conflicts with other topics, it is not\nsufficient to just rename \"merge-fix/B\" to \"merge-fix/A\"---the\neffect of cherry-picking \"merge-fix/B\" needs to be merged to\nexisting \"merge-fix/A\".  If a merge-fix is recorded for a pair of\ncommits that necessitates an evil merge, this naturally goes away.\nI can keep a merge-fix for the <A,B> pair whether I merge A before\nor after B, and semantic conflicts A may have with another topic C\nwould be stored in a separate merge-fix for <A,C> pair.\n"},{"id":"215239","messageId":"CALWbr2xAxkNMedbuS-+pPy+Zc5MEhoCWk3oW8BXS9db63DoGAg@mail.gmail.com","threadId":"33466","inReplyTo":"7vwqrtl2mk.fsf@alter.siamese.dyndns.org","subject":"Re: Premerging topics","fromName":"Antoine Pelisse","fromEmail":"apelisse@gmail.com","sentAt":"2013-04-23T15:17:54Z","receivedAt":"2013-04-23T15:17:54Z","isPatch":false,"sender":{"key":"apelisse@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1929644?v=4"},"body":"On Tue, Apr 23, 2013 at 4:53 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Johan Herland <johan@herland.net> writes:\n>\n>> Can you solve this problem with a tree object, instead of inventing a\n>> specially-formatted blob?\n>\n> Hmm.  What problem are you guys trying to solve?\n>\n> [snipped..]\n> And that was why I wanted to have a data structure that is quick to\n> query to answer \"I am about to merge B.  Does the history already\n> have an A for which I have recorded a merge-fix for <A,B> pair?\"\n\nThat's exactly the problem I'm trying to solve.\nI'm willing to have an efficient way to merge topicC that has semantic\nconflicts with topicA and topicB.\nAs topics will be merged together first in pu, then in next and\nfinally in master, chances are that they won't be merged in the same\norder (or then, why would we even care about a topic workflow?). And I\nhave the feeling that \"merge-fix/B\" or \"merge-fix/A\" doesn't hold\nenough information to do that accurately.\n\nThe idea is then to store the <A, B> pair as a note, and to associate\na \"merge\" to that (solving the semantic conflict). It would then be\nused as an implicit third parent for the merge of \"branch containing\nA\" and \"branch containing B\". This is pretty much what Michael said in\nthe $gmane you talked about.\n\nCheers,\nAntoine\n"},{"id":"215242","messageId":"7vsj2hjme3.fsf@alter.siamese.dyndns.org","threadId":"33466","inReplyTo":"CALWbr2xAxkNMedbuS-+pPy+Zc5MEhoCWk3oW8BXS9db63DoGAg@mail.gmail.com","subject":"Re: Premerging topics","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-23T15:29:40Z","receivedAt":"2013-04-23T15:29:40Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Antoine Pelisse <apelisse@gmail.com> writes:\n\n> And I\n> have the feeling that \"merge-fix/B\" or \"merge-fix/A\" doesn't hold\n> enough information to do that accurately.\n\nOh, you do not have to resort to feeling; these names do _not_ hold\nenough information, period.  We already know that, that was why I was\nunhappy, and that was why I sent the \"annotating a pair of commit\nobjects\" RFD in the first place ;-).\n\n> The idea is then to store the <A, B> pair as a note, and to associate\n> a \"merge\" to that (solving the semantic conflict).\n\nOK, and as the datastore for <A, B> pair you were thinking about\nusing a specially-formatted blob and Johan suggested to use a\nregular tree object?\n"},{"id":"215243","messageId":"CALWbr2xosv9pM3yTRvZAhAoR_1DS6fS0jX2ud4=1VeJPSn+5iA@mail.gmail.com","threadId":"33466","inReplyTo":"7vsj2hjme3.fsf@alter.siamese.dyndns.org","subject":"Re: Premerging topics","fromName":"Antoine Pelisse","fromEmail":"apelisse@gmail.com","sentAt":"2013-04-23T15:36:21Z","receivedAt":"2013-04-23T15:36:21Z","isPatch":false,"sender":{"key":"apelisse@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1929644?v=4"},"body":"On Tue, Apr 23, 2013 at 5:29 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Antoine Pelisse <apelisse@gmail.com> writes:\n>\n>> And I\n>> have the feeling that \"merge-fix/B\" or \"merge-fix/A\" doesn't hold\n>> enough information to do that accurately.\n>\n> Oh, you do not have to resort to feeling; these names do _not_ hold\n> enough information, period.  We already know that, that was why I was\n> unhappy, and that was why I sent the \"annotating a pair of commit\n> objects\" RFD in the first place ;-).\n\n:)\n\n>> The idea is then to store the <A, B> pair as a note, and to associate\n>> a \"merge\" to that (solving the semantic conflict).\n>\n> OK, and as the datastore for <A, B> pair you were thinking about\n> using a specially-formatted blob and Johan suggested to use a\n> regular tree object?\n\nExactly. But as I said, it should associate the pair to a merge. And\ntrees contain other trees or blobs, not commits. I'm wondering if this\nis a problem.\n"},{"id":"215279","messageId":"CALKQrgeGPo--cYoGZ30nSfASh4CPzqGXQojkG9Ve96NFr+LrjA@mail.gmail.com","threadId":"33466","inReplyTo":"CALWbr2x5HDU2t7hpSCkZnuKjTJ1KxYC0v50wsDPT0fm4LyvzWw@mail.gmail.com","subject":"Re: Premerging topics (was: [RFD] annnotating a pair of commit objects?)","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-04-23T23:06:55Z","receivedAt":"2013-04-23T23:06:55Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Tue, Apr 23, 2013 at 4:51 PM, Antoine Pelisse <apelisse@gmail.com> wrote:\n> On Tue, Apr 23, 2013 at 8:34 AM, Johan Herland <johan@herland.net> wrote:\n>> On Wed, Apr 10, 2013 at 10:35 PM, Antoine Pelisse <apelisse@gmail.com> wrote:\n>>> Data-structure\n>>> ==============\n>>> We could use a note ref to store the pre-merge information. Each commit\n>>> would be annotated with a blob containing the list of pre-merges (one\n>>> sha1 per line with sha1 pointing to a merge commit). The commit on the\n>>> other side of a merge would also be annotated.\n>>> The choice of the refname could be done like we do with notes:\n>>> - Have a default value\n>>> - Have a default value configured in config\n>>> - Use a specific value when merging/creating the pre-merges\n>>>[snipped]\n>>> Cons\n>>> ----\n>>> 4. Checking connectivity means opening the blob and parsing it\n>>\n>> Can you solve this problem with a tree object, instead of inventing a\n>> specially-formatted blob?\n>\n> That looks like a good idea.\n>\n>> I.e. given pre-merge info P for a merge between commits A and B: A is\n>> annotated by a tree object that contains all pre-merges where A is\n>> involved. Each entry in the tree object has a filename and a blob\n>> SHA1; we store other commit involved in this pre-merge (B) in the\n>> filename, and the pre-merge data (P) in the blob SHA1.\n>\n> But P is a commit(/merge with two parents), not a blob. Can we have trees\n> pointing to commits instead of blobs ?\n\nSort of. We do so when recording submodules in regular git trees. The\nsubmodule is recorded as a tree entry whose type is commit, name is the\nsubdir containing the submodule, and SHA1 is the commit ID recorded for\nthat submodule at this point in history. So it definitely _can_ be done.\nThat said, I'm not sure whether it's actually a good idea in this case...\n\nI apologize for not having followed the initial discussion. I did not\nknow that the pre-merge information would be stored as commits.\nI figured since it would only contain a partial merge resolution, it\ncould be represented as something like a tree object containing (only)\nthe pre-resolved paths...\n\n>> A nice side-effect of using tree objects to store pre-merge entries,\n>> is that you can do a tree-level merge of them, and it'll do the Right\n>> Thing (assuming two-way merge with no common history), i.e. perform a\n>> union merge, and leave you to handle conflicts of individual\n>> pre-merges (i.e. you'll only get conflicts when both sides offer\n>> different pre-merge data for A + B).\n>\n> I'm definitely not sure what you mean here, especially with \"tree-level\n> merge\". Also I think we could be doing three-way merges. But I'm\n> no merge-strategies expert, so I'm kind of confused.\n\nI was simply thinking of the simple two-way merge that can be done between\ntwo independent trees:\n- All paths that exist in only one tree, exist unchanged in the result\n- All paths that are identical in both trees exist unchanged in the result\n- All paths that exist in both trees, but are different, yield a conflict\n\nIn your pre-merge domain, this would become (for given commit A, B, C):\n- If one tree records a pre-merge for (A,B) and the other for (A,C), then\n  both (A,B) and (A,C) will exist in the result\n- If both trees records the _same_ pre-merge resolution for (A,B), then\n  that will also exist in the result\n- If one tree records one way of pre-merging (A,B), and the other tree\n  records a _different_ way of pre-merging (A,B), then there will be a\n  conflict that needs resolving.\n\n>>> 5. Regular notes and pre-merge notes have to be handled separately\n>>> because of 4.\n>>\n>> Sort of, but you get that for any automated usage of notes for a\n>> specific purpose. Just look at the notes-cache mechanism in\n>> notes-cache.{h,c}. That's another example of functionality layered on\n>> top of notes that makes assumptions on how its notes trees are\n>> structured.\n>\n> Thanks, I will have a look at it.\n>\n>>> The goal is to merge branches J and B using existing pre-merges.\n>>>\n>>> E0. Create an empty stack S\n>>> E1. Create set of commits 'J..B' and 'B..J' (that is probably already done)\n>>> E2. For each commit C in smallest(J..B, B..J), execute E3\n>>> E3. For each premerge P in notes-premerge(C), execute E4\n>>> E4. If one of both parents of P belongs to biggest(J..B, B..J), stack P in S\n>>\n>> I don't think _both_ parents of P can belong to biggest(J..B, B..J).\n>> AFAICS J..B and B..J must always be completely disjoint sets of\n>> commits (this is easier to see when you consider that \"A..B\" is\n>> equivalent to \"B ^A\" for any commits A and B), and in E2/E3, you have\n>> already made sure that P has a parent in one of them. There is then no\n>> way that the same parent can occur in the other set, so you have at\n>> most _one_ parent in the other set.\n>\n> I agree with that. After step E3, one of the parent belongs to one of\n> the two branches. Step E4 makes sure the other parent belongs to the other\n> branch (and not another unrelated branch).\n>\n>>> E5. Merge J and B using all pre-merges from S\n>>\n>> This is where things get complicated... :)\n>>\n>> First there is one important thing that I have not seen a decision on\n>> yet (maybe this was discussed in an earlier thread?):\n>>\n>> Given pre-merge data P for commit A and B, does P encode the merge of\n>> the entire history up to A with the entire history up to B, or does it\n>> only encode the merging of the changes introduced in A with the\n>> changes introduced in B? In other words, are we merging snapshots or\n>> diffs?\n>>\n>> In the former case, we only need to find the most recent commits A and\n>> B on their respective branches - for which P exists - and then execute\n>> that one P (or at most two Ps, if there is a criss-cross pre-merge\n>> situation). In the other case, however, we need to enumerate all Ps\n>> that apply to the two branches, and find a way to execute them\n>> chronologically, dealing with missing Ps and conflicting Ps along the\n>> way. IMHO, only the former approach seems practically solvable.\n>>\n>> So you do not need to enumerate all Ps in J..B vs. B..J, you only need\n>> to find the _most_ _recent_ P, and execute that one.\n>\n> Indeed, we only need to know the most recent. That's a good point.\n>\n>        B1   B2    B3\n>     O---o---o-----o\n>     |      / \\      \\\n>     |    P1  P2     M\n>     |    /    |     /\n>      \\__o_____o___o\n>        J1   J2  J3\n>\n> In this use-case, we can use P1 to compute P2, and then we only need P2\n> to compute the real merge M. The idea would be to use P1 as an implicit\n> third parent to the pre-merge P2, and then P2 as an implicit third\n> parent to the real merge M.\n\nI'm not sure what is really meant by \"implicit third parent\" here. Will\nGit automatically help you (i.e. auto-resolve conflicts in the correct\nmanner) if you do an octopus merge between (B3, J3, P2)? I thought you\nwould have to start by merging J3 and B3, and then - as part of the\nconflict resolution process - you invoke the pre-merge machinery, which\ngoes searching for pre-merges and finds P2, which is then used to help\nauto-resolve (some of) the conflicts between B3 and J3. This means that\nP2 is not a merge parent in the traditional sense, and I also don't think\nthat you want to record P2 as a \"proper\" parent of the resulting merge\ncommit M.\n\nAt this point I also wonder why the pre-merges (P1, P2) has to be\nrecorded as commit objects. Do they have meaningful commit messages?\n\n...Johan\n\n>>>     $ git pre-merge topicA topicB topicC\n>>>\n>>> to find, resolve and store all interactions between the topics.\n>>\n>> Let's leave out octopus merges for now, and only concentrate on two\n>> branches at a time.\n>\n> I was not thinking about octopus merge here, but an easy way to\n> pre-merge many topic in a \"single step\", so it could be used like this:\n>\n>     $ git pre-merge $(git for-each-ref refs/heads/??/*)\n>\n> And that would pre-merge each pair of branches between each other. That\n> is: \"n choose 2\" (with n the number of branches given)\n>\n>> Hope this helps,\n>\n> It does, thanks !\n>\n>> PS: Could you also use this mechanism to store rerere information?\n>\n> That's one of the primary goal. The problem it would solves are:\n> - You could apply pre-merges even on clean merges, while rerere focuses\n> on conflict resolution. (typical use case is: somebody renames a\n> function in one topic, somebody decides to use that function in another\n> topic. You won't have a conflict in this situation but the code no\n> longer compiles.)\n> - You could easily pull/push pre-merges while today there is not built-in\n> mechanism to exchange/remote-save rerere's\n\n\n--\nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"215284","messageId":"7vzjwofpht.fsf@alter.siamese.dyndns.org","threadId":"33466","inReplyTo":"CALKQrgeGPo--cYoGZ30nSfASh4CPzqGXQojkG9Ve96NFr+LrjA@mail.gmail.com","subject":"Re: Premerging topics","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-24T05:48:30Z","receivedAt":"2013-04-24T05:48:30Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Herland <johan@herland.net> writes:\n\n>> But P is a commit(/merge with two parents), not a blob. Can we have trees\n>> pointing to commits instead of blobs ?\n>\n> Sort of. We do so when recording submodules in regular git trees.\n\nYou are using notes to maintain reachability, aren't you?  Because\ncommit objects that appears in trees are not treated as reachable\nfrom the trees, that won't fly.\n\nI think you guys are making it unnecessarily complex by using notes.\nTo record a prepared evil merge for merging branch that contains A\nwith another branch that contains B (assuming that the interation\nbetween A and B is what makes the evil merge necessary, e.g. A\nrenames a function foo() to bar(), while B adds new callsite that\ncalls foo()), we can store a single commit that records the prepared\nevil merge under \"refs/merge-fix/$A-$B\" where A and B are their\nobject names.\n\nThen when merging a branch Y that contains B into our history X that\nalready contains A (or vice versa),\n\n  ---o---o---A---o---X... ???\n      \\                  .\n       \\                .\n        \\              .\n         o---B----o---Y\n\nwe can enumerate the commits that appear in \"log --left-right X...Y\"\non the left/right side and notice there is refs/merge-fix/$A-$B.\n\nSo the simplest implementation of \"an efficient data store to record\na commit for <A,B> pair\" turns out to be just a ref namespace ;-)\n\nThere may be other <C,D> pairs in X...Y history, and it probably is\nthe sane thing to do to replay prepackaged evil merges from older to\nnewer in the topological sense, but that loop would be trivial, once\nwe understand how to replay a single such evil merge.\n\nThe actual merge-fix data should be just a commit with a single\nparent. The easiest way to prepare it would be like this:\n\n  ---o---o---A\n      \\       \\\n       \\       M---F\n        \\     /\n         o---B\n\nwhere M is the result of mechanical merge between A and B (there\ncould be textual conflicts and you could choose to leave them in, or\nyou could choose to have rerere resolve it.  As long as you do the\nsame when replaying this prepackaged evil merge, this choice does\nnot matter, but using rerere will make your life easier), and F is\nthe final result you would want, with semantics conflicts resolved.\nIn other words, in the ideal world, you would have resolved a merge\nbetween A and B to record the tree of F.\n\nPoint \"F\" with refs/merge-fix/$A-$B and you are done.\n\nWhen you replay this prepackaged evil merge, first you mechanically\nmerge X and Y without worrying about M or F to produce N.  If you\nallowed rerere to resolve textual conflicts between A and B when you\nrecorded M, allow rerere to resolve this merge.  Otherwise leave the\ntextual conflict in.\n\n  ---o---o---A---o---X\n      \\               \\\n       \\               N\n        \\             /\n         o---B---o---Y\n\nThen on top of N, you cherry-pick F, which will bring the semantic\nconflict resolution between M and F on top of N.\n\n  ---o---o---A---o---X\n      \\               \\\n       \\               N---F'\n        \\             /\n         o---B---o---Y\n\nOnce you know the tree shape of F', then you no longer need N.  Just\namend it away and make the tree recorded in F' the result of the\nmerge between X and Y.\n\n  ---o---o---A---o---X---.\n      \\                   \\\n       \\                  F''\n        \\                /\n         o---B---o---Y--.\n"},{"id":"215286","messageId":"CALKQrgd8jZQ__rnAT3wbfx-Y6mg-vrTdam53nS2ya2c=yMcS6Q@mail.gmail.com","threadId":"33466","inReplyTo":"7vzjwofpht.fsf@alter.siamese.dyndns.org","subject":"Re: Premerging topics","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2013-04-24T06:22:18Z","receivedAt":"2013-04-24T06:22:18Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"On Wed, Apr 24, 2013 at 7:48 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Johan Herland <johan@herland.net> writes:\n>\n>>> But P is a commit(/merge with two parents), not a blob. Can we have trees\n>>> pointing to commits instead of blobs ?\n>>\n>> Sort of. We do so when recording submodules in regular git trees.\n>\n> You are using notes to maintain reachability, aren't you?  Because\n> commit objects that appears in trees are not treated as reachable\n> from the trees, that won't fly.\n>\n> I think you guys are making it unnecessarily complex by using notes.\n> To record a prepared evil merge for merging branch that contains A\n> with another branch that contains B (assuming that the interation\n> between A and B is what makes the evil merge necessary, e.g. A\n> renames a function foo() to bar(), while B adds new callsite that\n> calls foo()), we can store a single commit that records the prepared\n> evil merge under \"refs/merge-fix/$A-$B\" where A and B are their\n> object names.\n>\n> Then when merging a branch Y that contains B into our history X that\n> already contains A (or vice versa),\n>\n>   ---o---o---A---o---X... ???\n>       \\                  .\n>        \\                .\n>         \\              .\n>          o---B----o---Y\n>\n> we can enumerate the commits that appear in \"log --left-right X...Y\"\n> on the left/right side and notice there is refs/merge-fix/$A-$B.\n>\n> So the simplest implementation of \"an efficient data store to record\n> a commit for <A,B> pair\" turns out to be just a ref namespace ;-)\n>\n> There may be other <C,D> pairs in X...Y history, and it probably is\n> the sane thing to do to replay prepackaged evil merges from older to\n> newer in the topological sense, but that loop would be trivial, once\n> we understand how to replay a single such evil merge.\n\nThis raises the same question I recently asked Antoine: For a given\nprepackaged merge <X,Y>, do we assume that it only resolves conflicts\nbetween the changes introduced in commit X vs. changes introduced in\ncommit Y, or do we assume that it resolves conflicts between the\nhistories leading up to X and Y, respectively? In other words, does\n<X,Y> _supercede_ earlier pre-merges between the histories leading up\nto X and Y?\n\nI think the latter makes more sense, since we can then reduce the\nnumber of pre-merges to consider in the final merge. There might still\nbe more than one pre-merge to consider, though, e.g. in criss-cross\ncases like this:\n\n  ---o---o---o---o---o---o---o---o\n      \\             /     \\       \\\n       \\           /       \\       \\\n        \\         /         \\       \\\n         o---o---o           P2      \\\n          \\       \\         /         \\\n           \\       \\       /           M\n            \\       \\     /           /\n             o---o---+---o           /\n              \\       \\   \\         /\n               \\       P1  \\       /\n                \\     /     \\     /\n                 o---o---o---o---o\n\n(there is no commit at the \"+\")\n\n> The actual merge-fix data should be just a commit with a single\n> parent. The easiest way to prepare it would be like this:\n>\n>   ---o---o---A\n>       \\       \\\n>        \\       M---F\n>         \\     /\n>          o---B\n>\n> where M is the result of mechanical merge between A and B (there\n> could be textual conflicts and you could choose to leave them in, or\n> you could choose to have rerere resolve it.  As long as you do the\n> same when replaying this prepackaged evil merge, this choice does\n> not matter, but using rerere will make your life easier), and F is\n> the final result you would want, with semantics conflicts resolved.\n> In other words, in the ideal world, you would have resolved a merge\n> between A and B to record the tree of F.\n>\n> Point \"F\" with refs/merge-fix/$A-$B and you are done.\n>\n> When you replay this prepackaged evil merge, first you mechanically\n> merge X and Y without worrying about M or F to produce N.  If you\n> allowed rerere to resolve textual conflicts between A and B when you\n> recorded M, allow rerere to resolve this merge.  Otherwise leave the\n> textual conflict in.\n>\n>   ---o---o---A---o---X\n>       \\               \\\n>        \\               N\n>         \\             /\n>          o---B---o---Y\n>\n> Then on top of N, you cherry-pick F, which will bring the semantic\n> conflict resolution between M and F on top of N.\n>\n>   ---o---o---A---o---X\n>       \\               \\\n>        \\               N---F'\n>         \\             /\n>          o---B---o---Y\n>\n> Once you know the tree shape of F', then you no longer need N.  Just\n> amend it away and make the tree recorded in F' the result of the\n> merge between X and Y.\n>\n>   ---o---o---A---o---X---.\n>       \\                   \\\n>        \\                  F''\n>         \\                /\n>          o---B---o---Y--.\n\nThis is obviously a much better way to solve it. It might already be\nobvious, but I would suggest when making \"refs/merge-fix/$A-$B\" that you\ncanonicalize the name by always choosing A and B such that A precedes B\nalphabetically. That way you won't have problems with both recording\n\"refs/merge-fix/$A-$B\" and \"refs/merge-fix/$B-$A\".\n\n\n...Johan\n\n--\nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"215289","messageId":"7vppxkflhq.fsf@alter.siamese.dyndns.org","threadId":"33466","inReplyTo":"CALKQrgd8jZQ__rnAT3wbfx-Y6mg-vrTdam53nS2ya2c=yMcS6Q@mail.gmail.com","subject":"Re: Premerging topics","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-24T07:14:57Z","receivedAt":"2013-04-24T07:14:57Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Herland <johan@herland.net> writes:\n\n> This raises the same question I recently asked Antoine: For a given\n> prepackaged merge <X,Y>, do we assume that it only resolves conflicts\n> between the changes introduced in commit X vs. changes introduced in\n> commit Y, or do we assume that it resolves conflicts between the\n> histories leading up to X and Y, respectively? In other words, does\n> <X,Y> _supercede_ earlier pre-merges between the histories leading up\n> to X and Y?\n\nThat is an interesting question.  There are largely two cases.\n\nWhen you replayed M---F to produce N---F', there may have been no\ntextual or semantic conflict.  Which means that there were no new\nreason between A--X and B--Y that necessitates an evil merge.  A\nlater merge between a descendant of X (but not Y) and a descendant\nof Y (but not X) can cherry pick the same <A,B> (M---F) on top of a\nmechanical merge,\n\nOn the other hand, you may have had either a textual or a semantic\nconflict when replaying <A,B> on N, and you had to fix up F' for it\nto be the correct resolution of merge between X and Y.\n\n  ---o---o---A---o---X\n      \\               \\\n       \\               N---F'\n        \\             /\n         o---B---o---Y\n\nIn such a case, you do want to record the fixed N---F' as the\nprepackaged resolution for <X,Y>.  Any time later when somebody is\non a branch that has X (but not Y) and merges a branch that has Y\n(but not X), that N---F' should be the one to cherry-pick on top of\na mechanical merge O between S and T.  What <A,B> (M---F) did is\nsuperseded if you are going to replay <X,Y>.\n\n  ---o---o---A---o---X----------S\n      \\       \\       \\          \\\n       \\       M--F    N---F'     O---F''\n        \\     /       /          /\n         o---B---o---Y----------T\n\nYou can tell that by noticing that A is an ancestor of X and B is an\nancestor of Y.  As you said, this is a good way to reduce the number\nof prepackaged evil merges that need to be considered.\n"},{"id":"215848","messageId":"CALWbr2xD4i4kipp4XAdbZ7pVKD2vk_UdBdE04oU-8nhTc5Dtbw@mail.gmail.com","threadId":"33466","inReplyTo":"7vzjwofpht.fsf@alter.siamese.dyndns.org","subject":"Re: Premerging topics","fromName":"Antoine Pelisse","fromEmail":"apelisse@gmail.com","sentAt":"2013-04-29T13:04:19Z","receivedAt":"2013-04-29T13:04:19Z","isPatch":false,"sender":{"key":"apelisse@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1929644?v=4"},"body":"On Wed, Apr 24, 2013 at 7:48 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> there\n> could be textual conflicts and you could choose to leave them in, or\n> you could choose to have rerere resolve it.  As long as you do the\n> same when replaying this prepackaged evil merge, this choice does\n> not matter, but using rerere will make your life easier\n\nThe problem is that rerere can not be easily shared, and I'm afraid it\nwould be almost impossible to go without it (do you commit N with\nconflict markers hoping that F' will remove them?).\nBut, as it looks like you would save F on top of M, it means that M\nwould be reachable, and thus rerere would be \"recomputable\" from\nsomewhere else.\n"},{"id":"215856","messageId":"7vtxmpl6go.fsf@alter.siamese.dyndns.org","threadId":"33466","inReplyTo":"CALWbr2xD4i4kipp4XAdbZ7pVKD2vk_UdBdE04oU-8nhTc5Dtbw@mail.gmail.com","subject":"Re: Premerging topics","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-29T15:08:55Z","receivedAt":"2013-04-29T15:08:55Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Antoine Pelisse <apelisse@gmail.com> writes:\n\n> But, as it looks like you would save F on top of M, it means that M\n> would be reachable, and thus rerere would be \"recomputable\" from\n> somewhere else.\n\nExactly.\n"},{"id":"215902","messageId":"CALWbr2wiYkHMSihh-X-ToO-j4fty-P5OHicHa8ZUoqBkLS5mow@mail.gmail.com","threadId":"33466","inReplyTo":"7vppxkflhq.fsf@alter.siamese.dyndns.org","subject":"Re: Premerging topics","fromName":"Antoine Pelisse","fromEmail":"apelisse@gmail.com","sentAt":"2013-04-29T19:06:59Z","receivedAt":"2013-04-29T19:06:59Z","isPatch":false,"sender":{"key":"apelisse@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1929644?v=4"},"body":"Should we think about adding some commands for that ?\n\nOn the very top of my head (there is certainly more than that):\n- Save such a change: By basically creating a ref to HEAD (HEAD being\nthe commit, HEAD^ the fixed merge) with merge-fix/HEAD^^1-HEAD^^2\n- Apply the merge-fix: On top of a merge, find the most recent\nmerge-fix for HEAD^1/HEAD^2 (according to what was discussed), and\nsquash it.\n\nOn Wed, Apr 24, 2013 at 9:14 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Johan Herland <johan@herland.net> writes:\n>\n>> This raises the same question I recently asked Antoine: For a given\n>> prepackaged merge <X,Y>, do we assume that it only resolves conflicts\n>> between the changes introduced in commit X vs. changes introduced in\n>> commit Y, or do we assume that it resolves conflicts between the\n>> histories leading up to X and Y, respectively? In other words, does\n>> <X,Y> _supercede_ earlier pre-merges between the histories leading up\n>> to X and Y?\n>\n> That is an interesting question.  There are largely two cases.\n>\n> When you replayed M---F to produce N---F', there may have been no\n> textual or semantic conflict.  Which means that there were no new\n> reason between A--X and B--Y that necessitates an evil merge.  A\n> later merge between a descendant of X (but not Y) and a descendant\n> of Y (but not X) can cherry pick the same <A,B> (M---F) on top of a\n> mechanical merge,\n>\n> On the other hand, you may have had either a textual or a semantic\n> conflict when replaying <A,B> on N, and you had to fix up F' for it\n> to be the correct resolution of merge between X and Y.\n>\n>   ---o---o---A---o---X\n>       \\               \\\n>        \\               N---F'\n>         \\             /\n>          o---B---o---Y\n>\n> In such a case, you do want to record the fixed N---F' as the\n> prepackaged resolution for <X,Y>.  Any time later when somebody is\n> on a branch that has X (but not Y) and merges a branch that has Y\n> (but not X), that N---F' should be the one to cherry-pick on top of\n> a mechanical merge O between S and T.  What <A,B> (M---F) did is\n> superseded if you are going to replay <X,Y>.\n>\n>   ---o---o---A---o---X----------S\n>       \\       \\       \\          \\\n>        \\       M--F    N---F'     O---F''\n>         \\     /       /          /\n>          o---B---o---Y----------T\n>\n> You can tell that by noticing that A is an ancestor of X and B is an\n> ancestor of Y.  As you said, this is a good way to reduce the number\n> of prepackaged evil merges that need to be considered.\n>\n"},{"id":"215925","messageId":"7v61z5geu1.fsf@alter.siamese.dyndns.org","threadId":"33466","inReplyTo":"CALWbr2wiYkHMSihh-X-ToO-j4fty-P5OHicHa8ZUoqBkLS5mow@mail.gmail.com","subject":"Re: Premerging topics","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-29T22:19:18Z","receivedAt":"2013-04-29T22:19:18Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Antoine Pelisse <apelisse@gmail.com> writes:\n\n> Should we think about adding some commands for that ?\n>\n> On the very top of my head (there is certainly more than that):\n> - Save such a change: By basically creating a ref to HEAD (HEAD being\n> the commit, HEAD^ the fixed merge) with merge-fix/HEAD^^1-HEAD^^2\n> - Apply the merge-fix: On top of a merge, find the most recent\n> merge-fix for HEAD^1/HEAD^2 (according to what was discussed), and\n> squash it.\n\nYeah, some nasties may live in the details, but these two operations\nare needed and probably sufficient as the end-user facing UI.\n\nThe \"save\" step, when done manually, needs to be a two-step process\nthat saves M and then F separately, but somebody _might_ be able to\ncome up with a clever idea to let the user jump directly to F\nwithout recording M.  If such a triangle (A and B merges to F) can\nbe recorded as merge-fix/A-B, that would certainly be less error\nprone and easier for the users to use.  Having said that, in the\npresense of possible textual conflicts when creating M, I do not\nthink of a way that is easily implementable mechanically to\ninternally sift changes for M and F when replaying it while\nresolving a merge between X and Y to produce N and eventually F'.\n\nThe \"apply\" step should be a single step, and it should be easy to\nimplement mechanically if M and F are recorded separately (but\nagain, you may be able to re-synthesise M from A and B when you need\nto replay the evil merge).\n"}]}