{"thread":{"id":"32313","subject":"[BUG] Cannot push some grafted branches","startedAt":"2012-12-11T14:39:03Z","lastAt":"2012-12-22T16:38:46Z","messageCount":29,"participants":["Yann Dirson","Junio C Hamano","Thomas Rast","Christian Couder","Andreas Schwab","Johannes Sixt","Jeff King","Michael J Gruber"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"204678","messageId":"20121211153903.7522d6b0@chalon.bertin.fr","threadId":"32313","inReplyTo":null,"subject":"[BUG] Cannot push some grafted branches","fromName":"Yann Dirson","fromEmail":"dirson@bertin.fr","sentAt":"2012-12-11T14:39:03Z","receivedAt":"2012-12-11T14:39:03Z","isPatch":false,"sender":{"key":"dirson@bertin.fr","avatar":null},"body":"There seems to be some bad interactions between git-push and grafts.\nThe problem seems to occur when a commit that exists in the remote\nrepo is subject to a graft in the local repo, and we try to push one\nof the fake parents.\n\nThe problem was first seen on 1.7.12.3 in a private repo, and I could\nreproduce it using 1.8.1.rc0, as shown below.  1.7.10.4 seems even\nmore affected, with something looking like a memory corruption issue.\n\nHere is the test:\n\n$ git clone git.git git-test\nCloning into 'git-test'...\ndone.\nChecking out files: 100% (2518/2518), done.\n$ cd git-test/\ngit-test$ git co maint\nBranch maint set up to track remote branch maint from origin.\nSwitched to a new branch 'maint'\ngit-test$ echo >> README \ngit-test$ git commit -a -m \"test\"\n[maint 0708279] test\n 1 file changed, 1 insertion(+)\ngit-test$ echo $(git rev-parse origin/master; git rev-parse origin/master^; git rev-parse HEAD) > .git/info/grafts\n\ngit-test$ git version\ngit version 1.8.1.rc0\ngit-test$ git push origin maint\nTotal 0 (delta 0), reused 0 (delta 0)\nfatal: bad object 0708279e168b52003234dd23601796b3b12e278b\nfatal: bad object 0708279e168b52003234dd23601796b3b12e278b\nTo /home/localadm/softs/git.git\n ! [remote rejected] maint -> maint (missing necessary objects)\nerror: failed to push some refs to '/home/localadm/softs/git.git'\n\n\n$ git version\ngit version 1.7.10.4\n\ngit-test$ git push origin maint\nTotal 0 (delta 0), reused 0 (delta 0)\nfatal: bad object 0708279e168b52003234dd23601796b3b12e278b\nfatal: bad object 0708279e168b52003234dd23601796b3b12e278b\nAuto packing the repository for optimum performance.\nfatal: protocol error: bad line length character: Remo\nerror: error in sideband demultiplexer\nerror: ૏        >S��ŋJ�jB�;�x'��R died of signal 13\nTo /home/localadm/softs/git.git\n ! [remote rejected] maint -> maint (missing necessary objects)\nerror: failed to push some refs to '/home/localadm/softs/git.git'\n\n-- \nYann Dirson - Bertin Technologies\n"},{"id":"204681","messageId":"7vd2yg8ngk.fsf@alter.siamese.dyndns.org","threadId":"32313","inReplyTo":"20121211153903.7522d6b0@chalon.bertin.fr","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-12-11T18:15:23Z","receivedAt":"2012-12-11T18:15:23Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Yann Dirson <dirson@bertin.fr> writes:\n\n> There seems to be some bad interactions between git-push and grafts.\n> The problem seems to occur when a commit that exists in the remote\n> repo is subject to a graft in the local repo, and we try to push one\n> of the fake parents.\n\nHistory tweaking by grafts is only visible inside your local\nrepository and objects are not rewritten, and grafts are not\ntransferred across repositories.  They were invented to be used as a\nstop-gap measure until you filter-branch the history before\npublishing (or if you do not publish, then you can keep using your\nlocal grafts).\n\nIsn't this well known?  Perhaps we would need to document it better.\n\nWhat you can do is to use \"replace\" instead and publish the replace\nrefs, I think.  Object transfer will then follow the true parenthood\nconnectivity and people who choose to use the same replacement as\nyou do can fetch the replace ref from you (this will grab objects\nnecessary to complete the alternative history) and install it.\n"},{"id":"204722","messageId":"20121212094432.6e1e48c8@chalon.bertin.fr","threadId":"32313","inReplyTo":"7vd2yg8ngk.fsf@alter.siamese.dyndns.org","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Yann Dirson","fromEmail":"dirson@bertin.fr","sentAt":"2012-12-12T08:44:32Z","receivedAt":"2012-12-12T08:44:32Z","isPatch":false,"sender":{"key":"dirson@bertin.fr","avatar":null},"body":"On Tue, 11 Dec 2012 10:15:23 -0800\nJunio C Hamano <gitster@pobox.com> wrote:\n\n> Yann Dirson <dirson@bertin.fr> writes:\n> \n> > There seems to be some bad interactions between git-push and grafts.\n> > The problem seems to occur when a commit that exists in the remote\n> > repo is subject to a graft in the local repo, and we try to push one\n> > of the fake parents.\n> \n> History tweaking by grafts is only visible inside your local\n> repository and objects are not rewritten, and grafts are not\n> transferred across repositories.  They were invented to be used as a\n> stop-gap measure until you filter-branch the history before\n> publishing (or if you do not publish, then you can keep using your\n> local grafts).\n> \n> Isn't this well known?  Perhaps we would need to document it better.\n\nI am well aware of that, and did not intend to push any grafted commit.\nI am attempting to push a well-formed commit, which happens to be used as\na grafted commit's fake parent, and my interpretation is that git reacts\nas if it was considering that the remote already had that commit, possibly\nbecause it would not ignore grafts when deciding which commits are already\nknown to the remote.\n\n> What you can do is to use \"replace\" instead and publish the replace\n> refs, I think.  Object transfer will then follow the true parenthood\n> connectivity and people who choose to use the same replacement as\n> you do can fetch the replace ref from you (this will grab objects\n> necessary to complete the alternative history) and install it.\n\nI am only using grafts as a temporary and lightweight drafting area,\nbefore setting the results in stone - although in my case it will be\nwith filter-branch rather than replace, but the idea is the same.  I just\ngot bitten when attempting to push a valid branch while the grafts were in\neffect, when in fact they should have had no influence at all.\n\nIn fact, I even looked for a way to specify an alternate (or supplementary)\ngrafts file for this drafting work, so only well-controlled git invocations\nwould see them, whereas the others would just ignore them, and could not find\nany - nor could I identify an existing way of disabling the use of grafts by\nother means than moving it out of the way.  In this respect, they seem to be\nlacking a few features, when compared to \"replace\" refs, but they have different\nuses, and just using the latter as a drafting area is just not adequate.\n\nI thought about adding support for a GIT_GRAFTS_FILE envvar, which would\ndefault to $GITDIR/info/grafts, or maybe with a more general addition of a\nGIT_EXTRA_GRAFT_FILES envvar, but I'm not sure the latter would be that useful.\n\n-- \nYann Dirson - Bertin Technologies\n"},{"id":"204724","messageId":"20121212115423.3db6bb4d@chalon.bertin.fr","threadId":"32313","inReplyTo":"20121212094432.6e1e48c8@chalon.bertin.fr","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Yann Dirson","fromEmail":"dirson@bertin.fr","sentAt":"2012-12-12T10:54:23Z","receivedAt":"2012-12-12T10:54:23Z","isPatch":false,"sender":{"key":"dirson@bertin.fr","avatar":null},"body":"On Wed, 12 Dec 2012 09:44:32 +0100 Yann Dirson <dirson@bertin.fr> wrote:\n> In fact, I even looked for a way to specify an alternate (or supplementary)\n> grafts file for this drafting work, so only well-controlled git invocations\n> would see them, whereas the others would just ignore them, and could not find\n> any - nor could I identify an existing way of disabling the use of grafts by\n> other means than moving it out of the way.  In this respect, they seem to be\n> lacking a few features, when compared to \"replace\" refs, but they have different\n> uses, and just using the latter as a drafting area is just not adequate.\n> \n> I thought about adding support for a GIT_GRAFTS_FILE envvar, which would\n> default to $GITDIR/info/grafts, or maybe with a more general addition of a\n> GIT_EXTRA_GRAFT_FILES envvar, but I'm not sure the latter would be that useful.\n\nMy bad on this point: there *is* a GIT_GRAFT_FILE envvar, it is just undocumented.\nIn fact it is not the only one:\n\ngit.git$ for v in $(git grep define.*_ENVIRONMENT master -- cache.h | cut -d'\"' -f2|grep ^GIT_); do git grep -q $v master -- Documentation || echo \"missing $v\"; done\nmissing GIT_GRAFT_FILE\nmissing GIT_CONFIG_PARAMETERS\n\n\n-- \nYann Dirson - Bertin Technologies\n"},{"id":"204779","messageId":"7v38zb3ux0.fsf@alter.siamese.dyndns.org","threadId":"32313","inReplyTo":"20121212094432.6e1e48c8@chalon.bertin.fr","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-12-12T19:57:47Z","receivedAt":"2012-12-12T19:57:47Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Yann Dirson <dirson@bertin.fr> writes:\n\n> ....  In this respect, they seem to be\n> lacking a few features, when compared to \"replace\" refs, but they have different\n> uses, ...\n\nNot reallyl; grafts were old hack whose use is still supported with\nits original limitations; replace is meant to replace all uses of\ngrafts while removing grafts' largest warts.\n"},{"id":"205030","messageId":"20121217085242.02a77243@chalon.bertin.fr","threadId":"32313","inReplyTo":"7v38zb3ux0.fsf@alter.siamese.dyndns.org","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Yann Dirson","fromEmail":"dirson@bertin.fr","sentAt":"2012-12-17T07:52:42Z","receivedAt":"2012-12-17T07:52:42Z","isPatch":false,"sender":{"key":"dirson@bertin.fr","avatar":null},"body":"On Wed, 12 Dec 2012 11:57:47 -0800\nJunio C Hamano <gitster@pobox.com> wrote:\n\n> Yann Dirson <dirson@bertin.fr> writes:\n> \n> > ....  In this respect, they seem to be\n> > lacking a few features, when compared to \"replace\" refs, but they have different\n> > uses, ...\n> \n> Not reallyl; grafts were old hack whose use is still supported with\n> its original limitations; replace is meant to replace all uses of\n> grafts while removing grafts' largest warts.\n\nOK, I'll take this into account.\n\nBut this situation should probably be make more clear in the docs.  Currently,\ngitrepository-layout.txt describes refs/replace/ (and shallow) by reference to grafts,\nand those are not marked as discouraged-use or anything.\n\nAnd we may still want the bug fixed, or would we just list it as a known bug ?\nAt least it does not seem to occur with \"replace\" refs:\n\ngit-test$ rm .git/info/grafts \ngit-test$ echo \"fake merge\" | git commit-tree master^{tree} -p master^ -p maint\nb821b2aa00973a47936d7cd25c9a5978b1c839c6\ngit-test$ git replace master b821b2aa00973a47936d7cd25c9a5978b1c839c6\ngit-test$ git push origin maint\n...\n   50b03b0..79211fe  maint -> maint\n\n-- \nYann Dirson - Bertin Technologies\n"},{"id":"205033","messageId":"877goht6eu.fsf@pctrast.inf.ethz.ch","threadId":"32313","inReplyTo":"7v38zb3ux0.fsf@alter.siamese.dyndns.org","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2012-12-17T08:43:53Z","receivedAt":"2012-12-17T08:43:53Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Yann Dirson <dirson@bertin.fr> writes:\n>\n>> ....  In this respect, they seem to be\n>> lacking a few features, when compared to \"replace\" refs, but they have different\n>> uses, ...\n>\n> Not reallyl; grafts were old hack whose use is still supported with\n> its original limitations; replace is meant to replace all uses of\n> grafts while removing grafts' largest warts.\n\nI suppose there's the additional issue that grafts are much easier to\nuse than replacements if you really only want to replace some parent\nlists.  With replace you need to handcraft the replacement commits, and\ngit-replace(1) unhelpfully does not say this, much less gives an example\nhow to do it.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"205036","messageId":"7vfw35m509.fsf@alter.siamese.dyndns.org","threadId":"32313","inReplyTo":"20121217085242.02a77243@chalon.bertin.fr","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-12-17T08:56:06Z","receivedAt":"2012-12-17T08:56:06Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Yann Dirson <dirson@bertin.fr> writes:\n\n> And we may still want the bug fixed, or would we just list it as a known bug ?\n> At least it does not seem to occur with \"replace\" refs:\n\nThe \"replace\" was designed to \"fix\" known limitation of grafts,\nwhich is _inherent_ to it; the graft information was designed _not_\nto be shared across repositories.  The fix was done by by using a\ndifferent mechanism to allow propagating the information across\nrepositories.\n\nSo there is nothing further to fix, except that there is a documentation\nbug you can fix if you didn't find it documented.\n\nThanks.\n\n>\n> git-test$ rm .git/info/grafts \n> git-test$ echo \"fake merge\" | git commit-tree master^{tree} -p master^ -p maint\n> b821b2aa00973a47936d7cd25c9a5978b1c839c6\n> git-test$ git replace master b821b2aa00973a47936d7cd25c9a5978b1c839c6\n> git-test$ git push origin maint\n> ...\n>    50b03b0..79211fe  maint -> maint\n"},{"id":"205043","messageId":"20121217113036.7745f956@chalon.bertin.fr","threadId":"32313","inReplyTo":"7vfw35m509.fsf@alter.siamese.dyndns.org","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Yann Dirson","fromEmail":"dirson@bertin.fr","sentAt":"2012-12-17T10:30:36Z","receivedAt":"2012-12-17T10:30:36Z","isPatch":false,"sender":{"key":"dirson@bertin.fr","avatar":null},"body":"On Mon, 17 Dec 2012 00:56:06 -0800\nJunio C Hamano <gitster@pobox.com> wrote:\n\n> Yann Dirson <dirson@bertin.fr> writes:\n> \n> > And we may still want the bug fixed, or would we just list it as a known bug ?\n> > At least it does not seem to occur with \"replace\" refs:\n> \n> The \"replace\" was designed to \"fix\" known limitation of grafts,\n> which is _inherent_ to it; the graft information was designed _not_\n> to be shared across repositories.  The fix was done by by using a\n> different mechanism to allow propagating the information across\n> repositories.\n\nI see.  But from what I observed (without looking at the source), it looks like\nwhen determining which commits are to be pushed, the grafts file is not \"neutralized\"\nas it should.\n\n> So there is nothing further to fix, except that there is a documentation\n> bug you can fix if you didn't find it documented.\n\nWill do.\n\n> Thanks.\n> \n> >\n> > git-test$ rm .git/info/grafts \n> > git-test$ echo \"fake merge\" | git commit-tree master^{tree} -p master^ -p maint\n> > b821b2aa00973a47936d7cd25c9a5978b1c839c6\n> > git-test$ git replace master b821b2aa00973a47936d7cd25c9a5978b1c839c6\n> > git-test$ git push origin maint\n> > ...\n> >    50b03b0..79211fe  maint -> maint\n\n\n-- \nYann Dirson - Bertin Technologies\n"},{"id":"205044","messageId":"20121217114058.449cbc3c@chalon.bertin.fr","threadId":"32313","inReplyTo":"877goht6eu.fsf@pctrast.inf.ethz.ch","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Yann Dirson","fromEmail":"dirson@bertin.fr","sentAt":"2012-12-17T10:40:58Z","receivedAt":"2012-12-17T10:40:58Z","isPatch":false,"sender":{"key":"dirson@bertin.fr","avatar":null},"body":"On Mon, 17 Dec 2012 09:43:53 +0100\nThomas Rast <trast@student.ethz.ch> wrote:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n> > Yann Dirson <dirson@bertin.fr> writes:\n> >\n> >> ....  In this respect, they seem to be\n> >> lacking a few features, when compared to \"replace\" refs, but they have different\n> >> uses, ...\n> >\n> > Not reallyl; grafts were old hack whose use is still supported with\n> > its original limitations; replace is meant to replace all uses of\n> > grafts while removing grafts' largest warts.\n> \n> I suppose there's the additional issue that grafts are much easier to\n> use than replacements if you really only want to replace some parent\n> lists.  With replace you need to handcraft the replacement commits, and\n> git-replace(1) unhelpfully does not say this, much less gives an example\n> how to do it.\n> \n\nRight, replace refs can surely be made easier to use.  The requirement to craft a\nnew commit manually is a major step back in ease of use.\n\nMaybe something like \"git replace -p <orig-commit> <parent>...\" to just provide a simple\nAPI to the exact graft functionnality would be good.  But it would be commit-specific, whereas\nreplace refs are indeed more generic, and, one could want to rewrite any other part of the commit,\nso we could prefer a more general mechanism.\n\nSomething that could be useful in this respect, would be an --amend like option to git-commit, like\n\"git commit --replace\".  But unfortunately it does not allow to change parents, and it has the\ndrawback of requiring that HEAD points to the commit to be replaced.\n\nSo maybe, if there are no other idea, a simple \"git graft\" command that would wrap \"git replace\",\nwould fill the gap.\n\n-- \nYann Dirson - Bertin Technologies\n"},{"id":"205056","messageId":"CAP8UFD2pkotNy=t5wTxDH-pMivQsTz-kw2y8Y7rWY42YKabp7g@mail.gmail.com","threadId":"32313","inReplyTo":"20121217114058.449cbc3c@chalon.bertin.fr","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2012-12-17T13:43:59Z","receivedAt":"2012-12-17T13:43:59Z","isPatch":false,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Hi Yann,\n\nOn Mon, Dec 17, 2012 at 11:40 AM, Yann Dirson <dirson@bertin.fr> wrote:\n> On Mon, 17 Dec 2012 09:43:53 +0100\n> Thomas Rast <trast@student.ethz.ch> wrote:\n>\n>> Junio C Hamano <gitster@pobox.com> writes:\n>>\n>>\n>> I suppose there's the additional issue that grafts are much easier to\n>> use than replacements if you really only want to replace some parent\n>> lists.  With replace you need to handcraft the replacement commits, and\n>> git-replace(1) unhelpfully does not say this, much less gives an example\n>> how to do it.\n>>\n>\n> Right, replace refs can surely be made easier to use.  The requirement to craft a\n> new commit manually is a major step back in ease of use.\n\nYeah, at one point I wanted to have a command that created to craft a\nnew commit based on an existing one.\nPerhaps it could be useful when using filter-branch or perhaps it\ncould reuse some filter-branch code.\n\n> Maybe something like \"git replace -p <orig-commit> <parent>...\" to just provide a simple\n> API to the exact graft functionnality would be good.  But it would be commit-specific, whereas\n> replace refs are indeed more generic, and, one could want to rewrite any other part of the commit,\n> so we could prefer a more general mechanism.\n\nYeah I wondered at one point if something like the following would do:\n\ngit replace --parent <parent1> --parent <parent2> --author <author>\n--commiter <commiter> ... <orig-commit>\n\n> Something that could be useful in this respect, would be an --amend like option to git-commit, like\n> \"git commit --replace\".  But unfortunately it does not allow to change parents, and it has the\n> drawback of requiring that HEAD points to the commit to be replaced.\n>\n> So maybe, if there are no other idea, a simple \"git graft\" command that would wrap \"git replace\",\n> would fill the gap.\n\nIt would not be straightforward to call it \"graft\" if it uses git replace.\n\nBest,\nChristian.\n"},{"id":"205057","messageId":"20121217150230.545a3938@chalon.bertin.fr","threadId":"32313","inReplyTo":"CAP8UFD2pkotNy=t5wTxDH-pMivQsTz-kw2y8Y7rWY42YKabp7g@mail.gmail.com","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Yann Dirson","fromEmail":"dirson@bertin.fr","sentAt":"2012-12-17T14:02:30Z","receivedAt":"2012-12-17T14:02:30Z","isPatch":false,"sender":{"key":"dirson@bertin.fr","avatar":null},"body":"On Mon, 17 Dec 2012 14:43:59 +0100\nChristian Couder <christian.couder@gmail.com> wrote:\n\n> Hi Yann,\n> \n> On Mon, Dec 17, 2012 at 11:40 AM, Yann Dirson <dirson@bertin.fr> wrote:\n> > On Mon, 17 Dec 2012 09:43:53 +0100\n> > Thomas Rast <trast@student.ethz.ch> wrote:\n> >\n> >> Junio C Hamano <gitster@pobox.com> writes:\n> >>\n> >>\n> >> I suppose there's the additional issue that grafts are much easier to\n> >> use than replacements if you really only want to replace some parent\n> >> lists.  With replace you need to handcraft the replacement commits, and\n> >> git-replace(1) unhelpfully does not say this, much less gives an example\n> >> how to do it.\n> >>\n> >\n> > Right, replace refs can surely be made easier to use.  The requirement to craft a\n> > new commit manually is a major step back in ease of use.\n> \n> Yeah, at one point I wanted to have a command that created to craft a\n> new commit based on an existing one.\n> Perhaps it could be useful when using filter-branch or perhaps it\n> could reuse some filter-branch code.\n> \n> > Maybe something like \"git replace -p <orig-commit> <parent>...\" to just provide a simple\n> > API to the exact graft functionnality would be good.  But it would be commit-specific, whereas\n> > replace refs are indeed more generic, and, one could want to rewrite any other part of the commit,\n> > so we could prefer a more general mechanism.\n> \n> Yeah I wondered at one point if something like the following would do:\n> \n> git replace --parent <parent1> --parent <parent2> --author <author>\n> --commiter <commiter> ... <orig-commit>\n\nYes, modification flags, that would only be allowed when the objects are commits, \nand would cause creation of a replace commit that's <orig-commit> plus modifications.\nWe could then reuse the relevant options from git-commit, and add the missing --parent.\n\nBut wouldn't it stretch git-replace too much, to add commit-specific behaviour there ?\n\n> > Something that could be useful in this respect, would be an --amend like option to git-commit, like\n> > \"git commit --replace\".  But unfortunately it does not allow to change parents, and it has the\n> > drawback of requiring that HEAD points to the commit to be replaced.\n> >\n> > So maybe, if there are no other idea, a simple \"git graft\" command that would wrap \"git replace\",\n> > would fill the gap.\n> \n> It would not be straightforward to call it \"graft\" if it uses git replace.\n\nWell, \"git replace\" would just be the \"implementation detail\".  The idea would be to keep\nthe concept of a \"graft\", and just change its implementation.  If we care (and we surely\ndo not, it's just a thought experiment ;), we could even provide, for pre-replace gits, a\n\"git graft\" implementation that would manipulate info/grafts, together with a docpatch\nsaying that direct manipulation of info/grafts is deprecated.\n\n-- \nYann Dirson - Bertin Technologies\n"},{"id":"205070","messageId":"m21ueo78f8.fsf@igel.home","threadId":"32313","inReplyTo":"CAP8UFD2pkotNy=t5wTxDH-pMivQsTz-kw2y8Y7rWY42YKabp7g@mail.gmail.com","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Andreas Schwab","fromEmail":"schwab@linux-m68k.org","sentAt":"2012-12-17T20:03:39Z","receivedAt":"2012-12-17T20:03:39Z","isPatch":false,"sender":{"key":"schwab@linux-m68k.org","avatar":"https://avatars.githubusercontent.com/u/2175493?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> Yeah, at one point I wanted to have a command that created to craft a\n> new commit based on an existing one.\n\nThis isn't hard to do, you only have to resort to plumbing:\n\n$ git cat-file commit fef11965da875c105c40f1a9550af1f5e34a6e62 | sed s/bfae342c973b0be3c9e99d3d86ed2e6b152b4a6b/790c83cda92f95f1b4b91e2ddc056a52a99a055d/ | git hash-object -t commit --stdin -w\nbb45cc6356eac6c7fa432965090045306dab7026\n\nAndreas.\n\n-- \nAndreas Schwab, schwab@linux-m68k.org\nGPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5\n\"And now for something completely different.\"\n"},{"id":"205076","messageId":"7vwqwgjs8f.fsf@alter.siamese.dyndns.org","threadId":"32313","inReplyTo":"m21ueo78f8.fsf@igel.home","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-12-17T21:14:56Z","receivedAt":"2012-12-17T21:14:56Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andreas Schwab <schwab@linux-m68k.org> writes:\n\n> Christian Couder <christian.couder@gmail.com> writes:\n>\n>> Yeah, at one point I wanted to have a command that created to craft a\n>> new commit based on an existing one.\n>\n> This isn't hard to do, you only have to resort to plumbing:\n>\n> $ git cat-file commit fef11965da875c105c40f1a9550af1f5e34a6e62 | sed s/bfae342c973b0be3c9e99d3d86ed2e6b152b4a6b/790c83cda92f95f1b4b91e2ddc056a52a99a055d/ | git hash-object -t commit --stdin -w\n> bb45cc6356eac6c7fa432965090045306dab7026\n\nGood.  I do not think an extra special-purpose command is welcome\nhere.\n"},{"id":"205114","messageId":"20121218120058.0c558ba5@chalon.bertin.fr","threadId":"32313","inReplyTo":"7vwqwgjs8f.fsf@alter.siamese.dyndns.org","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Yann Dirson","fromEmail":"dirson@bertin.fr","sentAt":"2012-12-18T11:00:58Z","receivedAt":"2012-12-18T11:00:58Z","isPatch":false,"sender":{"key":"dirson@bertin.fr","avatar":null},"body":"On Mon, 17 Dec 2012 13:14:56 -0800\nJunio C Hamano <gitster@pobox.com> wrote:\n\n> Andreas Schwab <schwab@linux-m68k.org> writes:\n> \n> > Christian Couder <christian.couder@gmail.com> writes:\n> >\n> >> Yeah, at one point I wanted to have a command that created to craft a\n> >> new commit based on an existing one.\n> >\n> > This isn't hard to do, you only have to resort to plumbing:\n> >\n> > $ git cat-file commit fef11965da875c105c40f1a9550af1f5e34a6e62 | sed s/bfae342c973b0be3c9e99d3d86ed2e6b152b4a6b/790c83cda92f95f1b4b91e2ddc056a52a99a055d/ | git hash-object -t commit --stdin -w\n> > bb45cc6356eac6c7fa432965090045306dab7026\n> \n> Good.  I do not think an extra special-purpose command is welcome\n> here.\n\nWell, I'm not sure this is intuitive enough to be useful to the average user :)\nAdding git-rev-parse calls for convenience, and calling git-replace, would make it\na more complete recipe, and we could suggest that as an alias in the collection that's\nin the wiki (which is not even linked any more from git-scm.com btw), but imho that\nwould be hiding valuable information in a dark corner.\n\nAnyway, in this form it will only replace a parent with another, whereas a full\ngraft replacement should allow to write a different number of new parents instead.\nThat is, instead of this simple sed, something like:\n\n(NEWPARENTS='parent xxx\\nparent yyy\\nparent zzz\\n; git cat-file commit master | perl -ne 'BEGIN { $state=0 }; if ($state eq 0) { if (/^parent/) { $state=1 } else { print } } elsif ($state eq 1) { if (/^author/) { print \"'\"$NEWPARENTS\"'\"; print; $state=2 } } else { print }')\n\nWell, a short bash script should be more readable and possibly faster, but that's the\nidea.  Such a script could be a candidate for contrib ?\n-- \nYann Dirson - Bertin Technologies\n"},{"id":"205115","messageId":"50D05BAF.4000200@viscovery.net","threadId":"32313","inReplyTo":"20121218120058.0c558ba5@chalon.bertin.fr","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2012-12-18T12:03:59Z","receivedAt":"2012-12-18T12:03:59Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 12/18/2012 12:00, schrieb Yann Dirson:\n> On Mon, 17 Dec 2012 13:14:56 -0800\n> Junio C Hamano <gitster@pobox.com> wrote:\n> \n>> Andreas Schwab <schwab@linux-m68k.org> writes:\n>>\n>>> Christian Couder <christian.couder@gmail.com> writes:\n>>>\n>>>> Yeah, at one point I wanted to have a command that created to craft a\n>>>> new commit based on an existing one.\n>>>\n>>> This isn't hard to do, you only have to resort to plumbing:\n>>>\n>>> $ git cat-file commit fef11965da875c105c40f1a9550af1f5e34a6e62 | sed s/bfae342c973b0be3c9e99d3d86ed2e6b152b4a6b/790c83cda92f95f1b4b91e2ddc056a52a99a055d/ | git hash-object -t commit --stdin -w\n>>> bb45cc6356eac6c7fa432965090045306dab7026\n>>\n>> Good.  I do not think an extra special-purpose command is welcome\n>> here.\n> \n> Well, I'm not sure this is intuitive enough to be useful to the average user :)\n\nWhen I played with git-replace in the past, I imagined that it could be\n\n   git replace <object> --commit ...commit options...\n\nthat would do the trick.\n\nWe could implement it with a git-replace--commit helper script that\ngenerates the replacement commit using the ...commit options... (to be\ndefined what this should be), and git-replace would just pick its output\n(the SHA1 of the generated commit) as a substitute for the <replacement>\nargument that would have to be given without the --commit option.\n\n-- Hannes\n"},{"id":"205117","messageId":"871uentthz.fsf@pctrast.inf.ethz.ch","threadId":"32313","inReplyTo":"50D05BAF.4000200@viscovery.net","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Thomas Rast","fromEmail":"trast@inf.ethz.ch","sentAt":"2012-12-18T12:49:44Z","receivedAt":"2012-12-18T12:49:44Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Johannes Sixt <j.sixt@viscovery.net> writes:\n\n> Am 12/18/2012 12:00, schrieb Yann Dirson:\n>> On Mon, 17 Dec 2012 13:14:56 -0800\n>> Junio C Hamano <gitster@pobox.com> wrote:\n>> \n>>> Andreas Schwab <schwab@linux-m68k.org> writes:\n>>>\n>>>> Christian Couder <christian.couder@gmail.com> writes:\n>>>>\n>>>>> Yeah, at one point I wanted to have a command that created to craft a\n>>>>> new commit based on an existing one.\n>>>>\n>>>> This isn't hard to do, you only have to resort to plumbing:\n>>>>\n>>>> $ git cat-file commit fef11965da875c105c40f1a9550af1f5e34a6e62 |\n>>>> sed\n>>>> s/bfae342c973b0be3c9e99d3d86ed2e6b152b4a6b/790c83cda92f95f1b4b91e2ddc056a52a99a055d/\n>>>> | git hash-object -t commit --stdin -w\n>>>> bb45cc6356eac6c7fa432965090045306dab7026\n>>>\n>>> Good.  I do not think an extra special-purpose command is welcome\n>>> here.\n>> \n>> Well, I'm not sure this is intuitive enough to be useful to the average user :)\n>\n> When I played with git-replace in the past, I imagined that it could be\n>\n>    git replace <object> --commit ...commit options...\n>\n> that would do the trick.\n>\n> We could implement it with a git-replace--commit helper script that\n> generates the replacement commit using the ...commit options... (to be\n> defined what this should be), and git-replace would just pick its output\n> (the SHA1 of the generated commit) as a substitute for the <replacement>\n> argument that would have to be given without the --commit option.\n\nI wouldn't even want a script -- we'd end up inventing a complicated\ncommand-line editor for what can simply be done by judicious use of an\nactual text editor.  How about something like the following?\n\n\n Documentation/git-replace.txt | 21 +++++++++++++++++++++\n 1 file changed, 21 insertions(+)\n\ndiff --git i/Documentation/git-replace.txt w/Documentation/git-replace.txt\nindex 51131d0..2502118 100644\n--- i/Documentation/git-replace.txt\n+++ w/Documentation/git-replace.txt\n@@ -61,6 +61,27 @@ OPTIONS\n \tTyping \"git replace\" without arguments, also lists all replace\n \trefs.\n \n+\n+EXAMPLE\n+-------\n+\n+Replacements (and before them, grafts) are often used to replace the\n+parent list of a commit.  Since commits are stored in a human-readable\n+format, you can in fact change any property using the following\n+recipe:\n+\n+------------------------------------------------\n+$ git cat-file commit original_commit >tmp\n+$ vi tmp\n+------------------------------------------------\n+In the editor, adjust the commit as needed.  For example, you can edit\n+the parent lists by adding/removing lines starting with \"parent\".\n+When done, replace the original commit with the edited one:\n+------------------------------------------------\n+$ git replace original_commit $(git hash-object -w tmp)\n+------------------------------------------------\n+\n+\n BUGS\n ----\n Comparing blobs or trees that have been replaced with those that\n\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"205118","messageId":"20121218144157.00ccd915@chalon.bertin.fr","threadId":"32313","inReplyTo":"871uentthz.fsf@pctrast.inf.ethz.ch","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Yann Dirson","fromEmail":"dirson@bertin.fr","sentAt":"2012-12-18T13:41:57Z","receivedAt":"2012-12-18T13:41:57Z","isPatch":false,"sender":{"key":"dirson@bertin.fr","avatar":null},"body":"On Tue, 18 Dec 2012 13:49:44 +0100\nThomas Rast <trast@inf.ethz.ch> wrote:\n\n> Johannes Sixt <j.sixt@viscovery.net> writes:\n> \n> > Am 12/18/2012 12:00, schrieb Yann Dirson:\n> >> On Mon, 17 Dec 2012 13:14:56 -0800\n> >> Junio C Hamano <gitster@pobox.com> wrote:\n> >> \n> >>> Andreas Schwab <schwab@linux-m68k.org> writes:\n> >>>\n> >>>> Christian Couder <christian.couder@gmail.com> writes:\n> >>>>\n> >>>>> Yeah, at one point I wanted to have a command that created to craft a\n> >>>>> new commit based on an existing one.\n> >>>>\n> >>>> This isn't hard to do, you only have to resort to plumbing:\n> >>>>\n> >>>> $ git cat-file commit fef11965da875c105c40f1a9550af1f5e34a6e62 |\n> >>>> sed\n> >>>> s/bfae342c973b0be3c9e99d3d86ed2e6b152b4a6b/790c83cda92f95f1b4b91e2ddc056a52a99a055d/\n> >>>> | git hash-object -t commit --stdin -w\n> >>>> bb45cc6356eac6c7fa432965090045306dab7026\n> >>>\n> >>> Good.  I do not think an extra special-purpose command is welcome\n> >>> here.\n> >> \n> >> Well, I'm not sure this is intuitive enough to be useful to the average user :)\n> >\n> > When I played with git-replace in the past, I imagined that it could be\n> >\n> >    git replace <object> --commit ...commit options...\n> >\n> > that would do the trick.\n> >\n> > We could implement it with a git-replace--commit helper script that\n> > generates the replacement commit using the ...commit options... (to be\n> > defined what this should be), and git-replace would just pick its output\n> > (the SHA1 of the generated commit) as a substitute for the <replacement>\n> > argument that would have to be given without the --commit option.\n> \n> I wouldn't even want a script -- we'd end up inventing a complicated\n> command-line editor for what can simply be done by judicious use of an\n> actual text editor.  How about something like the following?\n\nWell, while it does the job, it is still hardly as straightforward as the\nold \"vi .git/info/grafts\", or as a single easily-remembered commandline.\n\nI was again thinking the only commandline stuff that does not exist currently in\ngit-commit is specifying parents.  One possiblity would be to add such an\noption to git-commit, together with a --replace flag that would cause the\nnew commit to attached a replace ref (not completely unlike --append, in that\nwe're doing some non-default action instead of just adding the changes to a\nnew commit).\n\nBut well, I don't think we would want to add to git-commit the ability of playing\nwith something else than what's in the index/worktree.  Abstracting the commit\ncommandline to make it reusable by a git-replace--commit and possibly other tools\nthat may want to rw-manipulate arbitrary commits could make sense ?\n\n\n> \n>  Documentation/git-replace.txt | 21 +++++++++++++++++++++\n>  1 file changed, 21 insertions(+)\n> \n> diff --git i/Documentation/git-replace.txt w/Documentation/git-replace.txt\n> index 51131d0..2502118 100644\n> --- i/Documentation/git-replace.txt\n> +++ w/Documentation/git-replace.txt\n> @@ -61,6 +61,27 @@ OPTIONS\n>  \tTyping \"git replace\" without arguments, also lists all replace\n>  \trefs.\n>  \n> +\n> +EXAMPLE\n> +-------\n> +\n> +Replacements (and before them, grafts) are often used to replace the\n> +parent list of a commit.  Since commits are stored in a human-readable\n> +format, you can in fact change any property using the following\n> +recipe:\n> +\n> +------------------------------------------------\n> +$ git cat-file commit original_commit >tmp\n> +$ vi tmp\n> +------------------------------------------------\n> +In the editor, adjust the commit as needed.  For example, you can edit\n> +the parent lists by adding/removing lines starting with \"parent\".\n> +When done, replace the original commit with the edited one:\n> +------------------------------------------------\n> +$ git replace original_commit $(git hash-object -w tmp)\n\nYou probably meant \"-t commit\" - a sign that it's not so trivial to forge ?\n\n> +------------------------------------------------\n> +\n> +\n>  BUGS\n>  ----\n>  Comparing blobs or trees that have been replaced with those that\n> \n> \n\n\n-- \nYann Dirson - Bertin Technologies\n"},{"id":"205119","messageId":"87txrjsa8o.fsf@pctrast.inf.ethz.ch","threadId":"32313","inReplyTo":"20121218144157.00ccd915@chalon.bertin.fr","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Thomas Rast","fromEmail":"trast@inf.ethz.ch","sentAt":"2012-12-18T14:31:03Z","receivedAt":"2012-12-18T14:31:03Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Yann Dirson <dirson@bertin.fr> writes:\n\n>> +EXAMPLE\n>> +-------\n>> +\n>> +Replacements (and before them, grafts) are often used to replace the\n>> +parent list of a commit.  Since commits are stored in a human-readable\n>> +format, you can in fact change any property using the following\n>> +recipe:\n>> +\n>> +------------------------------------------------\n>> +$ git cat-file commit original_commit >tmp\n>> +$ vi tmp\n>> +------------------------------------------------\n>> +In the editor, adjust the commit as needed.  For example, you can edit\n>> +the parent lists by adding/removing lines starting with \"parent\".\n>> +When done, replace the original commit with the edited one:\n>> +------------------------------------------------\n>> +$ git replace original_commit $(git hash-object -w tmp)\n>\n> You probably meant \"-t commit\" - a sign that it's not so trivial to forge ?\n\nMostly a sign that despite my testing efforts, I still fail at\ncut&paste...\n\nBut yes, it absolutely needs -t commit.  Otherwise the commit would be\nreplaced by a blob, and confusion ensues.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"205127","messageId":"7vehinibpc.fsf@alter.siamese.dyndns.org","threadId":"32313","inReplyTo":"20121218120058.0c558ba5@chalon.bertin.fr","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-12-18T16:09:35Z","receivedAt":"2012-12-18T16:09:35Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Yann Dirson <dirson@bertin.fr> writes:\n\n> On Mon, 17 Dec 2012 13:14:56 -0800\n> Junio C Hamano <gitster@pobox.com> wrote:\n>\n>> Andreas Schwab <schwab@linux-m68k.org> writes:\n>> \n>> > Christian Couder <christian.couder@gmail.com> writes:\n>> >\n>> >> Yeah, at one point I wanted to have a command that created to craft a\n>> >> new commit based on an existing one.\n>> >\n>> > This isn't hard to do, you only have to resort to plumbing:\n>> >\n>> > $ git cat-file commit fef11965da875c105c40f1a9550af1f5e34a6e62 | sed s/bfae342c973b0be3c9e99d3d86ed2e6b152b4a6b/790c83cda92f95f1b4b91e2ddc056a52a99a055d/ | git hash-object -t commit --stdin -w\n>> > bb45cc6356eac6c7fa432965090045306dab7026\n>> \n>> Good.  I do not think an extra special-purpose command is welcome\n>> here.\n>\n> Well, I'm not sure this is intuitive enough to be useful to the average user :)\n\nI do not understand why you even want to go in the harder route in\nthe first place, only to complicate things?\n\nAll you want to do is to craft a commit object that records a\nspecific tree shape, has a set of parents you want, and has the log\ninformation you want.  Once you have the commit, you can replace an\nunwanted commit with it.\n\n    ----A----B----o---- ....\n\n           X----Y----Z---- ....\n\nSuppose you want to pretend that X is a child of A, even though it\nis not in the real life.  So you want to create a commit that \n\n    - has the same tree as X;\n    - has A as its parent; and\n    - records log and authorship of X.\n\nand then use \"git replace\" to replace X, right?  How about doing it\nthis way?\n\n    $ git checkout X^0 ;# detach\n    $ git reset --soft A\n    $ git commit -C X\n\nThe first gives you the index and the working tree that is the same\nas X, the second moves HEAD while keeping the index and the working\ntree so that the commit you create will be a child of A, and the\nlast makes that commit with the metainformation from X [*1*].  If\nyou want, you can even tweak the contents of the tree before making\nthe commit in the final step, or tweak the log message during the\nfinal step.\n\nThen you can take the resulting commit and replace X with it, no?\n\nAlternatively, you can do:\n\n    $ git checkout X^0 ;# detach\n    $ git reset --soft B\n    $ git commit --amend -C X\n\nthat is, find an existing commit B that has the desired set of\nparents, and amend it with the same tree and the metainformation as\nX.  This would even work when you want to come up with a commit that\nreplaces a merge.  For example, if you want to pretend that B were a\nmerge between A and X in the above topology, you could\n\n    $ git checkout -b temp A\n    $ git merge -s ours X ;# the recorded tree does not matter\n    $ git checkout B^0 ;# detach\n    $ git reset --soft temp\n    $ git commit --amend -c B\n\nwhich would create one merge that has the desired set of parents\n(i.e. A and X) in the first two steps on temp branch, prepares the\nindex and the working tree to match the tree of B, and with that\ntree and the metainformation from B, amends that merge.  The\nresulting commit will be a merge between A and X that has the tree\nof B and metainformation of B (with a chance to edit it further, as\nI used -c there).\n\nIs this not intuitive enough?\n\n\n[Footnote]\n\n*1* If you are not tweaking the tree contents, you can do this\nall in the index without affecting the working tree, e.g.\n\n    $ git checkout HEAD^0 ;# totally random state unrelated to X nor A\n    $ git read-tree X ;# just update the index to match tree of X\n    $ git reset --soft A ;# next commit will be child of A\n    $ git commit -C X ;# and with metainformation from X\n\nAfter you are done, you can \"read-tree $branch\" followed by\n\"checkout $branch\" to come back to where you were.\n"},{"id":"205128","messageId":"20121218162402.GA20122@sigill.intra.peff.net","threadId":"32313","inReplyTo":"20121218144157.00ccd915@chalon.bertin.fr","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-12-18T16:24:02Z","receivedAt":"2012-12-18T16:24:02Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Dec 18, 2012 at 02:41:57PM +0100, Yann Dirson wrote:\n\n> > I wouldn't even want a script -- we'd end up inventing a complicated\n> > command-line editor for what can simply be done by judicious use of an\n> > actual text editor.  How about something like the following?\n> \n> Well, while it does the job, it is still hardly as straightforward as the\n> old \"vi .git/info/grafts\", or as a single easily-remembered commandline.\n\nI wouldn't discount coming up with something based around \"git commit\"\nthat might be easier to use for specific instances, but it does seem\nlike an obvious feature to \"git replace\" to encapsulate Thomas's edit\nscript, which is the most general form.\n\nI am not really interested in pushing this forward myself, but I worked\nup this toy that somebody might find interesting (you can \"git replace\nHEAD~20\" to get dumped in an editor). It should probably handle trees,\nand it would probably make sense to do per-object-type sanity checks\n(e.g., call verify_tag on tags).\n\ndiff --git a/builtin/replace.c b/builtin/replace.c\nindex 398ccd5..90979b6 100644\n--- a/builtin/replace.c\n+++ b/builtin/replace.c\n@@ -81,6 +81,57 @@ static int delete_replace_ref(const char *name, const char *ref,\n \treturn 0;\n }\n \n+static void edit_buffer(struct strbuf *out, const char *buf, unsigned long len)\n+{\n+\tchar tmpfile[PATH_MAX];\n+\tint fd;\n+\n+\tfd = git_mkstemp(tmpfile, sizeof(tmpfile), \"replace.XXXXXX\");\n+\tif (fd < 0)\n+\t\tdie_errno(\"unable to create tempfile\");\n+\tif (write_in_full(fd, buf, len) < 0)\n+\t\tdie_errno(\"unable to write to tempfile\");\n+\tif (launch_editor(tmpfile, out, NULL) < 0)\n+\t\tdie_errno(\"unable to run editor\");\n+\n+\tclose(fd);\n+\tunlink_or_warn(tmpfile);\n+}\n+\n+static void edit_object(unsigned char old[20], unsigned char new[20])\n+{\n+\tenum object_type type;\n+\tunsigned long size;\n+\tchar *old_buf;\n+\tstruct strbuf new_buf = STRBUF_INIT;\n+\n+\told_buf = read_sha1_file_extended(old, &type, &size, 0);\n+\tif (!old_buf)\n+\t\tdie(\"unable to read object '%s'\", sha1_to_hex(old));\n+\n+\tswitch (type) {\n+\tcase OBJ_COMMIT:\n+\tcase OBJ_TAG:\n+\tcase OBJ_BLOB:\n+\t\t/* These are OK to edit literally. */\n+\t\tedit_buffer(&new_buf, old_buf, size);\n+\t\tbreak;\n+\tcase OBJ_TREE:\n+\t\t/*\n+\t\t * XXX we'd probably want to massage this into ls-tree format,\n+\t\t * and then read the result back via mktree.\n+\t\t */\n+\t\tdie(\"editing tree objects is not yet supported\");\n+\tdefault:\n+\t\tdie(\"unknown object type for %s\", sha1_to_hex(old));\n+\t}\n+\n+\tif (write_sha1_file(new_buf.buf, new_buf.len, typename(type), new) < 0)\n+\t\tdie(\"unable to write replacement object\");\n+\tfree(old_buf);\n+\tstrbuf_release(&new_buf);\n+}\n+\n static int replace_object(const char *object_ref, const char *replace_ref,\n \t\t\t  int force)\n {\n@@ -90,7 +141,7 @@ static int replace_object(const char *object_ref, const char *replace_ref,\n \n \tif (get_sha1(object_ref, object))\n \t\tdie(\"Failed to resolve '%s' as a valid ref.\", object_ref);\n-\tif (get_sha1(replace_ref, repl))\n+\tif (replace_ref && get_sha1(replace_ref, repl))\n \t\tdie(\"Failed to resolve '%s' as a valid ref.\", replace_ref);\n \n \tif (snprintf(ref, sizeof(ref),\n@@ -105,6 +156,9 @@ static int replace_object(const char *object_ref, const char *replace_ref,\n \telse if (!force)\n \t\tdie(\"replace ref '%s' already exists\", ref);\n \n+\tif (!replace_ref)\n+\t\tedit_object(object, repl);\n+\n \tlock = lock_any_ref_for_update(ref, prev, 0);\n \tif (!lock)\n \t\tdie(\"%s: cannot lock the ref\", ref);\n@@ -144,7 +198,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix)\n \n \t/* Replace object */\n \tif (!list && argc) {\n-\t\tif (argc != 2)\n+\t\tif (argc < 1 || argc > 2)\n \t\t\tusage_msg_opt(\"bad number of arguments\",\n \t\t\t\t      git_replace_usage, options);\n \t\treturn replace_object(argv[0], argv[1], force);\n"},{"id":"205177","messageId":"50D16911.10000@viscovery.net","threadId":"32313","inReplyTo":"20121218162402.GA20122@sigill.intra.peff.net","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2012-12-19T07:13:21Z","receivedAt":"2012-12-19T07:13:21Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 12/18/2012 17:24, schrieb Jeff King:\n> I am not really interested in pushing this forward myself, but I worked\n> up this toy that somebody might find interesting (you can \"git replace\n> HEAD~20\" to get dumped in an editor). It should probably handle trees,\n> and it would probably make sense to do per-object-type sanity checks\n> (e.g., call verify_tag on tags).\n\nI know it's just a throw-away patch, but I would discourage to go this\nroute without also adding all the sanity checks. Otherwise, it will have\njust created a porcelain command that can generate a commit object with\nany content you want!\n\n-- Hannes\n"},{"id":"205179","messageId":"20121219092920.2dc0f33e@chalon.bertin.fr","threadId":"32313","inReplyTo":"7vehinibpc.fsf@alter.siamese.dyndns.org","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Yann Dirson","fromEmail":"dirson@bertin.fr","sentAt":"2012-12-19T08:29:20Z","receivedAt":"2012-12-19T08:29:20Z","isPatch":false,"sender":{"key":"dirson@bertin.fr","avatar":null},"body":"On Tue, 18 Dec 2012 08:09:35 -0800\nJunio C Hamano <gitster@pobox.com> wrote:\n\n> Yann Dirson <dirson@bertin.fr> writes:\n> \n> > On Mon, 17 Dec 2012 13:14:56 -0800\n> > Junio C Hamano <gitster@pobox.com> wrote:\n> >\n> >> Andreas Schwab <schwab@linux-m68k.org> writes:\n> >> \n> >> > Christian Couder <christian.couder@gmail.com> writes:\n> >> >\n> >> >> Yeah, at one point I wanted to have a command that created to craft a\n> >> >> new commit based on an existing one.\n> >> >\n> >> > This isn't hard to do, you only have to resort to plumbing:\n> >> >\n> >> > $ git cat-file commit fef11965da875c105c40f1a9550af1f5e34a6e62 | sed s/bfae342c973b0be3c9e99d3d86ed2e6b152b4a6b/790c83cda92f95f1b4b91e2ddc056a52a99a055d/ | git hash-object -t commit --stdin -w\n> >> > bb45cc6356eac6c7fa432965090045306dab7026\n> >> \n> >> Good.  I do not think an extra special-purpose command is welcome\n> >> here.\n> >\n> > Well, I'm not sure this is intuitive enough to be useful to the average user :)\n> \n> I do not understand why you even want to go in the harder route in\n> the first place, only to complicate things?\n\nAlthough the approach you propose is elegant, it still looks like one\ncould not leave the worktree untouched in the case of creating a merge replace,\nwhich the \"just forge an arbitrary commit\" approach handles easily.\n\nIt seems the latter would also be more powerful, in that you can create new commits with an\narbitrary number of parents, even when merge-octopus would simply refuse to help;\nand it is has no special case for creating merges.\n\n> Is this not intuitive enough?\n\nI would say it is a nice read that can help an advanced user to earn\nsome XP - but well, replace refs are also meant for somewhat advanced users :)\n\n-- \nYann Dirson - Bertin Technologies\n"},{"id":"205182","messageId":"20121219130632.GA7134@sigill.intra.peff.net","threadId":"32313","inReplyTo":"50D16911.10000@viscovery.net","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-12-19T13:06:32Z","receivedAt":"2012-12-19T13:06:32Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Dec 19, 2012 at 08:13:21AM +0100, Johannes Sixt wrote:\n\n> Am 12/18/2012 17:24, schrieb Jeff King:\n> > I am not really interested in pushing this forward myself, but I worked\n> > up this toy that somebody might find interesting (you can \"git replace\n> > HEAD~20\" to get dumped in an editor). It should probably handle trees,\n> > and it would probably make sense to do per-object-type sanity checks\n> > (e.g., call verify_tag on tags).\n> \n> I know it's just a throw-away patch, but I would discourage to go this\n> route without also adding all the sanity checks. Otherwise, it will have\n> just created a porcelain command that can generate a commit object with\n> any content you want!\n\nI think I agree with you that it would not be worth doing without sanity\nchecks. I am not sure if your \"any content you want\" statement means\n\"bad people can easily make bogus objects\" or \"it is too easy to make\narbitrary mistakes, putting your repo in a bogus state\".\n\nI would agree that the latter is compelling, but not the former.  You\ncan already easily generate a commit with any content you want via\n\"hash-object -t commit\", and I have frequently done this while testing\ncorner cases of fsck, how git behaves when given buggy data, etc. So to\nme it is not about preventing intentional abuse, but about not promoting\na feature that makes it too easy to screw up.\n\n-Peff\n"},{"id":"205183","messageId":"87ip7yp4mf.fsf@pctrast.inf.ethz.ch","threadId":"32313","inReplyTo":"7vehinibpc.fsf@alter.siamese.dyndns.org","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2012-12-19T13:12:56Z","receivedAt":"2012-12-19T13:12:56Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> I do not understand why you even want to go in the harder route in\n> the first place, only to complicate things?\n>\n> All you want to do is to craft a commit object that records a\n> specific tree shape, has a set of parents you want, and has the log\n> information you want.  Once you have the commit, you can replace an\n> unwanted commit with it.\n[...]\n>     $ git checkout X^0 ;# detach\n>     $ git reset --soft A\n>     $ git commit -C X\n[...]\n> Is this not intuitive enough?\n\nI still wouldn't recommend this approach in git-replace(1) for several\nreasons:\n\n* It does not generalize in any direction.  For each field you may want\n  to change, you have to know a _specific_ way of getting just the\n  commit you want.\n\n* More to the point of replacing the parent lists, while the above might\n  be expected of a slightly advanced git user, you get into deep magic\n  the second you want to fake a merge commit with an arbitrary\n  combination of parents.  (No, you don't need to tell me how.  I'm just\n  saying that fooling with either MERGE_HEAD or read-tree is not for\n  mere mortals.)\n\n* The above potentially introduces clock skew into the repository, which\n  can trigger bugs (like rev-list accidentally missing out on some side\n  arm!) until we get around to implementing and using generation\n  numbers.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"205209","messageId":"7vvcbx956f.fsf@alter.siamese.dyndns.org","threadId":"32313","inReplyTo":"87ip7yp4mf.fsf@pctrast.inf.ethz.ch","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-12-19T20:07:36Z","receivedAt":"2012-12-19T20:07:36Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> I still wouldn't recommend this approach in git-replace(1) for several\n> reasons:\n>\n> * It does not generalize in any direction.  For each field you may want\n>   to change, you have to know a _specific_ way of getting just the\n>   commit you want.\n>\n> * More to the point of replacing the parent lists, while the above might\n>   be expected of a slightly advanced git user, you get into deep magic\n>   the second you want to fake a merge commit with an arbitrary\n>   combination of parents.  (No, you don't need to tell me how.  I'm just\n>   saying that fooling with either MERGE_HEAD or read-tree is not for\n>   mere mortals.)\n\nI do not buy either of the above.  When you are replacing one with\nsomething else, you ought to know what that something else is and\nhow to create it.  Editing a text file with an editor to replace\n40-hex object names with another is not a more intuitive way for end\nusers, either (in other words, you are seeing this from the point of\nview of somebody who *knows* the internal representation of Git\nobjects too much).\n\n> * The above potentially introduces clock skew into the repository, which\n>   can trigger bugs (like rev-list accidentally missing out on some side\n>   arm!) until we get around to implementing and using generation\n>   numbers.\n\nThat is an irrelevant point when comparing the \"go down to bare\nmetal replacing the object representation\" vs \"use the usual Git\ntools the end users are already familiar with\" approaches.  You will\nencounter the issue you are raising if you make a newer commit a\nparent of an existing child with an older commit timestamp, no\nmatter how you do the grafting.\n"},{"id":"205331","messageId":"50D45A78.3020104@drmicha.warpmail.net","threadId":"32313","inReplyTo":"7vvcbx956f.fsf@alter.siamese.dyndns.org","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2012-12-21T12:47:52Z","receivedAt":"2012-12-21T12:47:52Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"While replace refs are much more general than grafts, it seems the two\nmain uses are:\n\n- grafts (change the recorded parents for a commit)\n- svn cleanup (convert tagging commits into tag objects)\n\nThe latter one being quite a special case already.\n\nThe script below has helped me move from grafts to replace objects.\nWhile not being super clean, something like it may be fit for contrib.\n\nI think we ought to help John Doe get along with parents, while we can\nsafely leave most more advanced operations to people who know how to\nedit a raw object file. Putting that facility into \"git-commit\" seems to\nbe too encouraging, though - people would use replace when they should\nuse amend or rebase-i. I'd prefer a special git-replace mode (be it\n\"--graft\" or \"--graft-commit\") which does just what my script does. We\ncould add things like \"--commit-tag\" later, a full blown\n\"object-factory\" seems like overkill.\n\nMichael\n\n--->%---\n\n#!/bin/sh\n\ndie () {\n\techo \"$@\"\n\trm -f \"$commitfile\"\n \texit 1\n}\n\nwarn () {\n\techo \"$@\"\n}\n\ntest $# -gt 0 || die \"Usage: $0 <commit> [<parent>]*\"\n\nfor commit\ndo\n\tgit rev-parse --verify -q \"$commit\" >/dev/null || die \"Cannot parse\n$commit.\"\n\ttest x$(git cat-file -t $commit) == \"xcommit\" || die \"$commit is no\ncommit.\"\ndone\n\ncommit=\"$1\"\nshift\n\ncommitfile=$(mktemp)\n\ngit cat-file commit \"$commit\" | while read a b\ndo\n\tif test \"$a\" != \"parent\"\n\tthen\n\t\techo $a $b\n\tfi\n\tif test \"$a\" == \"tree\"\n\tthen\n\t\tfor parent\n\t\tdo\n\t\t\techo \"parent $(git rev-parse $parent)\"\n\t\tdone\n\tfi\ndone >$commitfile\nhash=$(git hash-object -t commit -w \"$commitfile\") || die \"Cannot create\ncommit object.\"\ngit replace \"$commit\" $hash\nrm -f $commitfile\n"},{"id":"205346","messageId":"7vzk171gvh.fsf@alter.siamese.dyndns.org","threadId":"32313","inReplyTo":"50D45A78.3020104@drmicha.warpmail.net","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-12-21T16:58:58Z","receivedAt":"2012-12-21T16:58:58Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n> While replace refs are much more general than grafts, it seems the two\n> main uses are:\n>\n> - grafts (change the recorded parents for a commit)\n> - svn cleanup (convert tagging commits into tag objects)\n>\n> The latter one being quite a special case already.\n>\n> The script below has helped me move from grafts to replace objects.\n> While not being super clean, something like it may be fit for contrib.\n>\n> I think we ought to help John Doe get along with parents, while we can\n> safely leave most more advanced operations to people who know how to\n> edit a raw object file. Putting that facility into \"git-commit\" seems to\n> be too encouraging, though - people would use replace when they should\n> use amend or rebase-i. I'd prefer a special git-replace mode (be it\n> \"--graft\" or \"--graft-commit\") which does just what my script does. We\n> could add things like \"--commit-tag\" later, a full blown\n> \"object-factory\" seems like overkill.\n>\n> Michael\n>\n> --->%---\n>\n> #!/bin/sh\n>\n> die () {\n> \techo \"$@\"\n> \trm -f \"$commitfile\"\n>  \texit 1\n> }\n>\n> warn () {\n> \techo \"$@\"\n> }\n>\n> test $# -gt 0 || die \"Usage: $0 <commit> [<parent>]*\"\n>\n> for commit\n> do\n> \tgit rev-parse --verify -q \"$commit\" >/dev/null || die \"Cannot parse\n> $commit.\"\n> \ttest x$(git cat-file -t $commit) == \"xcommit\" || die \"$commit is no\n> commit.\"\n\ns/==/=/ or you have to say #!/bin/bash on the first line, I think.\nAppears multiple times throughout this script.\n\n\n> done\n>\n> commit=\"$1\"\n> shift\n>\n> commitfile=$(mktemp)\n>\n> git cat-file commit \"$commit\" | while read a b\n> do\n> \tif test \"$a\" != \"parent\"\n> \tthen\n> \t\techo $a $b\n\nYou are losing information on non-header lines by reading without\n\"-r\" in the above, and also multi-line headers (e.g. mergetag),\naren't you?\n\n> \tfi\n> \tif test \"$a\" == \"tree\"\n> \tthen\n> \t\tfor parent\n> \t\tdo\n> \t\t\techo \"parent $(git rev-parse $parent)\"\n> \t\tdone\n> \tfi\n> done >$commitfile\n> hash=$(git hash-object -t commit -w \"$commitfile\") || die \"Cannot create\n> commit object.\"\n> git replace \"$commit\" $hash\n> rm -f $commitfile\n"},{"id":"205418","messageId":"50D5E216.4080006@drmicha.warpmail.net","threadId":"32313","inReplyTo":"7vzk171gvh.fsf@alter.siamese.dyndns.org","subject":"Re: [BUG] Cannot push some grafted branches","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2012-12-22T16:38:46Z","receivedAt":"2012-12-22T16:38:46Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Junio C Hamano venit, vidit, dixit 21.12.2012 17:58:\n> Michael J Gruber <git@drmicha.warpmail.net> writes:\n> \n>> While replace refs are much more general than grafts, it seems the two\n>> main uses are:\n>>\n>> - grafts (change the recorded parents for a commit)\n>> - svn cleanup (convert tagging commits into tag objects)\n>>\n>> The latter one being quite a special case already.\n>>\n>> The script below has helped me move from grafts to replace objects.\n>> While not being super clean, something like it may be fit for contrib.\n>>\n>> I think we ought to help John Doe get along with parents, while we can\n>> safely leave most more advanced operations to people who know how to\n>> edit a raw object file. Putting that facility into \"git-commit\" seems to\n>> be too encouraging, though - people would use replace when they should\n>> use amend or rebase-i. I'd prefer a special git-replace mode (be it\n>> \"--graft\" or \"--graft-commit\") which does just what my script does. We\n>> could add things like \"--commit-tag\" later, a full blown\n>> \"object-factory\" seems like overkill.\n>>\n>> Michael\n>>\n>> --->%---\n>>\n>> #!/bin/sh\n>>\n>> die () {\n>> \techo \"$@\"\n>> \trm -f \"$commitfile\"\n>>  \texit 1\n>> }\n>>\n>> warn () {\n>> \techo \"$@\"\n>> }\n>>\n>> test $# -gt 0 || die \"Usage: $0 <commit> [<parent>]*\"\n>>\n>> for commit\n>> do\n>> \tgit rev-parse --verify -q \"$commit\" >/dev/null || die \"Cannot parse\n>> $commit.\"\n>> \ttest x$(git cat-file -t $commit) == \"xcommit\" || die \"$commit is no\n>> commit.\"\n> \n> s/==/=/ or you have to say #!/bin/bash on the first line, I think.\n> Appears multiple times throughout this script.\n> \n> \n>> done\n>>\n>> commit=\"$1\"\n>> shift\n>>\n>> commitfile=$(mktemp)\n>>\n>> git cat-file commit \"$commit\" | while read a b\n>> do\n>> \tif test \"$a\" != \"parent\"\n>> \tthen\n>> \t\techo $a $b\n> \n> You are losing information on non-header lines by reading without\n> \"-r\" in the above, and also multi-line headers (e.g. mergetag),\n> aren't you?\n>\n\nOh yes, it has bashisms and imperfections. It's not a submitted patch,\nnot even RFC. It's meant to show the git-replace mode that many users\ncould benefit from: works for commits only and replaces the parent list,\nbut takes any rev arguments as the new parents, rather than forcing the\nuser to specify a full sha1.\n\n>> \tfi\n>> \tif test \"$a\" == \"tree\"\n>> \tthen\n>> \t\tfor parent\n>> \t\tdo\n>> \t\t\techo \"parent $(git rev-parse $parent)\"\n>> \t\tdone\n>> \tfi\n>> done >$commitfile\n>> hash=$(git hash-object -t commit -w \"$commitfile\") || die \"Cannot create\n>> commit object.\"\n>> git replace \"$commit\" $hash\n>> rm -f $commitfile\n"}]}