{"thread":{"id":"6497","subject":"How to pull only a few files from one branch to another?","startedAt":"2007-01-24T03:24:42Z","lastAt":"2007-01-24T22:04:39Z","messageCount":18,"participants":["Bill Lear","Linus Torvalds","Daniel Barkalow","Shawn O. Pearce","Junio C Hamano","Jakub Narebski","Johannes Schindelin","Andy Whitcroft","Yann Dirson"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"32482","messageId":"17846.53626.895660.762096@lisa.zopyra.com","threadId":"6497","inReplyTo":null,"subject":"How to pull only a few files from one branch to another?","fromName":"Bill Lear","fromEmail":"rael@zopyra.com","sentAt":"2007-01-24T03:24:42Z","receivedAt":"2007-01-24T03:24:42Z","isPatch":false,"sender":{"key":"rael@zopyra.com","avatar":"https://gravatar.com/avatar/c4f2d2790ca3828d3b4e7dfebabf61d2fe94fd82fa49cdac2a5295dd2d46a874?d=mp&s=160"},"body":"I have a long-running topic branch.  I have fixed a few nits on\nthe master branch that I would like on the topic branch.  How do I\npull in only a few files from the head of the master branch?\n\nI tried all sorts of incantations (I am running 1.5.0-rc2), including:\n\ngit pull . origin foo.cc\ngit pull origin foo.cc\ngit pull foo.cc master\ngit pull . master foo.cc\ngit pull master foo.cc\n\n\nBill\n"},{"id":"32483","messageId":"Pine.LNX.4.64.0701231937310.3606@woody.linux-foundation.org","threadId":"6497","inReplyTo":"17846.53626.895660.762096@lisa.zopyra.com","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-01-24T04:11:38Z","receivedAt":"2007-01-24T04:11:38Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 23 Jan 2007, Bill Lear wrote:\n>\n> I have a long-running topic branch.  I have fixed a few nits on\n> the master branch that I would like on the topic branch.  How do I\n> pull in only a few files from the head of the master branch?\n> \n> I tried all sorts of incantations (I am running 1.5.0-rc2), including:\n> \n> git pull . origin foo.cc\n> git pull origin foo.cc\n> git pull foo.cc master\n> git pull . master foo.cc\n> git pull master foo.cc\n\nGit *very* fundamentally tracks project state, not file state. Which means \nthat you very much can NOT try to \"merge a file\". It is a senseless \noperation in git, and in fact, any SCM that allows it pretty much is \ndoomed to be a total piece of sh*t (*).\n\nSo if you want to get just one file, you cannot see it as a \"project-level \nmerge\", and you literally have to handle that file as an individual file \nand merge it as such, and then you can commit the result as a regular \ncommit (but it will _not_ show up as real \"git merge\").\n\nSo in git, the rule is always that you track the whole state of the \nproject. It's a project tracker, not a \"file tracker\".\n\nThat said, if you just want to get the fixes from one branch, and merge \nit, git does allow you to do it, although there isn't any \"porcelain\". \nYou'd basically have to do it by hand, a few different ways\n\n (1) If you just want to commit the state of a file AS IT IS in another \n     branch, you can just do\n\n\tgit checkout other-branch filename-goes-here\n\tgit commit\n\n     which will just do it for you.\n\n (2) However, more commonly, what you actually *want* to do is to merge \n     the changes in the other branch into the current branch (which has \n     its own set of changes), and then things get more interesting and \n     more complex.\n\n     If you have just one simple merge-base, you'd do something like\n\n\tgit merge-one-file \\\n\t\t$(git merge-base HEAD other):filename \\\n\t\tHEAD:filename \\\n\t\tother:filename \\\n\t\tfilename\n\n     (where those last three things are just the file mode). And then just \n     commit the end result.\n\n     Which is just total git magic. If you understand the above command\n     line, I have nothing more to teach you.\n\nMaybe somebody could actually test the above one-liner magic thing, and \nexplain how it works. And maybe we could write porcelain to do this ;)\n\nNOTE NOTE NOTE! I don't actually think \"git merge-one-file\" really works \ncorrectly as-is for your usage case. It _kind_of_ gets the result you \nwant, but it's not really written to be used like that, and you'll get an \nerror from the\n\n\tgit-checkout-index -f --stage=2 -- \"$4\" &&\n\t\tcat \"$src1\" >\"$4\"\n\nstage because stage 2 didn't exist (\"git-merge-one-file\" is really only \nsupposed to be called by a real merge).\n\nBut it's _almost_ usable that way. Maybe Dscho or Junio wants to make it \nwork the extra final mile.\n\nAnyway, the above (2) kind of works, but if you want to avoid the warning \nand want to avoid the magic, you would really have to do something like\n\n\tgit cat-file blob $(git-merge-base HEAD other):filename > .base\n\tgit cat-file blob other:filename > .other\n\tgit merge-file filename .base .other\n\nwhich will mostly do what you wanted (without complaints), and is what the \ngit-merge-one-file magic actually boils down to.\n\nNot exactly pretty. If this is something people want to do often, we'd \nneed to generate some porcelain for it.\n\nBut if you understand the above three lines, you're actually doing really \nreally well already. And as a \"yes, git can do it\" kind of demonstration, \nit may even be useful.\n\nFINAL NOTE! After you do file-level merging like this, don't expect future \nmerges to that file to be easy if you continue to make changes! This is \n_why_ git doesn't do file-level merges natively - namely it really doesn't \nwork well together with future merges.\n\nTo keep merges working after more than just one merge, you really need to \neither do _all_ merges on a file-per-file level (which is insane and \ndoesn't scale and has serious problems) or you need to do merges at a \n\"project level\" (which is how git fundamentally works).\n\n\t\tLinus\n\n(*) And I'm not saying that just because git doesn't do it. It's much \nmore fundamental than that. Once you start doing per-file branching and \nmerging, you've basically screwed yourself, and you'll never be able to \nwork on the project as a \"whole project\" any more - you no longer have a \nwell-defined history that actually is the history of the whole project.\n"},{"id":"32484","messageId":"Pine.LNX.4.64.0701232012450.3606@woody.linux-foundation.org","threadId":"6497","inReplyTo":"Pine.LNX.4.64.0701231937310.3606@woody.linux-foundation.org","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-01-24T04:18:58Z","receivedAt":"2007-01-24T04:18:58Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 23 Jan 2007, Linus Torvalds wrote:\n> \n>      If you have just one simple merge-base, you'd do something like\n> \n> \tgit merge-one-file \\\n> \t\t$(git merge-base HEAD other):filename \\\n> \t\tHEAD:filename \\\n> \t\tother:filename \\\n> \t\tfilename\n> \n>      (where those last three things are just the file mode)\n\nThat comment made no sense. I removed the file modes entirely, and forgot \nto remove the comment. It turns out that you can just drop the file modes \nentirely from the invocation of least the current \"git-merge-one-file\", so \nI did that, to keep it cleaner and simpler.\n\nAnyway, the way \"git merge-one-file\" works, you pass it:\n\n - the SHA1 of the \"base object\"\n\n\t$(git merge-base HEAD other):filename\n\n - the SHA1 of the \"current branch version of the file\"\n\n\tHEAD:filename\n\n - the SHA1 of the \"other branch version of the file\"\n\n\tother:filename\n\n - the filename as you want the end result to be in the index\n\n\tfilename\n\n - normally, you'd pass the file modes for the three cases too\n\n\t0644 0644 0644\n\n   but those are the ones I skipped because the shell script actually only \n   uses them to see if they are different (so dropping them means that it \n   all works fine - the empty arguments are all the same).\n\nbut additionally, since \"git merge-one-file\" expects to be in the middle \nof a real merge (and not just some faked-out single-file merging thing) it \nalso expects the index to be populated in stage2 with the current branch \nversion of the file - which it won't be outside of a merge. Which is why \nit ends up complaining.\n\nIt would be kind of cool to have the whole \"merge-recursive\" logic (which \ncan handle multiple ancestors etc - unlike the above) able to do this, but \nthat's a whole 'nother kettle of fish.\n\n\t\t\tLinus\n"},{"id":"32486","messageId":"Pine.LNX.4.64.0701240019250.20138@iabervon.org","threadId":"6497","inReplyTo":"17846.53626.895660.762096@lisa.zopyra.com","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2007-01-24T05:29:00Z","receivedAt":"2007-01-24T05:29:00Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Tue, 23 Jan 2007, Bill Lear wrote:\n\n> I have a long-running topic branch.  I have fixed a few nits on\n> the master branch that I would like on the topic branch.  How do I\n> pull in only a few files from the head of the master branch?\n\nYou don't pull in a few files, you apply the changes made in a few \ncommits:\n\n  git diff HEX_OF_NIT_FIX^ HEX_OF_NIT_FIX | git apply\n\nIf there's other stuff in the nit-fixing commit, shame on you, but you can \nedit the patch before applying it to remove everything that's not what you \nwant.\n\n(Incidentally, I think \"git diff ^ {commit}\" should be made to do \"git \ndiff {commit}^ {commit}\"; i.e., if there is a single other revision \nprovided, interpret a modifier not applied to anything as applying to that \nrevision, in the \"what else could that possibly mean?\" department.)\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"32487","messageId":"17846.63082.935311.947093@lisa.zopyra.com","threadId":"6497","inReplyTo":"Pine.LNX.4.64.0701240019250.20138@iabervon.org","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Bill Lear","fromEmail":"rael@zopyra.com","sentAt":"2007-01-24T06:02:18Z","receivedAt":"2007-01-24T06:02:18Z","isPatch":false,"sender":{"key":"rael@zopyra.com","avatar":"https://gravatar.com/avatar/c4f2d2790ca3828d3b4e7dfebabf61d2fe94fd82fa49cdac2a5295dd2d46a874?d=mp&s=160"},"body":"On Wednesday, January 24, 2007 at 00:29:00 (-0500) Daniel Barkalow writes:\n>On Tue, 23 Jan 2007, Bill Lear wrote:\n>\n>> I have a long-running topic branch.  I have fixed a few nits on\n>> the master branch that I would like on the topic branch.  How do I\n>> pull in only a few files from the head of the master branch?\n>\n>You don't pull in a few files, you apply the changes made in a few \n>commits:\n>\n>  git diff HEX_OF_NIT_FIX^ HEX_OF_NIT_FIX | git apply\n>...\n\nGood technique.  Thank you for sharing.\n\nI had been thinking about trying something along the lines of Junio's\n\"Separating topic branches\" posted on the \"GIT Howto Index\" page.  I\nmay have tried that had I been braver.\n\nI probably should have thought ahead and made this fix on a branch,\nmerged it into my master branch and then into my topic branch ... I\nthink.\n\n\nBill\n"},{"id":"32488","messageId":"20070124060703.GA25759@spearce.org","threadId":"6497","inReplyTo":"17846.63082.935311.947093@lisa.zopyra.com","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-01-24T06:07:04Z","receivedAt":"2007-01-24T06:07:04Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Bill Lear <rael@zopyra.com> wrote:\n> I probably should have thought ahead and made this fix on a branch,\n> merged it into my master branch and then into my topic branch ... I\n> think.\n\nYes.  That is standard \"good practice\" with Git.  Unfortunately it\ndoes require a little planning ahead if the base to start on isn't\nimmediately obvious (you need to think \"I want this here, and here,\nand here.. and compute the merge base\").\n\n-- \nShawn.\n"},{"id":"32489","messageId":"7vac08j4go.fsf@assigned-by-dhcp.cox.net","threadId":"6497","inReplyTo":"Pine.LNX.4.64.0701240019250.20138@iabervon.org","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-01-24T06:58:47Z","receivedAt":"2007-01-24T06:58:47Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Daniel Barkalow <barkalow@iabervon.org> writes:\n\n> You don't pull in a few files, you apply the changes made in a few \n> commits:\n>\n>   git diff HEX_OF_NIT_FIX^ HEX_OF_NIT_FIX | git apply\n>\n> If there's other stuff in the nit-fixing commit, shame on you, but you can \n> edit the patch before applying it to remove everything that's not what you \n> want.\n\nOr just:\n\n\tgit cherry-pick HEX_OF_NIT_FIX\n\npossibly followed by tweaking the result and running:\n\n\tgit commit --amend\n"},{"id":"32496","messageId":"ep791o$h2u$2@sea.gmane.org","threadId":"6497","inReplyTo":"Pine.LNX.4.64.0701240019250.20138@iabervon.org","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-01-24T09:32:33Z","receivedAt":"2007-01-24T09:32:33Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Daniel Barkalow wrote:\n\n> (Incidentally, I think \"git diff ^ {commit}\" should be made to do \"git \n> diff {commit}^ {commit}\"; i.e., if there is a single other revision \n> provided, interpret a modifier not applied to anything as applying to that \n> revision, in the \"what else could that possibly mean?\" department.)\n\n\"git diff <commit>^!\" doesn't work?\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"32500","messageId":"Pine.LNX.4.63.0701241110240.22628@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"6497","inReplyTo":"Pine.LNX.4.64.0701232012450.3606@woody.linux-foundation.org","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-01-24T10:14:25Z","receivedAt":"2007-01-24T10:14:25Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 23 Jan 2007, Linus Torvalds wrote:\n\n> It would be kind of cool to have the whole \"merge-recursive\" logic \n> (which can handle multiple ancestors etc - unlike the above) able to do \n> this, but that's a whole 'nother kettle of fish.\n\nYou'd lose all the renaming logic when doing it strictly on a file level. \nSo I suggest opening a sidebranch, doing the merge, and just pick the new \nfile as you proposed with \"git checkout -f sidebranch file\".\n\nCiao,\nDscho\n"},{"id":"32501","messageId":"Pine.LNX.4.63.0701241104300.22628@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"6497","inReplyTo":"Pine.LNX.4.64.0701231937310.3606@woody.linux-foundation.org","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-01-24T10:16:35Z","receivedAt":"2007-01-24T10:16:35Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 23 Jan 2007, Linus Torvalds wrote:\n\n> NOTE NOTE NOTE! I don't actually think \"git merge-one-file\" really works \n> correctly as-is for your usage case. It _kind_of_ gets the result you \n> want, but it's not really written to be used like that, and you'll get an \n> error from the\n> \n> \tgit-checkout-index -f --stage=2 -- \"$4\" &&\n> \t\tcat \"$src1\" >\"$4\"\n> \n> stage because stage 2 didn't exist (\"git-merge-one-file\" is really only \n> supposed to be called by a real merge).\n> \n> But it's _almost_ usable that way. Maybe Dscho or Junio wants to make it \n> work the extra final mile.\n\nI don't really see the point, but yes, it would be easy enough (at least \nin the builtin version I sent out last night).\n\nNote that the checkout-index is used _purely_ to set the correct mode (at \nleast as far as I can tell). *Clickety-click* well, seems you had \nsomething different in mind on June 8th, 2005. \"make sure that the full \npathname is created\". This, of course, is missing from the builtin \nmerge-one-file (yet).\n\n> Not exactly pretty. If this is something people want to do often, we'd \n> need to generate some porcelain for it.\n\nI fully expect people to agree that this is not the way to go. I think \ncherry-picking is what you were after, Bill, correct?\n\nHaving said that, I find myself picking changes from a side-branch (with \ntoo many one-liner commits) with this command:\n\n\tgit diff -R sidebranch file1 file2.. | git apply --index\n\nCiao,\nDscho\n"},{"id":"32506","messageId":"17847.15637.140812.730274@lisa.zopyra.com","threadId":"6497","inReplyTo":"Pine.LNX.4.63.0701241104300.22628@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Bill Lear","fromEmail":"rael@zopyra.com","sentAt":"2007-01-24T11:03:49Z","receivedAt":"2007-01-24T11:03:49Z","isPatch":false,"sender":{"key":"rael@zopyra.com","avatar":"https://gravatar.com/avatar/c4f2d2790ca3828d3b4e7dfebabf61d2fe94fd82fa49cdac2a5295dd2d46a874?d=mp&s=160"},"body":"On Wednesday, January 24, 2007 at 11:16:35 (+0100) Johannes Schindelin writes:\n>...\n>I fully expect people to agree that this is not the way to go. I think \n>cherry-picking is what you were after, Bill, correct?\n\nI can't answer confidently, but I think that this is correct.\n\n\nBill\n"},{"id":"32525","messageId":"45B772A0.3040806@shadowen.org","threadId":"6497","inReplyTo":"17846.63082.935311.947093@lisa.zopyra.com","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-01-24T14:52:16Z","receivedAt":"2007-01-24T14:52:16Z","isPatch":false,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"Bill Lear wrote:\n> On Wednesday, January 24, 2007 at 00:29:00 (-0500) Daniel Barkalow writes:\n>> On Tue, 23 Jan 2007, Bill Lear wrote:\n>>\n>>> I have a long-running topic branch.  I have fixed a few nits on\n>>> the master branch that I would like on the topic branch.  How do I\n>>> pull in only a few files from the head of the master branch?\n>> You don't pull in a few files, you apply the changes made in a few \n>> commits:\n>>\n>>  git diff HEX_OF_NIT_FIX^ HEX_OF_NIT_FIX | git apply\n>> ...\n> \n> Good technique.  Thank you for sharing.\n> \n> I had been thinking about trying something along the lines of Junio's\n> \"Separating topic branches\" posted on the \"GIT Howto Index\" page.  I\n> may have tried that had I been braver.\n> \n> I probably should have thought ahead and made this fix on a branch,\n> merged it into my master branch and then into my topic branch ... I\n> think.\n\nPerhaps you can just rebase that one fix 'back' onto the base.  Then\nmerge it into both.\n\n-apw\n"},{"id":"32548","messageId":"Pine.LNX.4.64.0701241434540.20138@iabervon.org","threadId":"6497","inReplyTo":"ep791o$h2u$2@sea.gmane.org","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2007-01-24T19:46:01Z","receivedAt":"2007-01-24T19:46:01Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Wed, 24 Jan 2007, Jakub Narebski wrote:\n\n> Daniel Barkalow wrote:\n> \n> > (Incidentally, I think \"git diff ^ {commit}\" should be made to do \"git \n> > diff {commit}^ {commit}\"; i.e., if there is a single other revision \n> > provided, interpret a modifier not applied to anything as applying to that \n> > revision, in the \"what else could that possibly mean?\" department.)\n> \n> \"git diff <commit>^!\" doesn't work?\n\nIt generates the right result, but it hasn't become something I \nautomatically think of. :) For that matter, \"git diff <commit>{^,}\" also \nworks, but, again, I don't think of it instantly.\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"32556","messageId":"20070124203913.GD4083@nan92-1-81-57-214-146.fbx.proxad.net","threadId":"6497","inReplyTo":"Pine.LNX.4.64.0701231937310.3606@woody.linux-foundation.org","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Yann Dirson","fromEmail":"ydirson@altern.org","sentAt":"2007-01-24T20:39:13Z","receivedAt":"2007-01-24T20:39:13Z","isPatch":false,"sender":{"key":"ydirson@altern.org","avatar":"https://avatars.githubusercontent.com/u/1190950?v=4"},"body":"On Tue, Jan 23, 2007 at 08:11:38PM -0800, Linus Torvalds wrote:\n> Git *very* fundamentally tracks project state, not file state. Which means \n> that you very much can NOT try to \"merge a file\". It is a senseless \n> operation in git, and in fact, any SCM that allows it pretty much is \n> doomed to be a total piece of sh*t (*).\n\n> (*) And I'm not saying that just because git doesn't do it. It's much \n> more fundamental than that. Once you start doing per-file branching and \n> merging, you've basically screwed yourself, and you'll never be able to \n> work on the project as a \"whole project\" any more - you no longer have a \n> well-defined history that actually is the history of the whole project.\n\nIn fact, I came some time ago on a workflow which could be seen as\nquite similar to this issue.\n\nThe problem was about merging a new upstream release in a local\nbranch, when both branches had heavy changes.  Indeed this tree was\nnot using GIT but CVS, with upstream tarballs imported on a branch - I\njust asked myself how it could be best handled with GIT, and could\nonly come to the conclusion that something in GIT was still missing.\n\nWhat was particular about this tree, is that we are several people\nworking on it, namely developpers taking care of the app, and me as\nbuild manager taking care of the build mechanics as well as kernel+OS.\nSo the task was logically divided: one dev would merge the app, and I\nwould merge everything else.  As you see, it's far from one-file\nmerges, but the problem is quite similar.\n\n\nThe idea which I came up with was inspired by the \"partial merge\"\nfeature in PRCS, which I had never used or even understood the purpose\nbefore that date.\n\nBasically, it was that if some set of files could be merged somewhat\nindependently from the rest, and we don't want to get GIT attempt to\nmerge them again when finally merging the whole, a commit of a partial\nmerge would somehow record that some files had already been merged.\nAnd I happenned to think that it could be sufficient to create a\ncommit that would not be a merge commit itself (since it is not a\nfull-project merge), but which would instead reference \"subcommits\"\nfor the relevant parts of the tree that were merged during that\niteration.\n\nI realize that solution would not really be perfect, as there is\nalways some coupling between the code and build stuff in a project.\nAnd sometimes we could want to get finer granularity than the file\nlevel.  But that's so far my best guess at finding a solution.\n\nHow would you handle such a situation ?\n\nBest regards,\n-- \nYann.\n"},{"id":"32561","messageId":"ep8ght$dlf$3@sea.gmane.org","threadId":"6497","inReplyTo":"20070124203913.GD4083@nan92-1-81-57-214-146.fbx.proxad.net","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-01-24T20:46:49Z","receivedAt":"2007-01-24T20:46:49Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Yann Dirson wrote:\n\n> What was particular about this tree, is that we are several people\n> working on it, namely developpers taking care of the app, and me as\n> build manager taking care of the build mechanics as well as kernel+OS.\n> So the task was logically divided: one dev would merge the app, and I\n> would merge everything else.  As you see, it's far from one-file\n> merges, but the problem is quite similar.\n\nThis I think would be best handled by (future/prototype) submodules\nsupport.\n\n\nI wonder if fake-recording resolutions in git-rerere would help\nin that case...\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"32563","messageId":"20070124212731.GE4083@nan92-1-81-57-214-146.fbx.proxad.net","threadId":"6497","inReplyTo":"ep8ght$dlf$3@sea.gmane.org","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Yann Dirson","fromEmail":"ydirson@altern.org","sentAt":"2007-01-24T21:27:31Z","receivedAt":"2007-01-24T21:27:31Z","isPatch":false,"sender":{"key":"ydirson@altern.org","avatar":"https://avatars.githubusercontent.com/u/1190950?v=4"},"body":"On Wed, Jan 24, 2007 at 09:46:49PM +0100, Jakub Narebski wrote:\n> Yann Dirson wrote:\n> \n> > What was particular about this tree, is that we are several people\n> > working on it, namely developpers taking care of the app, and me as\n> > build manager taking care of the build mechanics as well as kernel+OS.\n> > So the task was logically divided: one dev would merge the app, and I\n> > would merge everything else.  As you see, it's far from one-file\n> > merges, but the problem is quite similar.\n> \n> This I think would be best handled by (future/prototype) submodules\n> support.\n\nThat could be used for some cases, but it's harder to use to avoid\ngetting a Makefile merged with the rest of the subtree.\n\n\n> I wonder if fake-recording resolutions in git-rerere would help\n> in that case...\n\nHm.  Looks like that would require being able to communicate rerere\nresults from one workspace to another.\n"},{"id":"32564","messageId":"Pine.LNX.4.64.0701241251030.3606@woody.linux-foundation.org","threadId":"6497","inReplyTo":"20070124203913.GD4083@nan92-1-81-57-214-146.fbx.proxad.net","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-01-24T21:30:31Z","receivedAt":"2007-01-24T21:30:31Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 24 Jan 2007, Yann Dirson wrote:\n> \n> What was particular about this tree, is that we are several people\n> working on it, namely developpers taking care of the app, and me as\n> build manager taking care of the build mechanics as well as kernel+OS.\n> So the task was logically divided: one dev would merge the app, and I\n> would merge everything else.  As you see, it's far from one-file\n> merges, but the problem is quite similar.\n\nYes, it's basically the same thing.\n\nAnd the sad part is that you can easily come up with tons of examples of \nwhere this makes sense, and indeed there are no fundamental problems at \nall as long as the \"per-file\" (or \"file group\" - the thing doesn't really \nchange) history is strictly a perfect subset of the \"whole project\" \nhistory topology.\n\nThe reason it fundamentally doesn't work in the long run is that people \ninvariably will then do things that do _not_ have the same \"history \ntopology\". You'll have one file that has some of its history mixed in two \ndifferent branches that _globally_ share none of that per-file history, so \nthen the global history no longer matches the history of that file, and \nthe \"topology\" of the history cannot be mapped from one to the other.\n\nSo what do I mean by that?\n\nWhat git does is to track the history as it is shared by ALL files in the \nwhole project (or, the way I prefer to think about it: it's not about \nindependent files at all, it's _always_ about the whole collection).\n\nThis makes sense, because what does \"history\" actually mean? Forget about \nwhat it means as a word in English, and concentrate on what its meaning is \nstrictly from a technical standpoint. Why does history matter? Why don't \nwe just have a set of commits in date order?\n\n>From a technical standpoint, the thing that makes history matter (and why \n\"set of commits in date order\" is useless) is because it gives us a COMMON \nANCESTOR! And *that* is the only thing that matters.\n\nNow, what is fundamentally wrong with doing per-file history? \n\nNow, if you've followed this argument, you should go \"Aaahh! Obvious!\".\n\nThe thing that is _fundamentally_ wrong with per-file history is that it \nbreaks the one AND ONLY point of having history in the first place. There \nis no well-defined \"common ancestor\" notion on a repository level any \nmore. You've made the history meaningless on a repo level, and it's now \nonly meaningful on a file level.\n\nSo whats' wrong with that? You could still do merges, file by file, and \njust do the common ancestry that way, couldn't you?\n\nYes you can. It's just that if you do, you're a total moron, and you're \nback to the dark ages and playing with CVS (and possibly SVN - it's too \nearly to say yet, since SVN can't do merges and history AT ALL right now \nas far as I know - it has the same merge logic as CVS has, I think, \nwhich is to say that it doesn't really understand the point of having \nhistory in the first place).\n\nWhich gets me back to where I started: you could (at least in in theory)\nallow a situation where you allowed file-level merges AS LONG AS THEY \nNEVER CLASH WITH THE GLOBAL HISTORY.\n\nIn other words, I could imagine starting a branch for a particular file \n(and when I say \"file\", it can be any arbitrary subset of the full state), \nand having file-level history at that level, but you must NEVER then merge \nthat file across into _another_ global branch, because if you do, then the \n\"global history\" has lost all value, since it's no longer actually global \nhistory any more.\n\nSo you have to choose: do you want to track things file by file, or do you \nwant to track the whole project. You literally can't say \"I want to do \nboth!\". Because tracking history file by file breaks the whole concept of \ntracking global history, the moment you start merging individual files \nacross branch boundaries.\n\n> The idea which I came up with was inspired by the \"partial merge\"\n> feature in PRCS, which I had never used or even understood the purpose\n> before that date.\n\nI really don't think that people understand how fundamentally broken the \nwhole concept is.\n\nI think git should help you combine partial state between different \nbranches, but you should always realize that IT IS NOT A MERGE! It's more \nlike a \"cherry-pick\" - except you cherry-pick multiple commits \"in space\" \ninstead of cherry-picking one commit \"in time\".\n\n(The way I personally view git, \"space\" is the workspace - aka contents - \nwhile \"time\" is the history, aka the relationship of commits\")\n\nSo it's perfectly ok to take data from other branches and include them in \nyour current one. Nobody doubts that, and indeed, some forms of it we \nalready have nice tools to help you do that (\"cherry-pick\" in particular).\n\nAnd yes, doing a simple\n\n\tgit diff commit..othercommit filename | \n\t\tgit-apply --index && git commit\n\nis really just a way to \"cherry-pick\" the data when it's located in \n\"space\" instead of in \"time\" (ie we restrict it to a particular region of \nthe workspace, and cherry-pick the work we did over a long time: this is \n100% equivalent to \"git cherry-pick\", which does it the other way around: \nit cherry-picks the work restricted \"in time\", but unstrstricted \"in \nspace\").\n\nBut when you do this YOU MUST NOT CALL IT A MERGE!\n\nBecause you _by_definition_ don't actually do the ONE thing that is the \nwhole point of a merge: the result does not become a common ancestor of \nthe result.\n\nSo when you cherry-pick, you don't merge: you just create a bug-standard \ncommit. It may contain data from another branch, but it is NOT a merge of \nthe other branch.\n\n> How would you handle such a situation ?\n\nSee above. Just create them as individual commits, and perhaps point to \nwhere the data came from in the commit comment, but don't try to think \nthey are merges.\n\nBtw, to explain my point perhaps even more fully, let me give an example \nof the \"reverse\" situation:\n\n\tgit merge -s ours\n\nThis actually IS a merge, even though we don't actually make ANY CHANGES \nAT ALL to the tree, and we don't take any actual data at all from the \nother branch, and just state: \"the result of the merge is always the \ncurrent branch contents\".\n\nSo why is it a merge? Exactly for the same reason that a partial-file \n\"merge\" is NOT a merge. It's a merge because the whole point of the \"ours\" \nstrategy is to say \"This is now going to be the common ancestor for these \ntwo states going forward\". And that is the _definition_ of a merge, since \nthat's the whole (and ONLY) point of having history in the first place.\n\nSo it all really boils down to a simple question: \"What is the meaning of \n'history'?\"\n\nOnce you understand what history is all about, you understand why a \n\"merge\" of a few files isn't actually a merge at all, but just a \ncherry-pick.\n\n(And btw, that doesn't mean that we wouldn't use the \"merge\" program to do \nit. The way we actually implement \"cherry-pick\" is to physically do a \n\"merge\" of the contents, because passing patches forwards and backwards is \njust stupid. So the issue is somewhat confused by the different \"levels\" \nof meaning of the word \"merge\". There's the pure \"content merge\", which is \na purely technical method of combining data, and which is usually just a \nthree-way RCS-merge. And then there is the \"merge commit\", which tells you \nsomething about HISTORY, which is a lot more fundamental and a lot more \nimportant).\n\nYou can often do the \"data merge\" by hand. It's the least of your \nproblems, and it's not even very interesting. The _interesting_ part of a \ngit merge is what it means for history!\n\nDoing cherry-picking (whichever kind you want to) is fine, but you have to \nrealize that it also means that you will have a potentially harder time to \ndo a \"true merge\" of the two branches later. Once your per-file history \ndoesn't match the whole-project history, you end up losing a lot of the \nautomatic goodness of simple merges, and you get back to the old CVS merge \nhell.\n\nBut the good news is that at least it won't be any _worse_ than what a lot \nof people have long since learnt about CVS merging. It will be \"hell\" only \nwhen compared to what you can do when you don't play games, and when you \nmerge nicely.\n\n\t\t\tLinus\n"},{"id":"32566","messageId":"200701242304.40904.jnareb@gmail.com","threadId":"6497","inReplyTo":"20070124212731.GE4083@nan92-1-81-57-214-146.fbx.proxad.net","subject":"Re: How to pull only a few files from one branch to another?","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-01-24T22:04:39Z","receivedAt":"2007-01-24T22:04:39Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Yann Dirson wrote:\n> On Wed, Jan 24, 2007 at 09:46:49PM +0100, Jakub Narebski wrote:\n>> Yann Dirson wrote:\n>> \n>>> What was particular about this tree, is that we are several people\n>>> working on it, namely developpers taking care of the app, and me as\n>>> build manager taking care of the build mechanics as well as kernel+OS.\n>>> So the task was logically divided: one dev would merge the app, and I\n>>> would merge everything else.  As you see, it's far from one-file\n>>> merges, but the problem is quite similar.\n\n>> I wonder if fake-recording resolutions in git-rerere would help\n>> in that case...\n> \n> Hm.  Looks like that would require being able to communicate rerere\n> results from one workspace to another.\n\nAnother solution would be to record partial merge (using \"ours\" strategy\nfor files we don't want to merge), then --amend it. \n\n-- \nJakub Narebski\nPoland\n"}]}