{"thread":{"id":"60481","subject":"first-class conflicts?","startedAt":"2023-11-06T21:26:10Z","lastAt":"2023-11-12T23:25:32Z","messageCount":25,"participants":["Sandra Snan","Dragan Simic","rsbecker@nexbridge.com","Elijah Newren","Phillip Wood","Martin von Zweigbergk","phillip.wood123@gmail.com","Theodore Ts'o","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"484471","messageId":"87cywmintp.fsf@ellen.idiomdrottning.org","threadId":"60481","inReplyTo":null,"subject":"first-class conflicts?","fromName":"Sandra Snan","fromEmail":"sandra.snan@idiomdrottning.org","sentAt":"2023-11-06T21:17:22Z","receivedAt":"2023-11-06T21:26:10Z","isPatch":false,"sender":{"key":"sandra.snan@idiomdrottning.org","avatar":"https://gravatar.com/avatar/9f3cf671ef175db9ce2f833436f4f63b58f54651b1208ef07e63ee7443e86e82?d=mp&s=160"},"body":"Is this feature from jj also a good idea for git?\nhttps://martinvonz.github.io/jj/v0.11.0/conflicts/\n"},{"id":"484472","messageId":"ef30a484525157579c64249a396f10ae@manjaro.org","threadId":"60481","inReplyTo":"87cywmintp.fsf@ellen.idiomdrottning.org","subject":"Re: first-class conflicts?","fromName":"Dragan Simic","fromEmail":"dsimic@manjaro.org","sentAt":"2023-11-06T22:01:18Z","receivedAt":"2023-11-06T22:01:22Z","isPatch":false,"sender":{"key":"dsimic@manjaro.org","avatar":null},"body":"On 2023-11-06 22:17, Sandra Snan wrote:\n> Is this feature from jj also a good idea for git?\n> https://martinvonz.github.io/jj/v0.11.0/conflicts/\n\nHmm, that's quite interesting, but frankly it makes little sense to me.  \nSee, the source code in a repository should always be in a compileable \nor runnable state, in each and every commit, so going against that rule \nwouldn't make much sense.  Just think about various CI/CD tools that \nalso expect the same.\n"},{"id":"484473","messageId":"Mr.4OIMhhBXVmQ.FTCKAvYUnjv@idiomdrottning.org","threadId":"60481","inReplyTo":"ef30a484525157579c64249a396f10ae@manjaro.org","subject":"Re: first-class conflicts?","fromName":"Sandra Snan","fromEmail":"sandra.snan@idiomdrottning.org","sentAt":"2023-11-06T22:34:35Z","receivedAt":"2023-11-06T22:34:39Z","isPatch":false,"sender":{"key":"sandra.snan@idiomdrottning.org","avatar":"https://gravatar.com/avatar/9f3cf671ef175db9ce2f833436f4f63b58f54651b1208ef07e63ee7443e86e82?d=mp&s=160"},"body":"I've sometimes merged stuff in and almost not notice that I had a conflict \nin there and in those cases the code wasn't compilable even though I was \nusing vanilla git.\n"},{"id":"484474","messageId":"002901da1101$7d39a420$77acec60$@nexbridge.com","threadId":"60481","inReplyTo":"ef30a484525157579c64249a396f10ae@manjaro.org","subject":"RE: first-class conflicts?","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2023-11-06T22:34:59Z","receivedAt":"2023-11-06T22:35:21Z","isPatch":false,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On November 6, 2023 5:01 PM, Dragan Simic wrote:\n>On 2023-11-06 22:17, Sandra Snan wrote:\n>> Is this feature from jj also a good idea for git?\n>> https://martinvonz.github.io/jj/v0.11.0/conflicts/\n>\n>Hmm, that's quite interesting, but frankly it makes little sense to me.\n>See, the source code in a repository should always be in a compileable or\nrunnable\n>state, in each and every commit, so going against that rule wouldn't make\nmuch\n>sense.  Just think about various CI/CD tools that also expect the same.\n\nIt seems to me, perhaps naively, that the longer a conflict persists in a\nrepository, the greater the potential for chaotic results. There are,\nnotably, at least two fundamental types of conflicts:\n\n1. Content conflict, where a point in a file is modified in two (or n)\nbranches being combined, is what git tries to ensure never happens. The\nlonger such a conflict exists in a file, the greater the variance from a\nbuildable or consistent state will persist and will likely be increasingly\nharder to resolve.\n\n2. Semantic conflicts, where unrelated modification points cause\nincompatibilities are much harder to resolve and quantify - many are, in\nfact, undetectable from a computational standpoint (as in detecting general\nsemantic conflicts is an uncomputable problem). The longer those persist,\npartly when they are missed by pull requests/code reviews, the more\npersistent a defect can become.\n\n3. I am avoiding matters such as code optimization conflicts which are\noutside the scope of the proposal.\n\nIn either case, storing conflicts in the integration branches of a\nrepository is, in my view, a bad thing that eventually can make the\nrepository unsustainable. I will concede that keeping conflicts around in\nnon-integration branches may have intellectual value for recording research\nand development progress.\n\nThis is just my opinion.\nRandall\n\n--\nBrief whoami: NonStop&UNIX developer since approximately\nUNIX(421664400)\nNonStop(211288444200000000)\n-- In real life, I talk too much.\n\n\n\n"},{"id":"484475","messageId":"Gr..Y5kkszDx87g@idiomdrottning.org","threadId":"60481","inReplyTo":"002901da1101$7d39a420$77acec60$@nexbridge.com","subject":"Re: RE: first-class conflicts?","fromName":"Sandra Snan","fromEmail":"sandra.snan@idiomdrottning.org","sentAt":"2023-11-06T22:45:03Z","receivedAt":"2023-11-06T22:45:07Z","isPatch":false,"sender":{"key":"sandra.snan@idiomdrottning.org","avatar":"https://gravatar.com/avatar/9f3cf671ef175db9ce2f833436f4f63b58f54651b1208ef07e63ee7443e86e82?d=mp&s=160"},"body":"Randall, thank you for that.\n\nI did mean of the first type, pure content conflicts (just like the examples \non that jj page).\n\nI just have sometimes wish git could be a little more aware of them beyond \njust storing them with ASCII art in the files themselves (and alerting / \nwarning when they happen but I often can't properly see those warnings flash \nby so I end up having to search for the conflict markers manually). So if \nconflicts are a thing that *can* happen, it'd be better if vc could know \nabout them which would make some of the rebases simpler as in jj. That doesn't \nmean we wanna adopt the jj workflow of deliberately checking in conflicts \n(not even locally), just be able to deal with them better if it does happen.\n\nI dunno… and I've really appreciated the naysayers so far, helps me sort \nout my thoughts in this. I personally really prefer the vanilla \"explicit \nstaging\" workflow (with magit) over jj, got, gitless etc. I'm more scared \nof overcommitting by mistake than undercommitting. But this one feature \nseemed to me that it might be really good: just having the vc be aware of \nthe conflicts it has created.\n"},{"id":"484513","messageId":"CABPp-BH7WBm1j-Ue9oZFjoy6sTcw5B0hz_ndDEtJqvpZF4YF=w@mail.gmail.com","threadId":"60481","inReplyTo":"87cywmintp.fsf@ellen.idiomdrottning.org","subject":"Re: first-class conflicts?","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2023-11-07T08:16:39Z","receivedAt":"2023-11-07T08:16:55Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Mon, Nov 6, 2023 at 1:26 PM Sandra Snan\n<sandra.snan@idiomdrottning.org> wrote:\n>\n> Is this feature from jj also a good idea for git?\n> https://martinvonz.github.io/jj/v0.11.0/conflicts/\n\nMartin talked about this and other features at Git Merge 2022, a\nlittle over a year ago.  I talked to him in more depth about these\nwhile there.  I personally think he has some really interesting\nfeatures here, though at the time, I thought that the additional\nobject type might be too much to ask for in a Git change, and it was\nan intrinsic part of the implementation back then.\n\nMartin also gave us an update at the 2023 Git Contributors summit, and\nin particular noted a significant implementation change to not have\nper-file storage of conflicts, but rather storing at the commit level\nthe multiple conflicting trees involved.  That model might be\nsomething we could implement in Git.  And if we did, it'd solve\nvarious issues such as people wanting to be able to stash conflicts,\nor wanting to be able to partially resolve conflicts and fix it up\nlater, or be able to collaboratively resolve conflicts without having\neveryone have access to the same checkout.\n\nBut we'd also have to be careful and think through usecases, including\nin the surrounding community.  People would probably want to ensure\nthat e.g. \"Protected\" or \"Integration\" branches don't get accept\nfetches or pushes of conflicted commits, git status would probably\nneed some special warnings or notices, git checkout would probably\nbenefit from additional warnings/notices checks for those cases, git\nlog should probably display conflicted commits differently, we'd need\nto add special handling for higher order conflicts (e.g. a merge with\nconflicts is itself involved in a merge) probably similar to what jj\nhas done, and audit a lot of other code paths to see what would be\nneeded.\n\nI think it'd be really interesting to at least investigate, but it'd\nalso be a lot of work, and I already have several other things I've\nbeen wanting to get back to for over a year and haven't succeeded in\ngenerating more time for Git.\n\nAnyway, just my $0.02.\nElijah\n"},{"id":"484514","messageId":"6f15723ef86a40e939b98b731cd8026e@manjaro.org","threadId":"60481","inReplyTo":"CABPp-BH7WBm1j-Ue9oZFjoy6sTcw5B0hz_ndDEtJqvpZF4YF=w@mail.gmail.com","subject":"Re: first-class conflicts?","fromName":"Dragan Simic","fromEmail":"dsimic@manjaro.org","sentAt":"2023-11-07T08:21:22Z","receivedAt":"2023-11-07T08:21:26Z","isPatch":false,"sender":{"key":"dsimic@manjaro.org","avatar":null},"body":"On 2023-11-07 09:16, Elijah Newren wrote:\n> But we'd also have to be careful and think through usecases, including\n> in the surrounding community.  People would probably want to ensure\n> that e.g. \"Protected\" or \"Integration\" branches don't get accept\n> fetches or pushes of conflicted commits, git status would probably\n> need some special warnings or notices, git checkout would probably\n> benefit from additional warnings/notices checks for those cases, git\n> log should probably display conflicted commits differently, we'd need\n> to add special handling for higher order conflicts (e.g. a merge with\n> conflicts is itself involved in a merge) probably similar to what jj\n> has done, and audit a lot of other code paths to see what would be\n> needed.\n\nThat would be a truly _massive_ project.\n"},{"id":"484515","messageId":"874jhxj531.fsf@ellen.idiomdrottning.org","threadId":"60481","inReplyTo":"CABPp-BH7WBm1j-Ue9oZFjoy6sTcw5B0hz_ndDEtJqvpZF4YF=w@mail.gmail.com","subject":"Re: first-class conflicts?","fromName":"Sandra Snan","fromEmail":"sandra.snan@idiomdrottning.org","sentAt":"2023-11-07T09:16:50Z","receivedAt":"2023-11-07T09:16:57Z","isPatch":false,"sender":{"key":"sandra.snan@idiomdrottning.org","avatar":"https://gravatar.com/avatar/9f3cf671ef175db9ce2f833436f4f63b58f54651b1208ef07e63ee7443e86e82?d=mp&s=160"},"body":"Elijah Newren <newren@gmail.com> writes:\n> Martin talked about this and other features at Git Merge 2022, a \n> little over a year ago.\n\nThat is something I should've checked or searched for before \nstarting this thread, in hindsight. Thank you, Elijah, for letting \nme know that.\n\n> And if we did, it'd solve various issues such as people wanting \n> to be able to stash conflicts, or wanting to be able to \n> partially resolve conflicts and fix it up later, or be able to \n> collaboratively resolve conflicts without having everyone have \n> access to the same checkout. \n\nOne feature I would really like and maybe vanilla git can already \ndo this today and I just don't know how, but just becoming more \naware of conflicts, of when there's a conflict in the commit.\n \n> git status would probably need some special warnings or notices, \n> git checkout would probably benefit from additional \n> warnings/notices checks for those cases, git log should probably \n> display conflicted commits differently\n\nThat's exactly what I dream of! I wouldn't wanna commit conflicts \ndeliberately, just that I'm paranoid that I might have some failed \nmerges and three way diffs in code that I missed when they flashed \nby on the screen.\n\n> it'd also be a lot of work\n\nThat is for sure. And don't get me wrong, it's not a feature I\npersonally really need or am clamoring for. Thank you so much for the\nthoughtful explanation.\n"},{"id":"484525","messageId":"86e6b392-5a61-4864-89b0-42023e1804a6@gmail.com","threadId":"60481","inReplyTo":"Gr..Y5kkszDx87g@idiomdrottning.org","subject":"Re: first-class conflicts?","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-07T11:23:18Z","receivedAt":"2023-11-07T11:23:24Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Sandra\n\nOn 06/11/2023 22:45, Sandra Snan wrote:\n> Randall, thank you for that.\n> \n> I did mean of the first type, pure content conflicts (just like the \n> examples on that jj page).\n> \n> I just have sometimes wish git could be a little more aware of them \n> beyond just storing them with ASCII art in the files themselves (and \n> alerting / warning when they happen but I often can't properly see those \n> warnings flash by so I end up having to search for the conflict markers \n> manually). So if conflicts are a thing that *can* happen, it'd be better \n> if vc could know about them which would make some of the rebases simpler \n> as in jj. That doesn't mean we wanna adopt the jj workflow of \n> deliberately checking in conflicts (not even locally), just be able to \n> deal with them better if it does happen.\n> \n> I dunno… and I've really appreciated the naysayers so far, helps me sort \n> out my thoughts in this. I personally really prefer the vanilla \n> \"explicit staging\" workflow (with magit) over jj, got, gitless etc. I'm \n> more scared of overcommitting by mistake than undercommitting. But this \n> one feature seemed to me that it might be really good: just having the \n> vc be aware of the conflicts it has created.\n\nIf you run \"git status\" it will list the files that have conflicts as \n\"unmerged\". To prevent \"git commit\" from creating a commit that contains \nconflict markers you can use a pre-commit hook that runs \"git diff \n--cached--check\". The sample hook that is created by default does this, \nto activate it run\n\n\tmv .git/hooks/pre-commit.sample .git/hooks/pre-commit\n\nin the main worktree. You can also run \"git config commit.verbose true\" \nto make \"git commit\" show the diff of the changes that will be committed \nbelow the commit message when you're editing the message.\n\nBest Wishes\n\nPhillip\n"},{"id":"484526","messageId":"Gr..DPt0IB-WHFM@idiomdrottning.org","threadId":"60481","inReplyTo":"86e6b392-5a61-4864-89b0-42023e1804a6@gmail.com","subject":"Re: RE: first-class conflicts?","fromName":"Sandra Snan","fromEmail":"sandra.snan@idiomdrottning.org","sentAt":"2023-11-07T11:24:40Z","receivedAt":"2023-11-07T11:24:43Z","isPatch":false,"sender":{"key":"sandra.snan@idiomdrottning.org","avatar":"https://gravatar.com/avatar/9f3cf671ef175db9ce2f833436f4f63b58f54651b1208ef07e63ee7443e86e82?d=mp&s=160"},"body":"That is wonderful! Thank you so much, Phillip! 👍🏻\n\n"},{"id":"484528","messageId":"ba047d38-4ad1-4440-8342-3379404f430b@gmail.com","threadId":"60481","inReplyTo":"CABPp-BH7WBm1j-Ue9oZFjoy6sTcw5B0hz_ndDEtJqvpZF4YF=w@mail.gmail.com","subject":"Re: first-class conflicts?","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-07T11:49:23Z","receivedAt":"2023-11-07T11:49:28Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Elijah\n\n[I've cc'd Martin to see if he has anything to add about how \"jj\" \nmanages the issues around storing conflicts.]\n\nOn 07/11/2023 08:16, Elijah Newren wrote:\n> On Mon, Nov 6, 2023 at 1:26 PM Sandra Snan\n> <sandra.snan@idiomdrottning.org> wrote:\n>>\n>> Is this feature from jj also a good idea for git?\n>> https://martinvonz.github.io/jj/v0.11.0/conflicts/\n> \n> Martin talked about this and other features at Git Merge 2022, a\n> little over a year ago.  I talked to him in more depth about these\n> while there.  I personally think he has some really interesting\n> features here, though at the time, I thought that the additional\n> object type might be too much to ask for in a Git change, and it was\n> an intrinsic part of the implementation back then.\n> \n> Martin also gave us an update at the 2023 Git Contributors summit, and\n> in particular noted a significant implementation change to not have\n> per-file storage of conflicts, but rather storing at the commit level\n> the multiple conflicting trees involved.  That model might be\n> something we could implement in Git.  And if we did, it'd solve\n> various issues such as people wanting to be able to stash conflicts,\n> or wanting to be able to partially resolve conflicts and fix it up\n> later, or be able to collaboratively resolve conflicts without having\n> everyone have access to the same checkout.\n\nOne thing to think about if we ever want to implement this is what other \ndata we need to store along with the conflict trees to preserve the \ncontext in which the conflict was created. For example the files that \nare read by \"git commit\" when it commits a conflict resolution. For a \nsingle cherry-pick/revert it would probably be fairly straight forward \nto store CHERRY_PICK_HEAD/REVERT_HEAD and add it as a parent so it gets \ntransferred along with the conflicts. For a sequence of cherry-picks or \na rebase it is more complicated to preserve the context of the conflict. \nEven \"git merge\" can create several files in addition to MERGE_HEAD \nwhich are read when the conflict resolution is committed.\n\n> But we'd also have to be careful and think through usecases, including\n> in the surrounding community.  People would probably want to ensure\n> that e.g. \"Protected\" or \"Integration\" branches don't get accept\n> fetches or pushes of conflicted commits,\n\nI think this is a really important point, while it can be useful to \nshare conflicts so they can be collaboratively resolved we don't want to \npropagate them into \"stable\" or production branches. I wonder how 'jj' \nhandles this.\n\n> git status would probably\n> need some special warnings or notices, git checkout would probably\n> benefit from additional warnings/notices checks for those cases, git\n> log should probably display conflicted commits differently, we'd need\n> to add special handling for higher order conflicts (e.g. a merge with\n> conflicts is itself involved in a merge) probably similar to what jj\n> has done, and audit a lot of other code paths to see what would be\n> needed.\n\nAs you point out there is a lot more to this than just being able to \nstore the conflict data in a commit - in many ways I think that is the \neasiest part of the solution to sharing conflicts.\n\nBest Wishes\n\nPhillip\n\n"},{"id":"484534","messageId":"CAESOdVDmQ85-des6Au-LH0fkUB9BZBZho0r-5=8MkPLJVA5WQQ@mail.gmail.com","threadId":"60481","inReplyTo":"ba047d38-4ad1-4440-8342-3379404f430b@gmail.com","subject":"Re: first-class conflicts?","fromName":"Martin von Zweigbergk","fromEmail":"martinvonz@google.com","sentAt":"2023-11-07T17:38:19Z","receivedAt":"2023-11-07T17:38:31Z","isPatch":false,"sender":{"key":"martinvonz@google.com","avatar":"https://avatars.githubusercontent.com/u/891642?v=4"},"body":"(new attempt in plain text)\n\nOn Tue, Nov 7, 2023 at 3:49 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Elijah\n>\n> [I've cc'd Martin to see if he has anything to add about how \"jj\"\n> manages the issues around storing conflicts.]\n>\n> On 07/11/2023 08:16, Elijah Newren wrote:\n> > On Mon, Nov 6, 2023 at 1:26 PM Sandra Snan\n> > <sandra.snan@idiomdrottning.org> wrote:\n> >>\n> >> Is this feature from jj also a good idea for git?\n> >> https://martinvonz.github.io/jj/v0.11.0/conflicts/\n> >\n> > Martin talked about this and other features at Git Merge 2022, a\n> > little over a year ago.  I talked to him in more depth about these\n> > while there.  I personally think he has some really interesting\n> > features here, though at the time, I thought that the additional\n> > object type might be too much to ask for in a Git change, and it was\n> > an intrinsic part of the implementation back then.\n> >\n> > Martin also gave us an update at the 2023 Git Contributors summit, and\n> > in particular noted a significant implementation change to not have\n> > per-file storage of conflicts, but rather storing at the commit level\n> > the multiple conflicting trees involved.  That model might be\n> > something we could implement in Git.  And if we did, it'd solve\n> > various issues such as people wanting to be able to stash conflicts,\n> > or wanting to be able to partially resolve conflicts and fix it up\n> > later, or be able to collaboratively resolve conflicts without having\n> > everyone have access to the same checkout.\n>\n> One thing to think about if we ever want to implement this is what other\n> data we need to store along with the conflict trees to preserve the\n> context in which the conflict was created. For example the files that\n> are read by \"git commit\" when it commits a conflict resolution. For a\n> single cherry-pick/revert it would probably be fairly straight forward\n> to store CHERRY_PICK_HEAD/REVERT_HEAD and add it as a parent so it gets\n> transferred along with the conflicts. For a sequence of cherry-picks or\n> a rebase it is more complicated to preserve the context of the conflict.\n> Even \"git merge\" can create several files in addition to MERGE_HEAD\n> which are read when the conflict resolution is committed.\n\nGood point. We actually don't store any extra data in jj. The old\nper-path conflict model was prepared for having some label associated\nwith each term of the conflict but we never actually used it.\n\nIf we add such metadata, it would probably have to be something that\nmakes sense even after pushing the conflict to another repo, so it\nprobably shouldn't be commit ids, unless we made sure to also push\nthose commits. Also note that if you `jj restore --from <commit with\nconflict>`, you can get a conflict into a commit that didn't have\nconflicts previously. Or if you already had conflicts in the\ndestination commit, your root trees (the multiple root trees\nconstituting the conflict) will now have conflicts that potentially\nwere created by two completely unrelated operations, so you would kind\nof need different labels for different paths.\n\nhttps://github.com/martinvonz/jj/issues/1176 has some more discussion\nabout this.\n\n> > But we'd also have to be careful and think through usecases, including\n> > in the surrounding community.  People would probably want to ensure\n> > that e.g. \"Protected\" or \"Integration\" branches don't get accept\n> > fetches or pushes of conflicted commits,\n>\n> I think this is a really important point, while it can be useful to\n> share conflicts so they can be collaboratively resolved we don't want to\n> propagate them into \"stable\" or production branches. I wonder how 'jj'\n> handles this.\n\nAgreed. `jj git push` refuses to push commits with conflicts, because\nit's very unlikely that the remote will be able to make any sense of\nit. Our commit backend at Google does support conflicts, so users can\ncheck out each other's conflicted commits there (except that we\nhaven't even started dogfooding yet).\n\n> > git status would probably\n> > need some special warnings or notices, git checkout would probably\n> > benefit from additional warnings/notices checks for those cases, git\n> > log should probably display conflicted commits differently, we'd need\n> > to add special handling for higher order conflicts (e.g. a merge with\n> > conflicts is itself involved in a merge) probably similar to what jj\n> > has done, and audit a lot of other code paths to see what would be\n> > needed.\n>\n> As you point out there is a lot more to this than just being able to\n> store the conflict data in a commit - in many ways I think that is the\n> easiest part of the solution to sharing conflicts.\n\nYes, I think it would be a very large project. Unlike jj, Git of\ncourse has to worry about backwards compatibility. For example, you\nwould have to decide if your goal - even in the long term - is to make\n`git rebase` etc. not get interrupted due to conflicts.\n"},{"id":"484559","messageId":"CABPp-BGd-W8T7EsvKYyjdi3=mfSTJ8zM-uzVsFnh1AWyV2wEzQ@mail.gmail.com","threadId":"60481","inReplyTo":"ba047d38-4ad1-4440-8342-3379404f430b@gmail.com","subject":"Re: first-class conflicts?","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2023-11-08T06:31:37Z","receivedAt":"2023-11-08T06:31:54Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Phillip,\n\nOn Tue, Nov 7, 2023 at 3:49 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Elijah\n>\n> [I've cc'd Martin to see if he has anything to add about how \"jj\"\n> manages the issues around storing conflicts.]\n\n+1.  I'll add some other questions for him too while we're at it,\nseparately in this thread.\n\n[...]\n\n> > Martin also gave us an update at the 2023 Git Contributors summit, and\n> > in particular noted a significant implementation change to not have\n> > per-file storage of conflicts, but rather storing at the commit level\n> > the multiple conflicting trees involved.  That model might be\n> > something we could implement in Git.  And if we did, it'd solve\n> > various issues such as people wanting to be able to stash conflicts,\n> > or wanting to be able to partially resolve conflicts and fix it up\n> > later, or be able to collaboratively resolve conflicts without having\n> > everyone have access to the same checkout.\n>\n> One thing to think about if we ever want to implement this is what other\n> data we need to store along with the conflict trees to preserve the\n> context in which the conflict was created. For example the files that\n> are read by \"git commit\" when it commits a conflict resolution. For a\n> single cherry-pick/revert it would probably be fairly straight forward\n> to store CHERRY_PICK_HEAD/REVERT_HEAD and add it as a parent so it gets\n> transferred along with the conflicts.\n\nThis is a great thing to think about and bring up.  However, I'm not\nsure what part of it actually needs to be preserved; in fact, it's not\nclear to me that any of it needs preserving -- especially not the\nfiles read by \"git commit\".  A commit was already created, after all.\n\nIt seems that CHERRY_PICK_HEAD/REVERT_HEAD files exist primarily to\nclue in that we are in-the-middle-of-<op>, and the conflict header\n(the \"tree A + tree B - tree C\" thing; whatever that's called)\nsimilarly provides signal that the commit still has conflicts.\nSecondarily, these files contain information about the tree we came\nfrom and its parent tree, which allows users to investigate the diff\nbetween those...but that information is also available from the\nconflict header in the recorded commit.  The CHERRY_PICK_HEAD and\nREVERT_HEAD files could also be used to access the commit message, but\nthat would have been stored in the conflicted commit as well.  Are\nthere any other pieces of information I'm missing?\n\n> For a sequence of cherry-picks or\n> a rebase it is more complicated to preserve the context of the conflict.\n\nI think the big piece here is whether we also want to adopt jj's\nbehavior of automatically rebasing all descendant commits when\nchecking out and amending some historical commit (or at least having\nthe option of doing so).  That behavior allows users to amend commits\nto resolve conflicts without figuring out complicated interactive\nrebases to fix all the descendant commits across all relevant\nbranches.  Without that feature, I agree this might be a bit more\ndifficult, but with that feature, I'm having a hard time figuring out\nwhat context we actually need to preserve for a sequence of\ncherry-picks or a rebase.\n\nDigging into a few briefly...\n\nMany of the state files are about the status of the in-progress\noperation (todo-list, numbers of commits done and to do, what should\nbe done with not-yet-handled commits, temporary refs corresponding to\ntemporary labels that need to be deleted, rescheduling failed execs,\ndropping or keeping redundant commits, etc.), but if the operation has\ncompleted and new commits created (potentially with multiple files\nwith conflict headers), I don't see how this information is useful\nanymore.\n\nThere are some special state files related to half-completed\noperations (e.g. squash commits when we haven't yet reached the final\none in the sequence, a file to note that we want to edit a commit\nmessage once the user has finished resolving conflicts, whether we\nneed to create a new root commit), but again, the operation has\ncompleted and commits have been created with appropriate parentage and\ncommit messages so I don't think these are useful anymore either.\n\nOther state files are related to things needing to be done at the end\nof the operation, like invoke the post-rewrite hook or pop the\nautostash (with knowledge of what was rewritten to what).  But the\noperation would have been completed and those things done already, so\nI don't see how this is necessary either.\n\nSome state files are for controlling how commits are created (setting\ncommitter date to author date, gpg signing options, whether to add\nsignoff), but, again, commits have already been created, and can be\nfurther amended as the user wants (hopefully including resolving the\nconflicts).\n\nThe biggest issue is perhaps that REBASE_HEAD is used in the\nimplementation of `git rebase --show-current-patch`, but all\ninformation stored in that is still accessible -- the commit message\nis stored in the commit, the author time is stored in the commit, and\nthe trees involved are in the conflict header.  The only thing missing\nis committer timestamp, which isn't relevant anyway.\n\nThe only ones I'm pausing a bit on are the strategy and\nstrategy-options.  Those might be useful somehow...but I can't\ncurrently quite put my finger on explaining how they would be useful\nand I'm not sure they are.\n\nAm I missing anything?\n\n> Even \"git merge\" can create several files in addition to MERGE_HEAD\n> which are read when the conflict resolution is committed.\n\nThat's a good one to bring up too, but I'm not sure I understand how\nthese could be useful to preserve either.  Am I missing something?  My\nbreakdown:\n   * MERGE_HEAD: was recorded in the commit as a second parent, so we\nalready have that info\n   * MERGE_MSG: was recorded in the commit as the commit message, so\nagain we already have that info\n   * MERGE_AUTOSTASH: irrelevant since the stashed stuff isn't part of\nthe commit and was in fact unstashed after the\nmerge-commit-with-conflicts was created\n   * MERGE_MODE: irrelevant since it's only used for reducing heads at\ntime of git-commit, and git-commit has already been run\n   * MERGE_RR: I think this is irrelevant; the conflict record (tree A\n+ tree B - tree C) lets us redo the merge if needed to get the list of\nconflicted files and textual conflicts found therein\n\nSo I don't see how any of the information in these files need to be\nrecorded as additional auxiliary information.  However, that last item\nmight depend upon the strategy and strategy-options, which currently\nis not recorded...hmm....\n\n> > But we'd also have to be careful and think through usecases, including\n> > in the surrounding community.  People would probably want to ensure\n> > that e.g. \"Protected\" or \"Integration\" branches don't get accept\n> > fetches or pushes of conflicted commits,\n>\n> I think this is a really important point, while it can be useful to\n> share conflicts so they can be collaboratively resolved we don't want to\n> propagate them into \"stable\" or production branches. I wonder how 'jj'\n> handles this.\n\nYeah, figuring this out might be the biggest sticking point.\n\n> > git status would probably\n> > need some special warnings or notices, git checkout would probably\n> > benefit from additional warnings/notices checks for those cases, git\n> > log should probably display conflicted commits differently, we'd need\n> > to add special handling for higher order conflicts (e.g. a merge with\n> > conflicts is itself involved in a merge) probably similar to what jj\n> > has done, and audit a lot of other code paths to see what would be\n> > needed.\n>\n> As you point out there is a lot more to this than just being able to\n> store the conflict data in a commit - in many ways I think that is the\n> easiest part of the solution to sharing conflicts.\n\nYeah, another one I just thought of is that the trees referenced in\nthe conflicts would also need to affect reachability computations as\nwell, to make sure they both don't get gc'ed and that they are\ntransferred when appropriate.  There are lots of things that would be\ninvolved in implementing this idea.\n"},{"id":"484566","messageId":"CABPp-BEcqSJ79b9WLm+KgKkcPwSwTv3o13meU_aXakQhV6iKDQ@mail.gmail.com","threadId":"60481","inReplyTo":"CAESOdVDmQ85-des6Au-LH0fkUB9BZBZho0r-5=8MkPLJVA5WQQ@mail.gmail.com","subject":"Re: first-class conflicts?","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2023-11-08T07:31:00Z","receivedAt":"2023-11-08T07:31:25Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Martin,\n\nOn Tue, Nov 7, 2023 at 9:38 AM Martin von Zweigbergk\n<martinvonz@google.com> wrote:\n>\n[...]\n> > One thing to think about if we ever want to implement this is what other\n> > data we need to store along with the conflict trees to preserve the\n> > context in which the conflict was created. For example the files that\n> > are read by \"git commit\" when it commits a conflict resolution. For a\n> > single cherry-pick/revert it would probably be fairly straight forward\n> > to store CHERRY_PICK_HEAD/REVERT_HEAD and add it as a parent so it gets\n> > transferred along with the conflicts. For a sequence of cherry-picks or\n> > a rebase it is more complicated to preserve the context of the conflict.\n> > Even \"git merge\" can create several files in addition to MERGE_HEAD\n> > which are read when the conflict resolution is committed.\n>\n> Good point. We actually don't store any extra data in jj. The old\n> per-path conflict model was prepared for having some label associated\n> with each term of the conflict but we never actually used it.\n>\n> If we add such metadata, it would probably have to be something that\n> makes sense even after pushing the conflict to another repo, so it\n> probably shouldn't be commit ids, unless we made sure to also push\n> those commits. Also note that if you `jj restore --from <commit with\n> conflict>`, you can get a conflict into a commit that didn't have\n> conflicts previously. Or if you already had conflicts in the\n> destination commit, your root trees (the multiple root trees\n> constituting the conflict) will now have conflicts that potentially\n> were created by two completely unrelated operations, so you would kind\n> of need different labels for different paths.\n>\n> https://github.com/martinvonz/jj/issues/1176 has some more discussion\n> about this.\n\nInteresting link; thanks for sharing.\n\nI am curious more about the data you do store.  My fuzzy memory is\nthat you store a commit header involving something of the form \"A + B\n- C\", where those are all commit IDs.  Is that correct?  Is this in\naddition to a normal \"tree\" header as in Git, or are one of A or B\nfound in the tree header?  I think you said there was also the\npossibility for more than three terms.  Are those for when a\nconflicted commit is merged with another branch that adds more\nconflicts, or are there other cases too?  (Octopus merges?)\n\nWhat about recursive merges, i.e. merges where the two sides do not\nhave a unique merge base.  What is the form of those?  (Would \"- C\" be\nreplaced by \"- C1 - C2 - ... - Cn\"?  Or would we create the virtual\nmerge base V and then do a \" - V\"?  Or do we only have \"A + B\"?)\n\nYou previously mentioned that if someone goes to edit a commit with\nconflicts, and resolves the conflicts in just one file, then you can\nmodify each of the trees A, B, and C such that a merging of those\ntrees gives the partially resolved result.  How does one do that with\nspecial conflicts, such as:\n   * User modifies file D on both sides of history, in conflicting\nways, and also renames D -> E on one side of history.  User checks out\nthis conflicted commit and fixes the conflicts in E (but not other\nfiles) and does a \"git add E\".  When they go to commit, does the\nmachinery need a mapping to figure out that it needs to adjust \"D\" in\ntwo of the trees while adjusting \"E\" in the other?\n   * Similar to the above, but the side that doesn't rename D renames\nolddir/ -> newdir/, and the side that renames D instead renames\nD->olddir/E.  For this case, the file will end up at newdir/E; do we\nneed the backward mapping from newdir/E to both olddir/E and D?\n   * Slightly different than the above: User renames D -> E on one\nside of history, and D -> F on the other.  That's a rename/rename\n(1to2) conflict.  User checks out this conflicted commit and does a\n\"git add F\", marking it as okay, but leaving E conflicted.  How can\none adjust the tree such that no conflict for F appears, but one still\nappears for E?\n   * Similar to above with an extra wrinkle: User renames D -> E on\none side of history, and on the other side both renames D -> F and\nadds a slightly different file named E.  That's both a rename/rename\n(1to2) conflict for E & F, and an add/add conflict for E.  Users\nchecks out this conflicted commit and resolves textual conflict in E\n(in favor of the \"other side\"), and does a \"git add E\", marking it as\nresolved.  When they go to commit, we not only need to worry about\nmaking sure a conflict for F appears, we also need to figure out how\nto adjust the tree such that the merge result gives you the expected\nvalue in E without affecting F.  How can that be done?\n\nOn the first two bullet points, there's no such thing as a reverse\nmapping from conflicted files to original files from previous commits\nin current Git.  Creating one, if possible, would be a fair amount of\nwork.  But, I'm not so sure it's even possible, due to the fact that\nconflicts and files do not always have one-to-one (or even one-to-many\nor many-to-one) relationships; many-to-many relationship can exist, as\nI've started alluding to in the last two bullet points (see also\nhttps://github.com/git/git/blob/98009afd24e2304bf923a64750340423473809ff/Documentation/git-merge-tree.txt#L266-L271).\nIn fact, they can get even more complicated (e.g.\nhttps://github.com/git/git/blob/master/t/t6422-merge-rename-corner-cases.sh#L1017-L1022).\n\n> > > But we'd also have to be careful and think through usecases, including\n> > > in the surrounding community.  People would probably want to ensure\n> > > that e.g. \"Protected\" or \"Integration\" branches don't get accept\n> > > fetches or pushes of conflicted commits,\n> >\n> > I think this is a really important point, while it can be useful to\n> > share conflicts so they can be collaboratively resolved we don't want to\n> > propagate them into \"stable\" or production branches. I wonder how 'jj'\n> > handles this.\n>\n> Agreed. `jj git push` refuses to push commits with conflicts, because\n> it's very unlikely that the remote will be able to make any sense of\n> it. Our commit backend at Google does support conflicts, so users can\n> check out each other's conflicted commits there (except that we\n> haven't even started dogfooding yet).\n\nI'm curious to hear what happens when you do start dogfooding, on\nprojects with many developers and which are jj-only.  Do commits with\nconflicts accidentally end up in mainline branches, or are there good\nways to make sure they don't hit anything considered stable?\n\n> > > git status would probably\n> > > need some special warnings or notices, git checkout would probably\n> > > benefit from additional warnings/notices checks for those cases, git\n> > > log should probably display conflicted commits differently, we'd need\n> > > to add special handling for higher order conflicts (e.g. a merge with\n> > > conflicts is itself involved in a merge) probably similar to what jj\n> > > has done, and audit a lot of other code paths to see what would be\n> > > needed.\n> >\n> > As you point out there is a lot more to this than just being able to\n> > store the conflict data in a commit - in many ways I think that is the\n> > easiest part of the solution to sharing conflicts.\n>\n> Yes, I think it would be a very large project. Unlike jj, Git of\n> course has to worry about backwards compatibility. For example, you\n> would have to decide if your goal - even in the long term - is to make\n> `git rebase` etc. not get interrupted due to conflicts.\n\n...and whether to copy jj's other feature in this area in some form:\nauto-rebasing any descendants when you checkout and amend an old\ncommit (e.g. to resolve conflicts).  :-)\n"},{"id":"484591","messageId":"CAESOdVBjEYAp+P_mYdByYrPmbiu9DWL=Z_r19H8D9bxkJrquFA@mail.gmail.com","threadId":"60481","inReplyTo":"CABPp-BEcqSJ79b9WLm+KgKkcPwSwTv3o13meU_aXakQhV6iKDQ@mail.gmail.com","subject":"Re: first-class conflicts?","fromName":"Martin von Zweigbergk","fromEmail":"martinvonz@google.com","sentAt":"2023-11-08T18:22:58Z","receivedAt":"2023-11-08T18:23:11Z","isPatch":false,"sender":{"key":"martinvonz@google.com","avatar":"https://avatars.githubusercontent.com/u/891642?v=4"},"body":"Hi Elijah,\n\n\nOn Tue, Nov 7, 2023 at 11:31 PM Elijah Newren <newren@gmail.com> wrote:\n>\n> Hi Martin,\n>\n> On Tue, Nov 7, 2023 at 9:38 AM Martin von Zweigbergk\n> <martinvonz@google.com> wrote:\n> >\n> [...]\n> > > One thing to think about if we ever want to implement this is what other\n> > > data we need to store along with the conflict trees to preserve the\n> > > context in which the conflict was created. For example the files that\n> > > are read by \"git commit\" when it commits a conflict resolution. For a\n> > > single cherry-pick/revert it would probably be fairly straight forward\n> > > to store CHERRY_PICK_HEAD/REVERT_HEAD and add it as a parent so it gets\n> > > transferred along with the conflicts. For a sequence of cherry-picks or\n> > > a rebase it is more complicated to preserve the context of the conflict.\n> > > Even \"git merge\" can create several files in addition to MERGE_HEAD\n> > > which are read when the conflict resolution is committed.\n> >\n> > Good point. We actually don't store any extra data in jj. The old\n> > per-path conflict model was prepared for having some label associated\n> > with each term of the conflict but we never actually used it.\n> >\n> > If we add such metadata, it would probably have to be something that\n> > makes sense even after pushing the conflict to another repo, so it\n> > probably shouldn't be commit ids, unless we made sure to also push\n> > those commits. Also note that if you `jj restore --from <commit with\n> > conflict>`, you can get a conflict into a commit that didn't have\n> > conflicts previously. Or if you already had conflicts in the\n> > destination commit, your root trees (the multiple root trees\n> > constituting the conflict) will now have conflicts that potentially\n> > were created by two completely unrelated operations, so you would kind\n> > of need different labels for different paths.\n> >\n> > https://github.com/martinvonz/jj/issues/1176 has some more discussion\n> > about this.\n>\n> Interesting link; thanks for sharing.\n>\n> I am curious more about the data you do store.  My fuzzy memory is\n> that you store a commit header involving something of the form \"A + B\n> - C\", where those are all commit IDs.  Is that correct?\n\nWe actually store it outside the Git repo (together with the \"change\nid\"). We have avoided using commit headers because I wasn't sure how\nwell different tools deal with unexpected commit headers, and because\nI wanted commits to be indistinguishable from commits created by a\nregular Git binary. The latter argument doesn't apply to commits with\nconflicts since those are clearly not from a regular Git binary\nanyway, and we don't allow pushing them to a remote.\n\n>  Is this in\n> addition to a normal \"tree\" header as in Git, or are one of A or B\n> found in the tree header?\n\nIt's in addition. For the tree, we actually write a tree object with\nthree subtrees:\n\n.jjconflict-base-0: C\n.jjconflict-side-0: A\n.jjconflict-side-1: B\n\nThe tree is not authoritative - we use the Git-external storage for\nthat. The reason we write the trees is mostly to prevent them from\ngetting GC'd. Also, if a user does `git checkout <conflicted commit>`,\nthey'll see those subdirectories and will hopefully be reminded that\nthey did something odd (perhaps we should drop the leading `.` so `ls`\nwill show them...). They can also diff the directories in a diff tool\nif they like.\n\n>  I think you said there was also the\n> possibility for more than three terms.  Are those for when a\n> conflicted commit is merged with another branch that adds more\n> conflicts, or are there other cases too?  (Octopus merges?)\n\nYes, they can happen in both of those cases you mention. More\ngenerally, whenever you apply a diff between two trees onto another\ntree, you might end up with a higher-arity conflict. So merging in\nanother branch can do that, or doing an octopus merge (which is the\nsame thing at the tree level, just different at the commit level), or\nrebasing or reverting a commit.\n\nWe simplify conflicts algebraically, so rebasing a commit multiple\ntimes does not increase the arity - the intermediate parents were both\nadded and removed and thus cancel out. These simple algorithms for\nsimplifying conflicts are encapsulated in\nhttps://github.com/martinvonz/jj/blob/main/lib/src/merge.rs. Most of\nthem are independent of the type of values being merged; they can be\nused for doing algebra on tree ids, content hunks, refs, etc. (in the\ntest cases, we mostly merge integers because integer literals are\ncompact).\n\n> What about recursive merges, i.e. merges where the two sides do not\n> have a unique merge base.  What is the form of those?  (Would \"- C\" be\n> replaced by \"- C1 - C2 - ... - Cn\"?  Or would we create the virtual\n> merge base V and then do a \" - V\"?  Or do we only have \"A + B\"?)\n\nWe do that by recursively creating a virtual tree just like Git does,\nI think (https://github.com/martinvonz/jj/blob/084b99e1e2c42c40f2d52038cdc97687b76fed89/lib/src/rewrite.rs#L56-L71).\nI think the main difference is that by modeling conflicts, we can\navoid recursive conflict markers (if that's what Git does), and we can\neven automatically resolve some cases where the virtual tree has a\nconflict.\n\n> You previously mentioned that if someone goes to edit a commit with\n> conflicts, and resolves the conflicts in just one file, then you can\n> modify each of the trees A, B, and C such that a merging of those\n> trees gives the partially resolved result.  How does one do that with\n> special conflicts, such as:\n>    * User modifies file D on both sides of history, in conflicting\n> ways, and also renames D -> E on one side of history.  User checks out\n> this conflicted commit and fixes the conflicts in E (but not other\n> files) and does a \"git add E\".  When they go to commit, does the\n> machinery need a mapping to figure out that it needs to adjust \"D\" in\n> two of the trees while adjusting \"E\" in the other?\n>    * Similar to the above, but the side that doesn't rename D renames\n> olddir/ -> newdir/, and the side that renames D instead renames\n> D->olddir/E.  For this case, the file will end up at newdir/E; do we\n> need the backward mapping from newdir/E to both olddir/E and D?\n>    * Slightly different than the above: User renames D -> E on one\n> side of history, and D -> F on the other.  That's a rename/rename\n> (1to2) conflict.  User checks out this conflicted commit and does a\n> \"git add F\", marking it as okay, but leaving E conflicted.  How can\n> one adjust the tree such that no conflict for F appears, but one still\n> appears for E?\n>    * Similar to above with an extra wrinkle: User renames D -> E on\n> one side of history, and on the other side both renames D -> F and\n> adds a slightly different file named E.  That's both a rename/rename\n> (1to2) conflict for E & F, and an add/add conflict for E.  Users\n> checks out this conflicted commit and resolves textual conflict in E\n> (in favor of the \"other side\"), and does a \"git add E\", marking it as\n> resolved.  When they go to commit, we not only need to worry about\n> making sure a conflict for F appears, we also need to figure out how\n> to adjust the tree such that the merge result gives you the expected\n> value in E without affecting F.  How can that be done?\n>\n> On the first two bullet points, there's no such thing as a reverse\n> mapping from conflicted files to original files from previous commits\n> in current Git.  Creating one, if possible, would be a fair amount of\n> work.  But, I'm not so sure it's even possible, due to the fact that\n> conflicts and files do not always have one-to-one (or even one-to-many\n> or many-to-one) relationships; many-to-many relationship can exist, as\n> I've started alluding to in the last two bullet points (see also\n> https://github.com/git/git/blob/98009afd24e2304bf923a64750340423473809ff/Documentation/git-merge-tree.txt#L266-L271).\n> In fact, they can get even more complicated (e.g.\n> https://github.com/git/git/blob/master/t/t6422-merge-rename-corner-cases.sh#L1017-L1022).\n\nGreat questions! We don't have support for renames, so we haven't had\nto worry about these things. We have talked a little about divergent\nrenames and the need for recording that in the commit so we can tell\nthe user about it and maybe ask them which name they want to keep. I\nhad not considered the interaction with partial conflict resolution,\nso thanks for bringing that up. I don't have any answers now, but\nwe'll probably need to start thinking about this soon.\n\n> > > > But we'd also have to be careful and think through usecases, including\n> > > > in the surrounding community.  People would probably want to ensure\n> > > > that e.g. \"Protected\" or \"Integration\" branches don't get accept\n> > > > fetches or pushes of conflicted commits,\n> > >\n> > > I think this is a really important point, while it can be useful to\n> > > share conflicts so they can be collaboratively resolved we don't want to\n> > > propagate them into \"stable\" or production branches. I wonder how 'jj'\n> > > handles this.\n> >\n> > Agreed. `jj git push` refuses to push commits with conflicts, because\n> > it's very unlikely that the remote will be able to make any sense of\n> > it. Our commit backend at Google does support conflicts, so users can\n> > check out each other's conflicted commits there (except that we\n> > haven't even started dogfooding yet).\n>\n> I'm curious to hear what happens when you do start dogfooding, on\n> projects with many developers and which are jj-only.  Do commits with\n> conflicts accidentally end up in mainline branches, or are there good\n> ways to make sure they don't hit anything considered stable?\n\nThat won't happen at Google because our source of truth for \"merged\nPRs\" (in GitHub-speak) is in our existing VCS. We will necessarily\nhave to translate from jj's data model to its data model before a\ncommit can even be sent for review.\n\n>\n> > > > git status would probably\n> > > > need some special warnings or notices, git checkout would probably\n> > > > benefit from additional warnings/notices checks for those cases, git\n> > > > log should probably display conflicted commits differently, we'd need\n> > > > to add special handling for higher order conflicts (e.g. a merge with\n> > > > conflicts is itself involved in a merge) probably similar to what jj\n> > > > has done, and audit a lot of other code paths to see what would be\n> > > > needed.\n> > >\n> > > As you point out there is a lot more to this than just being able to\n> > > store the conflict data in a commit - in many ways I think that is the\n> > > easiest part of the solution to sharing conflicts.\n> >\n> > Yes, I think it would be a very large project. Unlike jj, Git of\n> > course has to worry about backwards compatibility. For example, you\n> > would have to decide if your goal - even in the long term - is to make\n> > `git rebase` etc. not get interrupted due to conflicts.\n>\n> ...and whether to copy jj's other feature in this area in some form:\n> auto-rebasing any descendants when you checkout and amend an old\n> commit (e.g. to resolve conflicts).  :-)\n"},{"id":"484645","messageId":"a1cd2dba-3a74-4b41-8585-209b4a13b8c4@gmail.com","threadId":"60481","inReplyTo":"CABPp-BGd-W8T7EsvKYyjdi3=mfSTJ8zM-uzVsFnh1AWyV2wEzQ@mail.gmail.com","subject":"Re: first-class conflicts?","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-09T14:45:56Z","receivedAt":"2023-11-09T14:46:00Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Elijah\n\nOn 08/11/2023 06:31, Elijah Newren wrote:\n> Hi Phillip,\n> \n> On Tue, Nov 7, 2023 at 3:49 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>\n>> Hi Elijah\n>>\n>> [I've cc'd Martin to see if he has anything to add about how \"jj\"\n>> manages the issues around storing conflicts.]\n> \n> +1.  I'll add some other questions for him too while we're at it,\n> separately in this thread.\n> \n> [...]\n> \n>>> Martin also gave us an update at the 2023 Git Contributors summit, and\n>>> in particular noted a significant implementation change to not have\n>>> per-file storage of conflicts, but rather storing at the commit level\n>>> the multiple conflicting trees involved.  That model might be\n>>> something we could implement in Git.  And if we did, it'd solve\n>>> various issues such as people wanting to be able to stash conflicts,\n>>> or wanting to be able to partially resolve conflicts and fix it up\n>>> later, or be able to collaboratively resolve conflicts without having\n>>> everyone have access to the same checkout.\n>>\n>> One thing to think about if we ever want to implement this is what other\n>> data we need to store along with the conflict trees to preserve the\n>> context in which the conflict was created. For example the files that\n>> are read by \"git commit\" when it commits a conflict resolution. For a\n>> single cherry-pick/revert it would probably be fairly straight forward\n>> to store CHERRY_PICK_HEAD/REVERT_HEAD and add it as a parent so it gets\n>> transferred along with the conflicts.\n> \n> This is a great thing to think about and bring up.  However, I'm not\n> sure what part of it actually needs to be preserved; in fact, it's not\n> clear to me that any of it needs preserving -- especially not the\n> files read by \"git commit\".  A commit was already created, after all.\n> \n> It seems that CHERRY_PICK_HEAD/REVERT_HEAD files exist primarily to\n> clue in that we are in-the-middle-of-<op>, and the conflict header\n> (the \"tree A + tree B - tree C\" thing; whatever that's called)\n> similarly provides signal that the commit still has conflicts.\n> Secondarily, these files contain information about the tree we came\n> from and its parent tree, which allows users to investigate the diff\n> between those...but that information is also available from the\n> conflict header in the recorded commit.  The CHERRY_PICK_HEAD and\n> REVERT_HEAD files could also be used to access the commit message, but\n> that would have been stored in the conflicted commit as well.  Are\n> there any other pieces of information I'm missing?\n\nMainly that I'm an idiot and forgot we were actually creating a commit \nand can store the message and authorship there! More seriously I think \nbeing able to inspect the commit being cherry-picked (including the \noriginal commit message) is useful so we'd need to recreate something \nlike CHERRY_PICK_HEAD when the conflict commit is checked out. \nRecreating CHERRY_PICK_HEAD is useful for \"git status\" as well. I think \nthat means storing a little more that just the \"tree A + tree B - tree \nC\" thing.\n\n>> For a sequence of cherry-picks or\n>> a rebase it is more complicated to preserve the context of the conflict.\n> \n> I think the big piece here is whether we also want to adopt jj's\n> behavior of automatically rebasing all descendant commits when\n> checking out and amending some historical commit (or at least having\n> the option of doing so).  That behavior allows users to amend commits\n> to resolve conflicts without figuring out complicated interactive\n> rebases to fix all the descendant commits across all relevant\n> branches.\n\nThat's a potentially attractive option which is fairly simple to \nimplement locally as I think you can use the commit DAG to find all the \ndescendants though that could be expensive if there are lots of \nbranches. However, if we're going to share conflicts I think we'd need \nsomething like \"hg evolve\" - if I push a commit with conflicts and you \nbase some work on it and then I resolve the conflict and push again you \nwould want to your work to be rebased onto my conflict resolution. To \nhandle \"rebase --exec\" we could store the exec command and run it when \nthe  conflicts are resolved.\n\nAlso I wonder how annoying it would be in cases where I just want to \nrebase and resolve the conflicts now. At the moment \"git rebase\" stops \nat the conflict, with this feature I'd have to go and checkout the \nconflicted commit and fix the conflicts after the rebase had finished.\n\n> Without that feature, I agree this might be a bit more\n> difficult,\n\nYes, when I wrote my original message I was imagining that we'd stop at \nthe first conflicting pick and store all the rebase state like some kind \nof stash on steroids so it could be continued when the conflict was \nresolved. It would be much simpler to try and avoid that.\n\n> but with that feature, I'm having a hard time figuring out\n> what context we actually need to preserve for a sequence of\n> cherry-picks or a rebase.\n>  \n> Digging into a few briefly...\n> \n> Many of the state files are about the status of the in-progress\n> operation (todo-list, numbers of commits done and to do, what should\n> be done with not-yet-handled commits, temporary refs corresponding to\n> temporary labels that need to be deleted, rescheduling failed execs,\n> dropping or keeping redundant commits, etc.), but if the operation has\n> completed and new commits created (potentially with multiple files\n> with conflict headers), I don't see how this information is useful\n> anymore.\n\nAgreed\n\n> There are some special state files related to half-completed\n> operations (e.g. squash commits when we haven't yet reached the final\n> one in the sequence, a file to note that we want to edit a commit\n> message once the user has finished resolving conflicts, whether we\n> need to create a new root commit), but again, the operation has\n> completed and commits have been created with appropriate parentage and\n> commit messages so I don't think these are useful anymore either.\n\nYes, though we may want to remember which commits were squashed together \nso the user can inspect that when resolving conflicts.\n\n> Other state files are related to things needing to be done at the end\n> of the operation, like invoke the post-rewrite hook or pop the\n> autostash (with knowledge of what was rewritten to what).  But the\n> operation would have been completed and those things done already, so\n> I don't see how this is necessary either.\n\nAgreed\n\n> Some state files are for controlling how commits are created (setting\n> committer date to author date, gpg signing options, whether to add\n> signoff), but, again, commits have already been created, and can be\n> further amended as the user wants (hopefully including resolving the\n> conflicts).\n\nAgreed\n\n> The biggest issue is perhaps that REBASE_HEAD is used in the\n> implementation of `git rebase --show-current-patch`, but all\n> information stored in that is still accessible -- the commit message\n> is stored in the commit, the author time is stored in the commit, and\n> the trees involved are in the conflict header.  The only thing missing\n> is committer timestamp, which isn't relevant anyway.\n\nThe commit message may have been edited so we lose the original message \nbut I'm not sure how important that is.\n\n> The only ones I'm pausing a bit on are the strategy and\n> strategy-options.  Those might be useful somehow...but I can't\n> currently quite put my finger on explaining how they would be useful\n> and I'm not sure they are.\n\nI can't think of an immediate use for them. When we re-create conflicts \nwe do it per-file based on the index entries created by the original \nmerge so I don't think we need to know anything about the strategy or \nstrategy-options.\n\n> Am I missing anything?\n\nexec commands? If the user runs \"git rebase --exec\" and there are \nconflicts then we'd need to defer running the exec commands until the \nconflicts are resolved. For something like \"git rebase --exec 'make \ntest'\" that should be fine. I wonder if there are corner cases where the \nexec command changes HEAD though.\n\n>> Even \"git merge\" can create several files in addition to MERGE_HEAD\n>> which are read when the conflict resolution is committed.\n> \n> That's a good one to bring up too, but I'm not sure I understand how\n> these could be useful to preserve either.  Am I missing something?  My\n> breakdown:\n>     * MERGE_HEAD: was recorded in the commit as a second parent, so we\n> already have that info\n>     * MERGE_MSG: was recorded in the commit as the commit message, so\n> again we already have that info\n>     * MERGE_AUTOSTASH: irrelevant since the stashed stuff isn't part of\n> the commit and was in fact unstashed after the\n> merge-commit-with-conflicts was created\n>     * MERGE_MODE: irrelevant since it's only used for reducing heads at\n> time of git-commit, and git-commit has already been run\n>     * MERGE_RR: I think this is irrelevant; the conflict record (tree A\n> + tree B - tree C) lets us redo the merge if needed to get the list of\n> conflicted files and textual conflicts found therein\n> \n> So I don't see how any of the information in these files need to be\n> recorded as additional auxiliary information.  However, that last item\n> might depend upon the strategy and strategy-options, which currently\n> is not recorded...hmm....\n\nYes, as we're creating some kind of commit we don't need to preserve \nthose files separately.\n\n>>> But we'd also have to be careful and think through usecases, including\n>>> in the surrounding community.  People would probably want to ensure\n>>> that e.g. \"Protected\" or \"Integration\" branches don't get accept\n>>> fetches or pushes of conflicted commits,\n>>\n>> I think this is a really important point, while it can be useful to\n>> share conflicts so they can be collaboratively resolved we don't want to\n>> propagate them into \"stable\" or production branches. I wonder how 'jj'\n>> handles this.\n> \n> Yeah, figuring this out might be the biggest sticking point.\n\nIndeed\n\n>>> git status would probably\n>>> need some special warnings or notices, git checkout would probably\n>>> benefit from additional warnings/notices checks for those cases, git\n>>> log should probably display conflicted commits differently, we'd need\n>>> to add special handling for higher order conflicts (e.g. a merge with\n>>> conflicts is itself involved in a merge) probably similar to what jj\n>>> has done, and audit a lot of other code paths to see what would be\n>>> needed.\n>>\n>> As you point out there is a lot more to this than just being able to\n>> store the conflict data in a commit - in many ways I think that is the\n>> easiest part of the solution to sharing conflicts.\n> \n> Yeah, another one I just thought of is that the trees referenced in\n> the conflicts would also need to affect reachability computations as\n> well, to make sure they both don't get gc'ed and that they are\n> transferred when appropriate.  There are lots of things that would be\n> involved in implementing this idea.\n\nYes, it would certainly be lots of work.\n\nBest Wishes\n\nPhillip\n"},{"id":"484646","messageId":"08fd9919-badc-4d3a-8dc4-4813c4dec649@gmail.com","threadId":"60481","inReplyTo":"CAESOdVDmQ85-des6Au-LH0fkUB9BZBZho0r-5=8MkPLJVA5WQQ@mail.gmail.com","subject":"Re: first-class conflicts?","fromName":"","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-11-09T14:50:40Z","receivedAt":"2023-11-09T14:50:43Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Martin\n\nOn 07/11/2023 17:38, Martin von Zweigbergk wrote:\n> (new attempt in plain text)\n\nOh, the joys of the mailing list! Thanks for your comments below and in \nyour reply to Elijah, I found them really helpful to get a better \nunderstanding of how 'jj' handles this.\n\nBest Wishes\n\nPhillip\n\n> On Tue, Nov 7, 2023 at 3:49 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>\n>> Hi Elijah\n>>\n>> [I've cc'd Martin to see if he has anything to add about how \"jj\"\n>> manages the issues around storing conflicts.]\n>>\n>> On 07/11/2023 08:16, Elijah Newren wrote:\n>>> On Mon, Nov 6, 2023 at 1:26 PM Sandra Snan\n>>> <sandra.snan@idiomdrottning.org> wrote:\n>>>>\n>>>> Is this feature from jj also a good idea for git?\n>>>> https://martinvonz.github.io/jj/v0.11.0/conflicts/\n>>>\n>>> Martin talked about this and other features at Git Merge 2022, a\n>>> little over a year ago.  I talked to him in more depth about these\n>>> while there.  I personally think he has some really interesting\n>>> features here, though at the time, I thought that the additional\n>>> object type might be too much to ask for in a Git change, and it was\n>>> an intrinsic part of the implementation back then.\n>>>\n>>> Martin also gave us an update at the 2023 Git Contributors summit, and\n>>> in particular noted a significant implementation change to not have\n>>> per-file storage of conflicts, but rather storing at the commit level\n>>> the multiple conflicting trees involved.  That model might be\n>>> something we could implement in Git.  And if we did, it'd solve\n>>> various issues such as people wanting to be able to stash conflicts,\n>>> or wanting to be able to partially resolve conflicts and fix it up\n>>> later, or be able to collaboratively resolve conflicts without having\n>>> everyone have access to the same checkout.\n>>\n>> One thing to think about if we ever want to implement this is what other\n>> data we need to store along with the conflict trees to preserve the\n>> context in which the conflict was created. For example the files that\n>> are read by \"git commit\" when it commits a conflict resolution. For a\n>> single cherry-pick/revert it would probably be fairly straight forward\n>> to store CHERRY_PICK_HEAD/REVERT_HEAD and add it as a parent so it gets\n>> transferred along with the conflicts. For a sequence of cherry-picks or\n>> a rebase it is more complicated to preserve the context of the conflict.\n>> Even \"git merge\" can create several files in addition to MERGE_HEAD\n>> which are read when the conflict resolution is committed.\n> \n> Good point. We actually don't store any extra data in jj. The old\n> per-path conflict model was prepared for having some label associated\n> with each term of the conflict but we never actually used it.\n> \n> If we add such metadata, it would probably have to be something that\n> makes sense even after pushing the conflict to another repo, so it\n> probably shouldn't be commit ids, unless we made sure to also push\n> those commits. Also note that if you `jj restore --from <commit with\n> conflict>`, you can get a conflict into a commit that didn't have\n> conflicts previously. Or if you already had conflicts in the\n> destination commit, your root trees (the multiple root trees\n> constituting the conflict) will now have conflicts that potentially\n> were created by two completely unrelated operations, so you would kind\n> of need different labels for different paths.\n> \n> https://github.com/martinvonz/jj/issues/1176 has some more discussion\n> about this.\n> \n>>> But we'd also have to be careful and think through usecases, including\n>>> in the surrounding community.  People would probably want to ensure\n>>> that e.g. \"Protected\" or \"Integration\" branches don't get accept\n>>> fetches or pushes of conflicted commits,\n>>\n>> I think this is a really important point, while it can be useful to\n>> share conflicts so they can be collaboratively resolved we don't want to\n>> propagate them into \"stable\" or production branches. I wonder how 'jj'\n>> handles this.\n> \n> Agreed. `jj git push` refuses to push commits with conflicts, because\n> it's very unlikely that the remote will be able to make any sense of\n> it. Our commit backend at Google does support conflicts, so users can\n> check out each other's conflicted commits there (except that we\n> haven't even started dogfooding yet).\n> \n>>> git status would probably\n>>> need some special warnings or notices, git checkout would probably\n>>> benefit from additional warnings/notices checks for those cases, git\n>>> log should probably display conflicted commits differently, we'd need\n>>> to add special handling for higher order conflicts (e.g. a merge with\n>>> conflicts is itself involved in a merge) probably similar to what jj\n>>> has done, and audit a lot of other code paths to see what would be\n>>> needed.\n>>\n>> As you point out there is a lot more to this than just being able to\n>> store the conflict data in a commit - in many ways I think that is the\n>> easiest part of the solution to sharing conflicts.\n> \n> Yes, I think it would be a very large project. Unlike jj, Git of\n> course has to worry about backwards compatibility. For example, you\n> would have to decide if your goal - even in the long term - is to make\n> `git rebase` etc. not get interrupted due to conflicts.\n"},{"id":"484715","messageId":"CABPp-BF35JvbXcjLxJkQtKeVhQ2qYaBXBoN4P07BEWS8mxTaMA@mail.gmail.com","threadId":"60481","inReplyTo":"CAESOdVBjEYAp+P_mYdByYrPmbiu9DWL=Z_r19H8D9bxkJrquFA@mail.gmail.com","subject":"Re: first-class conflicts?","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2023-11-10T21:41:43Z","receivedAt":"2023-11-10T21:42:01Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Martin,\n\nOn Wed, Nov 8, 2023 at 10:23 AM Martin von Zweigbergk\n<martinvonz@google.com> wrote:\n> On Tue, Nov 7, 2023 at 11:31 PM Elijah Newren <newren@gmail.com> wrote:\n> > On Tue, Nov 7, 2023 at 9:38 AM Martin von Zweigbergk\n> > <martinvonz@google.com> wrote:\n> > >\n[...]\n> > I am curious more about the data you do store.  My fuzzy memory is\n> > that you store a commit header involving something of the form \"A + B\n> > - C\", where those are all commit IDs.  Is that correct?\n>\n> We actually store it outside the Git repo (together with the \"change\n> id\"). We have avoided using commit headers because I wasn't sure how\n> well different tools deal with unexpected commit headers, and because\n> I wanted commits to be indistinguishable from commits created by a\n> regular Git binary. The latter argument doesn't apply to commits with\n> conflicts since those are clearly not from a regular Git binary\n> anyway, and we don't allow pushing them to a remote.\n>\n> >  Is this in\n> > addition to a normal \"tree\" header as in Git, or are one of A or B\n> > found in the tree header?\n>\n> It's in addition. For the tree, we actually write a tree object with\n> three subtrees:\n>\n> .jjconflict-base-0: C\n> .jjconflict-side-0: A\n> .jjconflict-side-1: B\n>\n> The tree is not authoritative - we use the Git-external storage for\n> that. The reason we write the trees is mostly to prevent them from\n> getting GC'd.\n\nOh, that seems like a clever way to handle reachability and make sure\nthe relevant trees are automatically included in any pushes or pulls.\n\n> Also, if a user does `git checkout <conflicted commit>`,\n> they'll see those subdirectories and will hopefully be reminded that\n> they did something odd (perhaps we should drop the leading `.` so `ls`\n> will show them...). They can also diff the directories in a diff tool\n> if they like.\n\nOh, so they don't get a regular top-level looking tree with\npossibly-conflicted-files present?  Or is this in addition to the\nregular repository contents?  If in addition, are you worried about\nusers ever creating real entries named \".jjconflict-base-<N>\" in their\nrepository?\n\n> >  I think you said there was also the\n> > possibility for more than three terms.  Are those for when a\n> > conflicted commit is merged with another branch that adds more\n> > conflicts, or are there other cases too?  (Octopus merges?)\n>\n> Yes, they can happen in both of those cases you mention. More\n> generally, whenever you apply a diff between two trees onto another\n> tree, you might end up with a higher-arity conflict. So merging in\n> another branch can do that, or doing an octopus merge (which is the\n> same thing at the tree level, just different at the commit level), or\n> rebasing or reverting a commit.\n>\n> We simplify conflicts algebraically, so rebasing a commit multiple\n> times does not increase the arity - the intermediate parents were both\n> added and removed and thus cancel out. These simple algorithms for\n> simplifying conflicts are encapsulated in\n> https://github.com/martinvonz/jj/blob/main/lib/src/merge.rs. Most of\n> them are independent of the type of values being merged; they can be\n> used for doing algebra on tree ids, content hunks, refs, etc. (in the\n> test cases, we mostly merge integers because integer literals are\n> compact).\n\nIt's done on content hunks as well?  That's interesting.\n\nWhen exactly would it be done on refs, though?  I'm not following that one.\n\nAnd what else is in that \"etc.\"?\n\n> > What about recursive merges, i.e. merges where the two sides do not\n> > have a unique merge base.  What is the form of those?  (Would \"- C\" be\n> > replaced by \"- C1 - C2 - ... - Cn\"?  Or would we create the virtual\n> > merge base V and then do a \" - V\"?  Or do we only have \"A + B\"?)\n>\n> We do that by recursively creating a virtual tree just like Git does,\n> I think (https://github.com/martinvonz/jj/blob/084b99e1e2c42c40f2d52038cdc97687b76fed89/lib/src/rewrite.rs#L56-L71).\n> I think the main difference is that by modeling conflicts, we can\n> avoid recursive conflict markers (if that's what Git does), and we can\n> even automatically resolve some cases where the virtual tree has a\n> conflict.\n\nOkay, but that talks about the mechanics of creating a recursive\nmerge, omitting all the details about how the conflict header is\nwritten when you record the merge.  Is the virtual merge base\nrepresented in the algebraic \"A + B - C\" expressions, or is the \"- C\"\npart omitted?  If it is represented, and the virtual merge base had\nconflicts which you could not automatically resolve, what exactly does\nthe conflicted header for the outer merge get populated with?\n\n[...]\n\n> Great questions! We don't have support for renames, so we haven't had\n> to worry about these things. We have talked a little about divergent\n> renames and the need for recording that in the commit so we can tell\n> the user about it and maybe ask them which name they want to keep. I\n> had not considered the interaction with partial conflict resolution,\n> so thanks for bringing that up. I don't have any answers now, but\n> we'll probably need to start thinking about this soon.\n\nI was wondering if that might be the answer.  When you do tackle this,\nI'd be interested to hear your thoughts.  I'm wondering if we just\nneed to augment the data in the conflict header to handle such cases\n(though I guess this could risk having commit objects that are\nsignificantly bigger than normal in theoretical cases where many such\npaths are involved?)\n\n> > I'm curious to hear what happens when you do start dogfooding, on\n> > projects with many developers and which are jj-only.  Do commits with\n> > conflicts accidentally end up in mainline branches, or are there good\n> > ways to make sure they don't hit anything considered stable?\n>\n> That won't happen at Google because our source of truth for \"merged\n> PRs\" (in GitHub-speak) is in our existing VCS. We will necessarily\n> have to translate from jj's data model to its data model before a\n> commit can even be sent for review.\n\nThat makes sense, but I was just hoping we'd have an example to look\nto for how to keep things safe if we were to implement this.  Sadly, I\ndon't think we have the benefit of relying on folks to first push\ntheir commits into some other VCS which lacks this feature.  ;-)\n"},{"id":"484725","messageId":"CABPp-BGhJEKu2LvFoVMg-RVaiWYQx1_VjGc=NyNVo-7s-JS8rQ@mail.gmail.com","threadId":"60481","inReplyTo":"a1cd2dba-3a74-4b41-8585-209b4a13b8c4@gmail.com","subject":"Re: first-class conflicts?","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2023-11-10T22:57:00Z","receivedAt":"2023-11-10T22:58:17Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Phillip,\n\nOn Thu, Nov 9, 2023 at 6:45 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n[...]\n> > This is a great thing to think about and bring up.  However, I'm not\n> > sure what part of it actually needs to be preserved; in fact, it's not\n> > clear to me that any of it needs preserving -- especially not the\n> > files read by \"git commit\".  A commit was already created, after all.\n> >\n> > It seems that CHERRY_PICK_HEAD/REVERT_HEAD files exist primarily to\n> > clue in that we are in-the-middle-of-<op>, and the conflict header\n> > (the \"tree A + tree B - tree C\" thing; whatever that's called)\n> > similarly provides signal that the commit still has conflicts.\n> > Secondarily, these files contain information about the tree we came\n> > from and its parent tree, which allows users to investigate the diff\n> > between those...but that information is also available from the\n> > conflict header in the recorded commit.  The CHERRY_PICK_HEAD and\n> > REVERT_HEAD files could also be used to access the commit message, but\n> > that would have been stored in the conflicted commit as well.  Are\n> > there any other pieces of information I'm missing?\n>\n> Mainly that I'm an idiot and forgot we were actually creating a commit\n> and can store the message and authorship there!\n\nYou're definitely not an idiot.  The whole problem space is new and\ndifferent, so it's easy to overlook or forget certain details, and\neven to make completely different assumptions than others and have no\none aware that we're operating with similar sounding but entirely\ndifferent mental models.\n\n> More seriously I think\n> being able to inspect the commit being cherry-picked (including the\n> original commit message) is useful so we'd need to recreate something\n> like CHERRY_PICK_HEAD when the conflict commit is checked out.\n\nSo, I see a few issues with this:\n\n1) Even if we were to create CHERRY_PICK_HEAD as you envision, that\ndoesn't necessarily guarantee the user can view the original commit\nbecause they may not have it.  It may have been a local-only commit\nthat wasn't pushed or pulled to the person who is now investigating\nit.\n\n2a) You highlight the original commit message, but if someone doesn't\nwant to immediately resolve conflicts, why would they be modifying the\ncommit message?\n\n2b) Even if users did want to modify the commit message without\nresolving conflicts, how would they do so?  Rebasing has\ninteractivity, but cherry-picking doesn't.  And interactivity seems to\nbe something people probably wouldn't use together with storing\nconflicts; the point of interactivity is to tweak things further and\nfix them up, suggesting they'd want to be running in\naddress-conflicts-now mode.\n\n> Recreating CHERRY_PICK_HEAD is useful for \"git status\" as well.\n\n\"git status\" uses this file to determine if it should display\ninformation about currently being in the middle of a cherry-pick\noperation.  Putting such a file in place would thus be misleading,\nbecause we aren't in a cherry-pick operation anymore; that has\ncompleted already.  I would not expect the suggested commands printed\nby git-status while it thinks we're in such a state (namely, \"git\ncherry-pick [--continue|--skip|--abort]\") to work either.  So, I'd\nargue it would be a bug to create such a file when checking out a\nconflicted-commit.\n\nOf course, we would want git-status to display information about the\ncurrent commit being conflicted, but I think that could be based on\nthe simple conflict header without additional info.\n\n> I think\n> that means storing a little more that just the \"tree A + tree B - tree\n> C\" thing.\n\nI'm totally willing to believe there will be cases where more info is\nneeded.  I'm suspecting that conflicts with certain kinds of renames,\nor which were performed with certain types of strategies or strategy\noptions might be some examples.  But I'm not sure I'm understanding\nwhy CHERRY_PICK_HEAD should be one of those cases.\n\n> > I think the big piece here is whether we also want to adopt jj's\n> > behavior of automatically rebasing all descendant commits when\n> > checking out and amending some historical commit (or at least having\n> > the option of doing so).  That behavior allows users to amend commits\n> > to resolve conflicts without figuring out complicated interactive\n> > rebases to fix all the descendant commits across all relevant\n> > branches.\n>\n> That's a potentially attractive option which is fairly simple to\n> implement locally as I think you can use the commit DAG to find all the\n> descendants though that could be expensive if there are lots of\n> branches. However, if we're going to share conflicts I think we'd need\n> something like \"hg evolve\" - if I push a commit with conflicts and you\n> base some work on it and then I resolve the conflict and push again you\n> would want to your work to be rebased onto my conflict resolution.\n\nOoh, that's an interesting point.\n\n> To handle \"rebase --exec\" we could store the exec command and run it when\n> the  conflicts are resolved.\n\nSo, my assumption is that even if we add the ability to commit\nconflicts and even if we default to auto-committing them during\ncherry-picks or non-interactive rebases, there will still be people\nwho want to resolve conflicts as they are hit rather than\nauto-committing them, and thus that stop-on-conflict should always be\nan option.  In the world where a user has this choice, I think it'd be\nrare for users to want to auto-commit conflicts with --exec.  I'd\nsuggest that --exec, and even --interactive, would default to stopping\non conflicts and waiting for the user to resolve even if\nauto-commit-on-conflict is the default in other cases.\n\nThat leaves me wondering if there are any cases where users want to\nauto-commit conflicts in.conjunction with --exec, which I'm already\nstruggling to come up with, _and_ that would further want the exec\ncommands to be preserved in the conflicted commits (and any descendant\ncommits?) for later usage.  Maybe there's a case for that, but I'm not\ncoming up with it right now.\n\nAlso, another way of looking at this is that my current mental model\nis that the cherry-pick or rebase operation is completed once it has\nhandled each of the commits in its list; the operation does not extend\nuntil all the conflicts in the commits it creates are resolved.  The\nfact that rebases do not extend until conflicts are resolved is\nimportant because you can later further rebase conflicted-commits (as\nMartin alludes to in his emails); considering the old rebase(s) to\nstill be in progress while a new one starts might get excessively\ncomplex to handle.  The reason all of this matters to --exec is that\n--exec is part of the rebase operation; once the rebase operation is\ndone, the --exec stuff is also done.  (And thus, if you don't want\n--exec to run on conflicted commits, then don't opt for\nauto-committing conflicts.).\n\n> Also I wonder how annoying it would be in cases where I just want to\n> rebase and resolve the conflicts now. At the moment \"git rebase\" stops\n> at the conflict, with this feature I'd have to go and checkout the\n> conflicted commit and fix the conflicts after the rebase had finished.\n\nI agree that would often be annoying.  Personally, I think that\nauto-committing conflicts as a feature should at most be an option\n(even if perhaps the default in some cases), not a new mandatory\nworldview.  And I'm currently not convinced that even if it were\nimplemented it should be the default in any cases.\n\n> > Without that feature, I agree this might be a bit more\n> > difficult,\n>\n> Yes, when I wrote my original message I was imagining that we'd stop at\n> the first conflicting pick and store all the rebase state like some kind\n> of stash on steroids so it could be continued when the conflict was\n> resolved. It would be much simpler to try and avoid that.\n\nYeah, this is an example of how completely different mental models we\ncan come up with when none of us (other than Martin) know much about\nthe problem space.  I suspect there's at least a few more examples\nlike this where we still have very different mental models, and\nperhaps some gems to be found by mixing and matching them.\n\n> > There are some special state files related to half-completed\n> > operations (e.g. squash commits when we haven't yet reached the final\n> > one in the sequence, a file to note that we want to edit a commit\n> > message once the user has finished resolving conflicts, whether we\n> > need to create a new root commit), but again, the operation has\n> > completed and commits have been created with appropriate parentage and\n> > commit messages so I don't think these are useful anymore either.\n>\n> Yes, though we may want to remember which commits were squashed together\n> so the user can inspect that when resolving conflicts.\n\nOoh, that's interesting...though it does run into the problem of users\nnot having access to the original commits.\n\n> > The biggest issue is perhaps that REBASE_HEAD is used in the\n> > implementation of `git rebase --show-current-patch`, but all\n> > information stored in that is still accessible -- the commit message\n> > is stored in the commit, the author time is stored in the commit, and\n> > the trees involved are in the conflict header.  The only thing missing\n> > is committer timestamp, which isn't relevant anyway.\n>\n> The commit message may have been edited so we lose the original message\n> but I'm not sure how important that is.\n\nIs this a reversal from your comment earlier in your email about the\nimportance of the original commit message for CHERRY_PICK_HEAD?  :-)\n\n> > The only ones I'm pausing a bit on are the strategy and\n> > strategy-options.  Those might be useful somehow...but I can't\n> > currently quite put my finger on explaining how they would be useful\n> > and I'm not sure they are.\n>\n> I can't think of an immediate use for them. When we re-create conflicts\n> we do it per-file based on the index entries created by the original\n> merge so I don't think we need to know anything about the strategy or\n> strategy-options.\n\nBut we don't have index entries.  We only have trees in this\nconflicted commit, and when users check it out, they probably expect\nconflicted index entries to be put into place.  Can we correctly\nregenerate the right conflicted index entries from the original trees\nwithout the strategy and strategy-options command line flags?  I\nsuspect there might be problems here, and user-defined merge\nstrategies could really throw a wrench in the works.  Hmm...\n\n> > Am I missing anything?\n>\n> exec commands? If the user runs \"git rebase --exec\" and there are\n> conflicts then we'd need to defer running the exec commands until the\n> conflicts are resolved. For something like \"git rebase --exec 'make\n> test'\" that should be fine. I wonder if there are corner cases where the\n> exec command changes HEAD though.\n\nWe talked about exec commands above, as well as the assumption whether\nauto-committing conflicts should be mandatory vs. an option, so I\nwon't repeat that here.  It was definitely a very interesting topic to\nbring up though; thanks!\n\n[...]\n\n> Yes, it would certainly be lots of work.\n\n...but even if none of us get time and prioritization to work on it, I\npersonally find it a really interesting topic to discuss and explore.\nThanks for joining in and bringing up many good points!\n"},{"id":"484739","messageId":"ZUmJyFs7z7wdmLVK@mit.edu","threadId":"60481","inReplyTo":"Gr..Y5kkszDx87g@idiomdrottning.org","subject":"Re: first-class conflicts?","fromName":"Theodore Ts'o","fromEmail":"tytso@mit.edu","sentAt":"2023-11-07T00:50:16Z","receivedAt":"2023-11-11T00:55:26Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Mon, Nov 06, 2023 at 10:45:03PM +0000, Sandra Snan wrote:\n> Randall, thank you for that.\n> \n> I just have sometimes wish git could be a little more aware of them beyond\n> just storing them with ASCII art in the files themselves (and alerting /\n> warning when they happen but I often can't properly see those warnings flash\n> by so I end up having to search for the conflict markers manually). So if\n> conflicts are a thing that *can* happen, it'd be better if vc could know\n> about them which would make some of the rebases simpler as in jj. That\n> doesn't mean we wanna adopt the jj workflow of deliberately checking in\n> conflicts (not even locally), just be able to deal with them better if it\n> does happen.\n\nWell, if you miss them, \"git status\" does show that there are conflicts:\n\n   Unmerged paths:\n     (use \"git add <file>...\" to mark resolution)\n           both modified:   version.h\n\nAnd if you attempt to commit the merge without resolving the\nconflicts, git won't let you:\n\n   error: Committing is not possible because you have unmerged files.\n   hint: Fix them up in the work tree, and then use 'git add/rm <file>'\n   hint: as appropriate to mark resolution and make a commit.\n\nSo it's hard to miss the indications of the content conflict, because\nif you try to commit without resolving them, it's not a warning, it's\nan outright error.\n\nCheers,\n\n\t\t\t\t\t- Ted\n"},{"id":"484741","messageId":"xmqqh6ltrs6t.fsf@gitster.g","threadId":"60481","inReplyTo":"ZUmJyFs7z7wdmLVK@mit.edu","subject":"Re: first-class conflicts?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-11T01:31:54Z","receivedAt":"2023-11-11T01:31:58Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Theodore Ts'o\" <tytso@mit.edu> writes:\n\n> And if you attempt to commit the merge without resolving the\n> conflicts, git won't let you:\n>\n>    error: Committing is not possible because you have unmerged files.\n>    hint: Fix them up in the work tree, and then use 'git add/rm <file>'\n>    hint: as appropriate to mark resolution and make a commit.\n>\n> So it's hard to miss the indications of the content conflict, because\n> if you try to commit without resolving them, it's not a warning, it's\n> an outright error.\n\nCorrect but with a caveat: it is too easy for lazy folks to\ncircumvent the safety by mistake with \"commit -a\".\n\nI wonder if it would help users to add a new configuration option\nfor those who want to live safer that tells \"commit -a\" to leave\nunmerged paths alone and require the unmerged paths to be added\nexplicitly (which may have to extend to cover things like \"add -u\"\nand \"add .\").\n\nPerhaps not.  I often find myself doing \"git add -u\" after resolving\nconflicts and re-reading the result, without an explicit pathspec.\n\n\n"},{"id":"484750","messageId":"87wmuohgsi.fsf@ellen.idiomdrottning.org","threadId":"60481","inReplyTo":"xmqqh6ltrs6t.fsf@gitster.g","subject":"Re: first-class conflicts?","fromName":"Sandra Snan","fromEmail":"sandra.snan@idiomdrottning.org","sentAt":"2023-11-11T07:48:13Z","receivedAt":"2023-11-11T07:48:19Z","isPatch":false,"sender":{"key":"sandra.snan@idiomdrottning.org","avatar":"https://gravatar.com/avatar/9f3cf671ef175db9ce2f833436f4f63b58f54651b1208ef07e63ee7443e86e82?d=mp&s=160"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n> Correct but with a caveat: it is too easy for lazy folks to \n> circumvent the safety by mistake with \"commit -a\". \n\nLazy and ignorant like myself because I didn't know -a was that\ndangerous. Thank you both!\n"},{"id":"484769","messageId":"CAESOdVCGG6JfW8kuSBPe0bPNyOqW-K6AWKp9acZv_B=teDd3KA@mail.gmail.com","threadId":"60481","inReplyTo":"CABPp-BF35JvbXcjLxJkQtKeVhQ2qYaBXBoN4P07BEWS8mxTaMA@mail.gmail.com","subject":"Re: first-class conflicts?","fromName":"Martin von Zweigbergk","fromEmail":"martinvonz@google.com","sentAt":"2023-11-12T07:05:19Z","receivedAt":"2023-11-12T07:05:34Z","isPatch":false,"sender":{"key":"martinvonz@google.com","avatar":"https://avatars.githubusercontent.com/u/891642?v=4"},"body":"On Fri, Nov 10, 2023 at 1:41 PM Elijah Newren <newren@gmail.com> wrote:\n>\n> Hi Martin,\n>\n> On Wed, Nov 8, 2023 at 10:23 AM Martin von Zweigbergk\n> <martinvonz@google.com> wrote:\n> > On Tue, Nov 7, 2023 at 11:31 PM Elijah Newren <newren@gmail.com> wrote:\n> > > On Tue, Nov 7, 2023 at 9:38 AM Martin von Zweigbergk\n> > > <martinvonz@google.com> wrote:\n> > > >\n> [...]\n> > > I am curious more about the data you do store.  My fuzzy memory is\n> > > that you store a commit header involving something of the form \"A + B\n> > > - C\", where those are all commit IDs.  Is that correct?\n> >\n> > We actually store it outside the Git repo (together with the \"change\n> > id\"). We have avoided using commit headers because I wasn't sure how\n> > well different tools deal with unexpected commit headers, and because\n> > I wanted commits to be indistinguishable from commits created by a\n> > regular Git binary. The latter argument doesn't apply to commits with\n> > conflicts since those are clearly not from a regular Git binary\n> > anyway, and we don't allow pushing them to a remote.\n> >\n> > >  Is this in\n> > > addition to a normal \"tree\" header as in Git, or are one of A or B\n> > > found in the tree header?\n> >\n> > It's in addition. For the tree, we actually write a tree object with\n> > three subtrees:\n> >\n> > .jjconflict-base-0: C\n> > .jjconflict-side-0: A\n> > .jjconflict-side-1: B\n> >\n> > The tree is not authoritative - we use the Git-external storage for\n> > that. The reason we write the trees is mostly to prevent them from\n> > getting GC'd.\n>\n> Oh, that seems like a clever way to handle reachability and make sure\n> the relevant trees are automatically included in any pushes or pulls.\n>\n> > Also, if a user does `git checkout <conflicted commit>`,\n> > they'll see those subdirectories and will hopefully be reminded that\n> > they did something odd (perhaps we should drop the leading `.` so `ls`\n> > will show them...). They can also diff the directories in a diff tool\n> > if they like.\n>\n> Oh, so they don't get a regular top-level looking tree with\n> possibly-conflicted-files present? Or is this in addition to the\n> regular repository contents?\n\nThey get a regular tree with conflict markers if they use `jj\ncheckout`, but not if they use `git checkout`.\n\n> If in addition, are you worried about\n> users ever creating real entries named \".jjconflict-base-<N>\" in their\n> repository?\n\nI'm not worried about that since it's not the source of truth, so at\nmost they waste some time.\n\nBy the way, if the user did use `git checkout` and got those\n`.jjconflict-*` directories in the working copy, and then ran a `jj`\ncommand afterwards, then jj would think that the conflict was resolved\nby replacing the conflicted paths (and all other paths!) by those\n`.jjconflict-*` directories :) The user would probably realize their\nmistake pretty quickly and run `jj abandon` to discard those changes.\n\n>\n> > >  I think you said there was also the\n> > > possibility for more than three terms.  Are those for when a\n> > > conflicted commit is merged with another branch that adds more\n> > > conflicts, or are there other cases too?  (Octopus merges?)\n> >\n> > Yes, they can happen in both of those cases you mention. More\n> > generally, whenever you apply a diff between two trees onto another\n> > tree, you might end up with a higher-arity conflict. So merging in\n> > another branch can do that, or doing an octopus merge (which is the\n> > same thing at the tree level, just different at the commit level), or\n> > rebasing or reverting a commit.\n> >\n> > We simplify conflicts algebraically, so rebasing a commit multiple\n> > times does not increase the arity - the intermediate parents were both\n> > added and removed and thus cancel out. These simple algorithms for\n> > simplifying conflicts are encapsulated in\n> > https://github.com/martinvonz/jj/blob/main/lib/src/merge.rs. Most of\n> > them are independent of the type of values being merged; they can be\n> > used for doing algebra on tree ids, content hunks, refs, etc. (in the\n> > test cases, we mostly merge integers because integer literals are\n> > compact).\n>\n> It's done on content hunks as well?  That's interesting.\n\nYes, when merging trees, we start at the root tree and try to resolve\nconflicts at the tree entry level (i.e. without reading file\ncontents). I think git does the same. If that's not enough we need to\nrecurse into subtrees or file contents. When merging files, we find\nmatching regions of the inputs and use the same algorithm on the\nindividual chunks between the matching regions.\n\n>\n> When exactly would it be done on refs, though?  I'm not following that one.\n\nFirst of all, note that jj allows refs to be in a conflicted state\nsimilar to how trees can be in a conflicted state. We merge refs for a\nfew different reasons. If you run two concurrent operations on a repo,\nwe merge any changes to the refs. We do the same thing when you fetch\nbranches from a remote. For example, if you've fetched branch \"main\"\nfrom a remote, then moved it locally, and then you fetch again from\nthe remote, we'll attempt to merge those refs. We use the same\nfunction for merging there, but if it fails, we then also\nautomatically resolve two operations moving the branch forward\ndifferent amounts (e.g. one operation moves a ref from X~10 to X~5\nwhile the other moves it forward to X, we resolve to X).\nhttps://github.com/martinvonz/jj/blob/main/docs/technical/concurrency.md\ntalks a bit more about that.\n\n>\n> And what else is in that \"etc.\"?\n\nI think it's only individual file ids (blob ids) and the executable\nbit. If a file's content changed and its executable bit changed, we\nuse the same algorithm for each of those pieces of information.\n\n>\n> > > What about recursive merges, i.e. merges where the two sides do not\n> > > have a unique merge base.  What is the form of those?  (Would \"- C\" be\n> > > replaced by \"- C1 - C2 - ... - Cn\"?  Or would we create the virtual\n> > > merge base V and then do a \" - V\"?  Or do we only have \"A + B\"?)\n> >\n> > We do that by recursively creating a virtual tree just like Git does,\n> > I think (https://github.com/martinvonz/jj/blob/084b99e1e2c42c40f2d52038cdc97687b76fed89/lib/src/rewrite.rs#L56-L71).\n> > I think the main difference is that by modeling conflicts, we can\n> > avoid recursive conflict markers (if that's what Git does), and we can\n> > even automatically resolve some cases where the virtual tree has a\n> > conflict.\n>\n> Okay, but that talks about the mechanics of creating a recursive\n> merge, omitting all the details about how the conflict header is\n> written when you record the merge.  Is the virtual merge base\n> represented in the algebraic \"A + B - C\" expressions, or is the \"- C\"\n> part omitted?  If it is represented, and the virtual merge base had\n> conflicts which you could not automatically resolve, what exactly does\n> the conflicted header for the outer merge get populated with?\n\nI think we're talking about the state in F below, right?\n\n  F\n/ \\\n/ \\\nD E\n|\\ /|\n| X |\n|/ \\|\nB C\n\\ /\n\\ /\nA\n\nThe virtual commit/tree, which we can think of as sitting where the X\nis in the graph, would have state V=B+C-A. The state at F would have\nD+E-V=D+E-(B+C-A)=D+(E-C)+(A-B). This is encoded in `Merge::flatten()`\nhere:  https://github.com/martinvonz/jj/blob/e3a1e5b80ed9124091baa4d920cc9e8124c1f559/lib/src/merge.rs#L421-L451.\nIt's not specific to recursive merge; we run into the same kind of\nhigher-arity conflicts on regular octopus merges or repeated merges\n(if you don't resolve conflicts in between).\n\nOh, I should also say that we don't store the unmodified trees in\nthese expressions. Instead, for anything we can automatically resolve,\nwe replace those parts of the trees. So even if A, B, and C differ at\npaths X, Y, and Z, the trees we associate with V might only differ at\npath Y if that's the only path we couldn't resolve. IIRC, I did it\nthat way because it seemed wasteful to re-attempt the merge at paths X\nand Z every time we rewrite the commit. I *think* it rarely matters in\npractice, but it feels like it could in some cases (maybe where two\nsides make the same changes).\n\n>\n> [...]\n>\n> > Great questions! We don't have support for renames, so we haven't had\n> > to worry about these things. We have talked a little about divergent\n> > renames and the need for recording that in the commit so we can tell\n> > the user about it and maybe ask them which name they want to keep. I\n> > had not considered the interaction with partial conflict resolution,\n> > so thanks for bringing that up. I don't have any answers now, but\n> > we'll probably need to start thinking about this soon.\n>\n> I was wondering if that might be the answer.  When you do tackle this,\n> I'd be interested to hear your thoughts.  I'm wondering if we just\n> need to augment the data in the conflict header to handle such cases\n> (though I guess this could risk having commit objects that are\n> significantly bigger than normal in theoretical cases where many such\n> paths are involved?)\n\nYes, that's what I've been thinking, but I think the only thing I had\nbeen thinking of storing was for \"divergent renames\" (A->B on one\nside, A->C on the other). Will let you know when we start thinking\nabout this for real. Thanks again for your input!\n\n>\n> > > I'm curious to hear what happens when you do start dogfooding, on\n> > > projects with many developers and which are jj-only.  Do commits with\n> > > conflicts accidentally end up in mainline branches, or are there good\n> > > ways to make sure they don't hit anything considered stable?\n> >\n> > That won't happen at Google because our source of truth for \"merged\n> > PRs\" (in GitHub-speak) is in our existing VCS. We will necessarily\n> > have to translate from jj's data model to its data model before a\n> > commit can even be sent for review.\n>\n> That makes sense, but I was just hoping we'd have an example to look\n> to for how to keep things safe if we were to implement this.  Sadly, I\n> don't think we have the benefit of relying on folks to first push\n> their commits into some other VCS which lacks this feature.  ;-)\n\nIt might be best to disallow pushing conflicts to start with. It\nshould also be easy to add a hook on the server to disallow it only to\ncertain branches.\n"},{"id":"484774","messageId":"20231112152143.GD35991@mit.edu","threadId":"60481","inReplyTo":"xmqqh6ltrs6t.fsf@gitster.g","subject":"Re: first-class conflicts?","fromName":"Theodore Ts'o","fromEmail":"tytso@mit.edu","sentAt":"2023-11-12T15:21:43Z","receivedAt":"2023-11-12T15:22:11Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Sat, Nov 11, 2023 at 10:31:54AM +0900, Junio C Hamano wrote:\n> Correct but with a caveat: it is too easy for lazy folks to\n> circumvent the safety by mistake with \"commit -a\".\n> \n> I wonder if it would help users to add a new configuration option\n> for those who want to live safer that tells \"commit -a\" to leave\n> unmerged paths alone and require the unmerged paths to be added\n> explicitly (which may have to extend to cover things like \"add -u\"\n> and \"add .\").\n> \n> Perhaps not.  I often find myself doing \"git add -u\" after resolving\n> conflicts and re-reading the result, without an explicit pathspec.\n\nMaybe the configuration option would also forbit \"git add -u\" from\nadding diffs with conflict markers unless --force is added?\n\nI dunno.  I personally wouldn't use it myself, because I've always\nmade a point of running \"git diff\", or \"git status\", and almost\nalways, a command like \"make -j16 && make -j16 check\" (or an aliased\nequivalent) before commiting a merge.\n\nBut that's because I'm a paranoid s.o.b. and in my long career, I've\nlearned is that \"you can't be paranoid enough\", and \"hope is not a\nstrategy\".  :-)\n\n\t\t\t\t\t- Ted\n"},{"id":"484778","messageId":"xmqqr0kumu56.fsf@gitster.g","threadId":"60481","inReplyTo":"20231112152143.GD35991@mit.edu","subject":"Re: first-class conflicts?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-11-12T23:25:25Z","receivedAt":"2023-11-12T23:25:32Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Theodore Ts'o\" <tytso@mit.edu> writes:\n\n> On Sat, Nov 11, 2023 at 10:31:54AM +0900, Junio C Hamano wrote:\n>> ... \n>> I wonder if it would help users to add a new configuration option\n>> for those who want to live safer that tells \"commit -a\" to leave\n>> unmerged paths alone and require the unmerged paths to be added\n>> explicitly (which may have to extend to cover things like \"add -u\"\n>> and \"add .\").\n>> \n>> Perhaps not.  I often find myself doing \"git add -u\" after resolving\n>> conflicts and re-reading the result, without an explicit pathspec.\n>\n> Maybe the configuration option would also forbit \"git add -u\" from\n> adding diffs with conflict markers unless --force is added?\n\nHistorically we left it to pre-commit hooks, but I agree that\nprotection at the time of \"git add\" may be more helpful.\n\nI also alluded to being careful about \"git add\" with an overly vague\npathspec (like \".\"  to add everything addable under the sun), but I\ndo not think it is possible to define \"overly vague\" in a way that\nsatisfies everybody (would \"git add \\*.h\" be still overly vague when\n5% of your header files have conflicts in the merge you are\nconcluding?) and keep the new users safe.\n\nUnless the configuration forbids patterns and say \"each and every\nindividual path must be named to add and resolve conflicted paths\",\nthat is.  Come to think of it, that may not be too bad.\n\n> I dunno.  I personally wouldn't use it myself, because I've always\n> made a point of running \"git diff\", or \"git status\", and almost\n> always, a command like \"make -j16 && make -j16 check\" (or an aliased\n> equivalent) before commiting a merge.\n>\n> But that's because I'm a paranoid s.o.b. and in my long career, I've\n> learned is that \"you can't be paranoid enough\", and \"hope is not a\n> strategy\".  :-)\n\nBeing careful and paranoid is good ;-) I wouldn't use it myself,\neither, but the discussion started while trying to allay new users'\nworries about recording a half-resolved state by mistake, and in\nthat context, I think it would have non-empty audiences.\n\nThanks.\n\n"}]}