{"thread":{"id":"37326","subject":"Sharing merge conflict resolution between multiple developers","startedAt":"2014-08-11T04:59:15Z","lastAt":"2014-08-19T13:09:36Z","messageCount":10,"participants":["Chris Packham","Junio C Hamano","Christian Couder","Nico Williams","Jeff King","Jason Pyeron"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"247574","messageId":"CAFOYHZCiKC4TR4jFVUB=W5qbDG8XvB2Obx1ZfTH8OF3E_c5BnA@mail.gmail.com","threadId":"37326","inReplyTo":null,"subject":"Sharing merge conflict resolution between multiple developers","fromName":"Chris Packham","fromEmail":"judge.packham@gmail.com","sentAt":"2014-08-11T04:59:15Z","receivedAt":"2014-08-11T04:59:15Z","isPatch":false,"sender":{"key":"judge.packham@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155667?v=4"},"body":"Hi List,\n\nAt $dayjob we maintain internal forks of the a number of upstream repositories.\n\nUnsurprisingly updating these forks can be extremely problematic,\nespecially when it's only one person doing the merge. Fortunately most\nof us are in the same physical location so it is possible to drag in\nsomeone who knows more about the code than the person merging but I\ncan't see that scaling with remote developers.\n\nIs there any way where we could share the conflict resolution around\nbut still end up with a single merge commit. I'm thinking of something\nlike the following workflow\n\ndeveloper A:\n  git merge $upstream\n  <conflicts>\n  git mergetool ...\n  <resolves some of the conflicts>\n  git commit -m \"WIP: Merge upstream\" --something-like--all-but-not\n\ndeveloper B:\n  git pull developer_A\n  git reset HEAD^\n  <at this point it's be nice if developer B's work tree and index\nwere in the same state as developer A's before they ran 'git commit'>\n  git mergetool ...\n  <resolves the conflicts that they know about>\n  git commit -m \"WIP: Merge upstream\" --something-like--all-but-not\n\ndeveloper A:\n  git pull developer_B\n  git reset HEAD^\n  git mergetool ....\n  <finishes off anything left>\n  git commit\n  <It'd be really nice if MERGE_MSG was retained through all of this>\n  git push\n\nAny thoughts on if something like this is currently possible? Is this\nsomething other git users would find useful?\n\nThanks,\nChris\n"},{"id":"247587","messageId":"xmqqd2c67tok.fsf@gitster.dls.corp.google.com","threadId":"37326","inReplyTo":"CAFOYHZCiKC4TR4jFVUB=W5qbDG8XvB2Obx1ZfTH8OF3E_c5BnA@mail.gmail.com","subject":"Re: Sharing merge conflict resolution between multiple developers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-08-11T18:44:11Z","receivedAt":"2014-08-11T18:44:11Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Chris Packham <judge.packham@gmail.com> writes:\n\n> Is there any way where we could share the conflict resolution around\n> but still end up with a single merge commit.\n\nOne idea that immediately comes to me is to use something like\n\"rerere\" (not its implementation and storage, but the underlying\nidea) enhanced with the trick I use to fix-up merges in my daily\nintegration cycle (look for \"merge-fix\" in howto/maintain-git.txt\nin Documentation/).\n\n> developer A:\n>   git merge $upstream\n>   <conflicts>\n\nAnd then commit this immediately, together with conflict markers\n(i.e. \"commit -a\"), and discard it with \"reset --hard HEAD^\" *after*\nstoring it somewhere safe.  And then redo the same merge, resolve\nthe conflicts and commit the usual way.\n\nThe difference between the final conflict resolution and the\noriginal conflicted state can be used as a reference for others to\nredo the same conflict resolution later elsewhere.  That can most\neasily be done by creating a commit that records the final state\nwhose parent is the one you recorded the initial conflicted state.\n\nSo, the \"recording\" phase may go something like this:\n\n    git checkout $this\n    git merge $that\n    git commit -a -m 'merge-fix/$this-$that preimage'\n    git branch merge-fix/$this-$that\n    git reset --hard HEAD^\n    git merge $that\n    edit\n    git commit -a -m 'merge $that to $this'\n    git checkout merge-fix/$this-$that\n    git read-tree -m -u HEAD $this\n    git commit -a -m 'merge-fix/$this-$that postimage'\n\nThe rough idea is \"git show merge-fix/$this-$that\" will show the\n\"patch\" you can apply on top of the conflicted state other people\nwould get by running \"git merge $that\" while on \"$this\" branch.\n\n\"rerere\" essentially does the above recording (and replaying)\nper-path and it comes with a clever indexing scheme to identify\nwhich previous conflict resolution would apply to the conflicts you\nsee in your working tree.\n"},{"id":"247589","messageId":"CAP8UFD27qHqHx4ZPw=Fyn0R9NWqhuiespDHnDi=z=1nKb=wKtg@mail.gmail.com","threadId":"37326","inReplyTo":"CAP8UFD0_zfB_D-9EVZ4K=Zdq_G+9C-QhX7WED53zExV+Nv8Arg@mail.gmail.com","subject":"Re: Sharing merge conflict resolution between multiple developers","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2014-08-11T18:57:53Z","receivedAt":"2014-08-11T18:57:53Z","isPatch":false,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Le 11 août 2014 07:50, \"Christian Couder\" <christian.couder@gmail.com> a écrit :\n>\n> This should be possible using \"git imerge\" which is separate tool.\n\nSorry I sent the above using the gmail app on my mobile phone and\nunfortunately I can't make it send plain text emails.\n(Emails which are not plain text are rejected by vger.kernel.org.)\n\nBest,\nChristian.\n"},{"id":"247592","messageId":"CAK3OfOhASo7O8UY0xbRti1GCaaLe8nZTsNj5tBQpGYNwO77R5g@mail.gmail.com","threadId":"37326","inReplyTo":"CAFOYHZCiKC4TR4jFVUB=W5qbDG8XvB2Obx1ZfTH8OF3E_c5BnA@mail.gmail.com","subject":"Re: Sharing merge conflict resolution between multiple developers","fromName":"Nico Williams","fromEmail":"nico@cryptonector.com","sentAt":"2014-08-11T19:33:47Z","receivedAt":"2014-08-11T19:33:47Z","isPatch":false,"sender":{"key":"nico@cryptonector.com","avatar":null},"body":"IIUC, this might help,\n\nhttp://www.mail-archive.com/git@vger.kernel.org/msg56418.html\nhttp://www.mail-archive.com/git@vger.kernel.org/msg56468.html\n"},{"id":"247600","messageId":"CAFOYHZAaF+Dve1DwUUd-k6Nh3+nOZzNVUQAD0quN4crRAjfCLQ@mail.gmail.com","threadId":"37326","inReplyTo":"xmqqd2c67tok.fsf@gitster.dls.corp.google.com","subject":"Re: Sharing merge conflict resolution between multiple developers","fromName":"Chris Packham","fromEmail":"judge.packham@gmail.com","sentAt":"2014-08-11T23:29:04Z","receivedAt":"2014-08-11T23:29:04Z","isPatch":false,"sender":{"key":"judge.packham@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155667?v=4"},"body":"On Tue, Aug 12, 2014 at 6:44 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Chris Packham <judge.packham@gmail.com> writes:\n>\n>> Is there any way where we could share the conflict resolution around\n>> but still end up with a single merge commit.\n>\n> One idea that immediately comes to me is to use something like\n> \"rerere\" (not its implementation and storage, but the underlying\n> idea) enhanced with the trick I use to fix-up merges in my daily\n> integration cycle (look for \"merge-fix\" in howto/maintain-git.txt\n> in Documentation/).\n>\n>> developer A:\n>>   git merge $upstream\n>>   <conflicts>\n>\n> And then commit this immediately, together with conflict markers\n> (i.e. \"commit -a\"), and discard it with \"reset --hard HEAD^\" *after*\n> storing it somewhere safe.  And then redo the same merge, resolve\n> the conflicts and commit the usual way.\n>\n> The difference between the final conflict resolution and the\n> original conflicted state can be used as a reference for others to\n> redo the same conflict resolution later elsewhere.  That can most\n> easily be done by creating a commit that records the final state\n> whose parent is the one you recorded the initial conflicted state.\n>\n> So, the \"recording\" phase may go something like this:\n>\n>     git checkout $this\n>     git merge $that\n>     git commit -a -m 'merge-fix/$this-$that preimage'\n>     git branch merge-fix/$this-$that\n>     git reset --hard HEAD^\n>     git merge $that\n>     edit\n>     git commit -a -m 'merge $that to $this'\n>     git checkout merge-fix/$this-$that\n>     git read-tree -m -u HEAD $this\n>     git commit -a -m 'merge-fix/$this-$that postimage'\n>\n> The rough idea is \"git show merge-fix/$this-$that\" will show the\n> \"patch\" you can apply on top of the conflicted state other people\n> would get by running \"git merge $that\" while on \"$this\" branch.\n\nSo how would someone else pickup that postimage and use it?\n\n  git checkout $this\n  git merge $that\n  git fetch $remote ':/merge-fix/$this-$that postimage'\n  git show ':/merge-fix/$this-$that postimage' | git apply (or patch -p1)\n  edit\n\n>\n> \"rerere\" essentially does the above recording (and replaying)\n> per-path and it comes with a clever indexing scheme to identify\n> which previous conflict resolution would apply to the conflicts you\n> see in your working tree.\n\nI feel a toy patch coming on.\n"},{"id":"247602","messageId":"CAPc5daW1A9OVSBPe-br-x9OeQPqj816NgMKztWMyp6gN==ojHw@mail.gmail.com","threadId":"37326","inReplyTo":"CAFOYHZAaF+Dve1DwUUd-k6Nh3+nOZzNVUQAD0quN4crRAjfCLQ@mail.gmail.com","subject":"Re: Sharing merge conflict resolution between multiple developers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-08-12T01:57:44Z","receivedAt":"2014-08-12T01:57:44Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"On Mon, Aug 11, 2014 at 4:29 PM, Chris Packham <judge.packham@gmail.com> wrote:\n\n>> So, the \"recording\" phase may go something like this:\n>> ...\n>>     git checkout merge-fix/$this-$that\n>>     git read-tree -m -u HEAD $this\n>>     git commit -a -m 'merge-fix/$this-$that postimage'\n>>\n>> The rough idea is \"git show merge-fix/$this-$that\" will show the\n>> \"patch\" you can apply on top of the conflicted state other people\n>> would get by running \"git merge $that\" while on \"$this\" branch.\n>\n> So how would someone else pickup that postimage and use it?\n>\n>   git checkout $this\n>   git merge $that\n>   git fetch $remote ':/merge-fix/$this-$that postimage'\n>   git show ':/merge-fix/$this-$that postimage' | git apply (or patch -p1)\n\nFor a simpler case that would work, but because we are not saving\njust a patch but two full trees to compare (i.e. merge-fix/$this-$that\nis the postimage, its ^1 is the preimage), you should be able to use\nthe three-way merge in a similar way cherry-pick works. In fact, that\nis how rerere replays the recorded resolution, not with a \"patch -p1\".\n"},{"id":"247808","messageId":"20140817075250.GH23808@peff.net","threadId":"37326","inReplyTo":"CAFOYHZCiKC4TR4jFVUB=W5qbDG8XvB2Obx1ZfTH8OF3E_c5BnA@mail.gmail.com","subject":"Re: Sharing merge conflict resolution between multiple developers","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-08-17T07:52:50Z","receivedAt":"2014-08-17T07:52:50Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Aug 11, 2014 at 04:59:15PM +1200, Chris Packham wrote:\n\n> Is there any way where we could share the conflict resolution around\n> but still end up with a single merge commit. I'm thinking of something\n> like the following workflow\n\nThis came up once a while back. Here's the discussion:\n\n  http://thread.gmane.org/gmane.comp.version-control.git/169187\n\nI proposed a solution there where developers push their partial\nresolutions, and the integrator (or just \"next person\" if it is a chain\nof developers) uses \"git checkout\" to pull the fixes. But note that I\nnever actually _used_ that in practice. It was a thought experiment, so\nthere may be gotchas.\n\n-Peff\n"},{"id":"247818","messageId":"DED50992A39F4A07ACD997A65602991E@black","threadId":"37326","inReplyTo":"20140817075250.GH23808@peff.net","subject":"Signinig a commit with multiple signatures","fromName":"Jason Pyeron","fromEmail":"jpyeron@pdinc.us","sentAt":"2014-08-17T13:30:47Z","receivedAt":"2014-08-17T13:30:47Z","isPatch":false,"sender":{"key":"jpyeron@pdinc.us","avatar":"https://gravatar.com/avatar/c2e53452caa53d940768a1ffc9cf76196d851b9b534b7a39cd39852a70a0508f?d=mp&s=160"},"body":"I am working on an open source project right now where we are looking to enforce a N of M audit approval process. It turns out that git supports verifying multiple signatures because gpg supports signature merging.\n\nMy question is how can this workflow best be added into git and if not added atleast supported.\n\nHere are the manual procedures (scripts are in the bundle too):\n\n> Procedures:\n> \n> 1. Identify a normal commit.\n> 2. create a new commit file as:\n> parent commit-id-of-step-1\n> tree tree-id-from-git-cat-file-commit-commit-id-of-step-1\n> author CipherShed Security Team <security@ciphershed.org> \n> timestamp timezone\n> committer Actual Person <username@ciphershed.org> timestamp timezone\n> gpgsig output-from-merge-sig-tool [1]\n>  more-output\n>  more-output\n> \n> Comments for this commit\n> ...\n> ...\n> \n> 3. run ruby script [2] to add commit to git db\n> 4. git update-ref refs/heads/BRANCH-NAME new-commit-id\n\nTo do this most properly I feel like there needs to be a way to \"share\" the repository state and intterrupt the commit process.\n\nComments?\n\n1: \n$ cat merge-multisigs.sh\n#!/bin/bash\n(\n for i in \"$@\"\n do\n  gpg --dearmor < \"$i\"\n done\n) | gpg --enarmor\n\n2:\n$ cat write-commit.ruby\n#!/usr/bin/irb\nrequire 'fileutils'\nfile = File.open(ARGV[0], \"rb\")\ncontent = file.read\nheader = \"commit #{content.length}\\0\"\nstore = header + content\nrequire 'digest/sha1'\nsha1 = Digest::SHA1.hexdigest(store)\nrequire 'zlib'\nzlib_content = Zlib::Deflate.deflate(store)\npath = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]\nFileUtils.mkdir_p(File.dirname(path))\nFile.open(path, 'w') { |f| f.write zlib_content }\n\n\nP.S. This was inspired by actual events and the parent thread.\n\n--\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n-                                                               -\n- Jason Pyeron                      PD Inc. http://www.pdinc.us -\n- Principal Consultant              10 West 24th Street #100    -\n- +1 (443) 269-1555 x333            Baltimore, Maryland 21218   -\n-                                                               -\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\nThis message is copyright PD Inc, subject to license 20080407P00.\n"},{"id":"247897","messageId":"20140819080510.GC7712@peff.net","threadId":"37326","inReplyTo":"DED50992A39F4A07ACD997A65602991E@black","subject":"Re: Signinig a commit with multiple signatures","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-08-19T08:05:11Z","receivedAt":"2014-08-19T08:05:11Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Aug 17, 2014 at 09:30:47AM -0400, Jason Pyeron wrote:\n\n> I am working on an open source project right now where we are looking\n> to enforce a N of M audit approval process. It turns out that git\n> supports verifying multiple signatures because gpg supports signature\n> merging.\n\nIn the scheme you propose, the commit object is actually rewritten. So\nwhoever made and signed it first will then need to rebase on top of the\nrewritten multi-signed version.\n\nIs there a reason not to use detached signatures, and let each person\nadd them after the fact? You can store them in git-notes and then push\nthem along with the other commits (you can even check in a pre-receive\nhook that the commits meet your N of M criteria, as long as everybody\nhas pushed up their signature notes).\n\n> $ cat write-commit.ruby\n> #!/usr/bin/irb\n> require 'fileutils'\n> file = File.open(ARGV[0], \"rb\")\n> content = file.read\n> header = \"commit #{content.length}\\0\"\n> store = header + content\n> require 'digest/sha1'\n> sha1 = Digest::SHA1.hexdigest(store)\n> require 'zlib'\n> zlib_content = Zlib::Deflate.deflate(store)\n> path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]\n> FileUtils.mkdir_p(File.dirname(path))\n> File.open(path, 'w') { |f| f.write zlib_content }\n\nI think this is just \"git hash-object -w -t commit <file>\", isn't it?\n\n-Peff\n"},{"id":"247908","messageId":"FC21F8BBC6EF41E1952CA340138A50D2@black","threadId":"37326","inReplyTo":"20140819080510.GC7712@peff.net","subject":"RE: Signinig a commit with multiple signatures","fromName":"Jason Pyeron","fromEmail":"jpyeron@pdinc.us","sentAt":"2014-08-19T13:09:36Z","receivedAt":"2014-08-19T13:09:36Z","isPatch":false,"sender":{"key":"jpyeron@pdinc.us","avatar":"https://gravatar.com/avatar/c2e53452caa53d940768a1ffc9cf76196d851b9b534b7a39cd39852a70a0508f?d=mp&s=160"},"body":"> -----Original Message-----\n> From: Jeff King\n> Sent: Tuesday, August 19, 2014 4:05\n> \n> On Sun, Aug 17, 2014 at 09:30:47AM -0400, Jason Pyeron wrote:\n> \n> > I am working on an open source project right now where we \n> are looking\n> > to enforce a N of M audit approval process. It turns out that git\n> > supports verifying multiple signatures because gpg supports \n> signature\n> > merging.\n> \n> In the scheme you propose, the commit object is actually rewritten. So\n> whoever made and signed it first will then need to rebase on \n> top of the\n> rewritten multi-signed version.\n\nNot exactly. A known and shared commit is used as the parent of an empty, no changes commit. The \"no changes\" commit object is taken and passed around before being added into the repository. There is no need for a rebase.\n\nBut my scheme uses out-of-band process to accomplish this. The idea of using git to \"distribute\" the conflict resolution seemed like a valid use case of sharing a working copy state for a distributed commit, just like this. [1][2]\n\n> \n> Is there a reason not to use detached signatures, and let each person\n\nYes. The embeded signatures provides the best user experience (UX) for verification.\n\n> add them after the fact? You can store them in git-notes and then push\n> them along with the other commits (you can even check in a pre-receive\n> hook that the commits meet your N of M criteria, as long as everybody\n> has pushed up their signature notes).\n> \n> > $ cat write-commit.ruby\n> > #!/usr/bin/irb\n> > require 'fileutils'\n> > file = File.open(ARGV[0], \"rb\")\n> > content = file.read\n> > header = \"commit #{content.length}\\0\"\n> > store = header + content\n> > require 'digest/sha1'\n> > sha1 = Digest::SHA1.hexdigest(store)\n> > require 'zlib'\n> > zlib_content = Zlib::Deflate.deflate(store)\n> > path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]\n> > FileUtils.mkdir_p(File.dirname(path))\n> > File.open(path, 'w') { |f| f.write zlib_content }\n> \n> I think this is just \"git hash-object -w -t commit <file>\", isn't it?\n\nLet me find the most complicated way of saying this, yes. I feel silly for that.\n\n-Jason\n\n[1]: http://git.661346.n2.nabble.com/Sharing-a-massive-distributed-merge-td6178696.html\n[2]: http://git.661346.n2.nabble.com/Sharing-merge-conflict-resolution-between-multiple-developers-td7616700.html\n"}]}