{"thread":{"id":"17865","subject":"Is there a way to exclude user-specified files or directories from participating in merges?","startedAt":"2009-02-18T00:49:01Z","lastAt":"2009-02-19T13:37:56Z","messageCount":9,"participants":["Brent Goodrick","Junio C Hamano","Sitaram Chamarty"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"105253","messageId":"e38bce640902171649g765275a4n4e86d1d4f4aaf394@mail.gmail.com","threadId":"17865","inReplyTo":null,"subject":"Is there a way to exclude user-specified files or directories from participating in merges?","fromName":"Brent Goodrick","fromEmail":"bgoodr@gmail.com","sentAt":"2009-02-18T00:49:01Z","receivedAt":"2009-02-18T00:49:01Z","isPatch":false,"sender":{"key":"bgoodr@gmail.com","avatar":"https://gravatar.com/avatar/2399bf5a3468b3516a892183edfd43a7fa0300a2e9d5072189020186961150bc?d=mp&s=160"},"body":"Suppose I create a git repo called central.git on a machine I will\ncall \"central\". In that central.git repo, I put these files:\n\n  work.sh\n  home.sh\n  generic.sh\n\nWhen I clone the central.git repo on to a different machine I will\ncall \"work\", I want this fileset to be pulled:\n\n  work.sh\n  generic.sh\n\nBut not the home.sh file.\n\nSimilarly, when I clone the central.git repo on a machine I will call\n\"home\", I want this fileset to be pulled:\n\n  home.sh\n  generic.sh\n\nBut not the work.sh file.\n\nWhat I think I need are two branches, one called \"home_branch\" and\n\"work_branch\", but read on for the twist:\n\nSay I'm working on editing the work machines fileset on the work repo\nI had cloned originally from central.git, and commit a change to both\ngeneric.sh and work.sh.  I do a git-push to an appropriate remote\nbranch I have set up on the central.git repo, so that I can do a\ngit-merge type of integration on the central machine in the\ncentral.git repo into the other branches (i.e., into the home_branch),\nspecifically so that the home_branch gets updated with the change to\nthe generic.sh file.  However, I want the home_branch to be updated\nwith the change I made to generic.sh, but I don't ever want the\nwork.sh to show up in the home_branch that would occur during a normal\nmerge. Likewise, I would not ever want the home.sh file to participate\nin merges from the work fileset back over to the home fileset (and\nlikewise I would not ever want to see the work.sh file show up on the\nhome_branch).\n\nThe above should apply for all files certain special directories. For\ninstance, if I were to have a work_files directory and a home_files\ndirectory, then the the work_files is for the \"work\" machine (and\nwork_branch) and the \"home_files\" is for the \"home\" machine (and\nhome_branch).\n\nHow do I mark certain files and/or directories (via relative file\npaths or with file globbing) on certain branches to be excluded from\nbeing merged into all other (or a specified list of) branches?\nIdeally I would want to only have to add some logic to the .git/config\nfile in the central.git repo that specifies the exclusions/exceptions,\nand not have to remember to make corresponding changes into any of the\nother repos that are cloned from it. Is this possible?\n\nAlso, is there a way to avoid the home.sh file from ever being added\nto any file underneath the .git directory of the repo I cloned on the\n\"work\" machine. I would not want there to be any risk that anyone with\nnetwork access to the \"work\" machine (say, a sysadmin with sufficient\nprivileges) to be able to see any form of the home.sh file since it\nexists on some branch in the .git directory.\n\nThanks,\nBrent\n"},{"id":"105254","messageId":"7v1vtw367w.fsf@gitster.siamese.dyndns.org","threadId":"17865","inReplyTo":"e38bce640902171649g765275a4n4e86d1d4f4aaf394@mail.gmail.com","subject":"Re: Is there a way to exclude user-specified files or directories from participating in merges?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-18T01:05:07Z","receivedAt":"2009-02-18T01:05:07Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brent Goodrick <bgoodr@gmail.com> writes:\n\n> Suppose I create a git repo called central.git on a machine I will\n> call \"central\". In that central.git repo, I put these files:\n>\n>   work.sh\n>   home.sh\n>   generic.sh\n>\n> When I clone the central.git repo on to a different machine I will\n> call \"work\", I want this fileset to be pulled:\n>\n>   work.sh\n>   generic.sh\n>\n> But not the home.sh file.\n\nYou would have one common branch and one branch per deployment.\n\nA common branch would host only common files (e.g. generic.sh file from\nyour example).  Per deployment branch, e.g. home, would branch from the\ncommon branch (so it starts with some version of generic.sh) and may add\nits own private files (e.g. home.sh).\n\nAnd stick to the following two rules:\n\n - You make edits to common files only on the common branch.\n - You merge from common to deployment, never the other way.\n\nSo at work, you would have a checkout of your work \"deployment branch\",\nand find needs to change things.  It is Ok to edit both work.sh and\ngeneric.sh (without being able to edit both, it would be hard to verify if\nthe changes would work together) at this time, but don't commit the result\nin the work branch.\n\nSave the changes to work.sh away (e.g. \"git diff work.sh >P.diff\" and then\n\"git checkout HEAD work.sh\"), switch to the common branch, and commit the\nchanges to the generic file.  Switch back to the deployment branch, merge\nthe common branch (to pick up the changes to home.sh), reapply the changes\nspecific to the deployment you saved earlier (e.g. \"git apply P.diff\"),\ntne commit the result.\n"},{"id":"105255","messageId":"e38bce640902171732j9b8801gca4223cdb96d2d34@mail.gmail.com","threadId":"17865","inReplyTo":"7v1vtw367w.fsf@gitster.siamese.dyndns.org","subject":"Re: Is there a way to exclude user-specified files or directories from participating in merges?","fromName":"Brent Goodrick","fromEmail":"bgoodr@gmail.com","sentAt":"2009-02-18T01:32:03Z","receivedAt":"2009-02-18T01:32:03Z","isPatch":false,"sender":{"key":"bgoodr@gmail.com","avatar":"https://gravatar.com/avatar/2399bf5a3468b3516a892183edfd43a7fa0300a2e9d5072189020186961150bc?d=mp&s=160"},"body":"On Tue, Feb 17, 2009 at 5:05 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> So at work, you would have a checkout of your work \"deployment branch\",\n> and find needs to change things.  It is Ok to edit both work.sh and\n> generic.sh (without being able to edit both, it would be hard to verify if\n> the changes would work together) at this time, but don't commit the result\n> in the work branch.\n>\n> Save the changes to work.sh away (e.g. \"git diff work.sh >P.diff\" and then\n> \"git checkout HEAD work.sh\"), switch to the common branch, and commit the\n> changes to the generic file.  Switch back to the deployment branch, merge\n> the common branch (to pick up the changes to home.sh), reapply the changes\n> specific to the deployment you saved earlier (e.g. \"git apply P.diff\"),\n> tne commit the result.\n>\n\nThanks. Well, I should have said in my initial request: \"Without\nmanually forwarding changes from branch to branch and without having\nto remember special rules about what I can and cannot merge into which\nbranch\", since that is likely to get forgotten. :)\n\nThe answer I am hearing you say is that git doesn't have a way to\nautomatically exclude files akin to how rsync handles include/exclude.\n Is that what you are saying? Or, could the hook mechanism be\nexploited to get this behavior?\n\nbg\n"},{"id":"105256","messageId":"7vmyck1q7i.fsf@gitster.siamese.dyndns.org","threadId":"17865","inReplyTo":"7v1vtw367w.fsf@gitster.siamese.dyndns.org","subject":"Re: Is there a way to exclude user-specified files or directories from participating in merges?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-18T01:36:17Z","receivedAt":"2009-02-18T01:36:17Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Brent Goodrick <bgoodr@gmail.com> writes:\n>\n>> Suppose I create a git repo called central.git on a machine I will\n>> call \"central\". In that central.git repo, I put these files:\n>>\n>>   work.sh\n>>   home.sh\n>>   generic.sh\n>>\n>> When I clone the central.git repo on to a different machine I will\n>> call \"work\", I want this fileset to be pulled:\n>>\n>>   work.sh\n>>   generic.sh\n>>\n>> But not the home.sh file.\n>\n> You would have one common branch and one branch per deployment.\n>\n> A common branch would host only common files (e.g. generic.sh file from\n> your example).  Per deployment branch, e.g. home, would branch from the\n> common branch (so it starts with some version of generic.sh) and may add\n> its own private files (e.g. home.sh).\n>\n> And stick to the following two rules:\n>\n>  - You make edits to common files only on the common branch.\n>  - You merge from common to deployment, never the other way.\n>\n> So at work, you would have a checkout of your work \"deployment branch\",\n> and find needs to change things.  It is Ok to edit both work.sh and\n> generic.sh (without being able to edit both, it would be hard to verify if\n> the changes would work together) at this time, but don't commit the result\n> in the work branch.\n>\n> Save the changes to work.sh away (e.g. \"git diff work.sh >P.diff\" and then\n> \"git checkout HEAD work.sh\"), switch to the common branch, and commit the\n> changes to the generic file.  Switch back to the deployment branch, merge\n> the common branch (to pick up the changes to home.sh), reapply the changes\n> specific to the deployment you saved earlier (e.g. \"git apply P.diff\"),\n> tne commit the result.\n\nBy the way, earlier in a different thread, somebody wondered if being able\nto make a commit on detached HEAD is a good thing, and this is a good\nexample of why it is convenient.  When I use the above \"one-way merge,\nnever merging back\" workflow in real life [*1*], I do not use a simple\n\"git diff work.sh >P.diff && git checkout HEAD work.sh\" to save away the\ntentative changes I made and verified on the deployment branch.  The above\nis an oversimplified example.\n\nFor one, in real life projects, there are many files that are specific to\nindividual deployments, and for another, distinction between generic vs\ndeployment specific changes does not cleanly appear at file boundaries.\n\nInstead, I would make a real commit, with full intention of discarding it\nlater.\n\n                  T work\n                 /\n         ...o---o\n               / \n       ...o---o common\n\nI would go back to common branch (\"git checkout common\"), cherry-pick the\ncommit from the deployment branch (\"git cherry-pick --no-commit work\").\nThis would conflict heavily because the common branch does not have any\nchanges specific to the deployment branch (i.e. files that were modified\nsince the deployment forked from the generic, and files the deployment\nadded).  That is Ok.  I would use \"git add -i\" and editor to sift out the\ndeployment specific parts to discard, and commit only the parts of the\nchange T made that are truly generic:\n\n                  T work\n                 /\n         ...o---o\n               / \n       ...o---o---A common\n\nThen I would go back to the deployment, and detach the head at commit\nbefore the tentative commit T.  From here, I can merge the common branch\nin.\n\n                  T work\n                 /\n         ...o---o HEAD\n               / \n       ...o---o---A common\n\n\"git merge common\" would make something like this:\n\n                  T work\n                 /\n         ...o---o---B HEAD\n               /   /\n       ...o---o---A common\n\nI know that the remainder of the change (i.e. difference between B and T)\nshould be the parts that are specific to the deployment.  After reading\nthrough the output of \"git diff HEAD work\" to make sure that it has all\ndeployment specific changes I made (and nothing that should have been in\nthe commit A on common), I would:\n\n\tgit read-tree -m -u work && git commit\n\nto grow the history of detached HEAD.\n\n                  T work\n                 /\n         ...o---o---B---C HEAD\n               /   /\n       ...o---o---A common\n\nAfter this step, just wrap it up with:\n\n\tgit branch -f work && git checkout work\n\nto reach the final state:\n\n                  T\n                 /\n         ...o---o---B---C work\n               /   /\n       ...o---o---A common\n\nThe tentative commit T becomes dangling but we know \"diff T C\" are empty\nand records the good state we verified when we made T.\n\nThis is one case I still use the plumbing \"read-tree -m -u\".\n\n\n[Footnote]\n\n*1* http://gitster.livejournal.com/26540.html\n"},{"id":"105259","messageId":"7vfxic1p6m.fsf@gitster.siamese.dyndns.org","threadId":"17865","inReplyTo":"e38bce640902171732j9b8801gca4223cdb96d2d34@mail.gmail.com","subject":"Re: Is there a way to exclude user-specified files or directories from participating in merges?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-18T01:58:25Z","receivedAt":"2009-02-18T01:58:25Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brent Goodrick <bgoodr@gmail.com> writes:\n\n> Thanks. Well, I should have said in my initial request: \"Without\n> manually forwarding changes from branch to branch and without having\n> to remember special rules about what I can and cannot merge into which\n> branch\", since that is likely to get forgotten. :)\n>\n> The answer I am hearing you say is that git doesn't have a way to\n> automatically exclude files akin to how rsync handles include/exclude.\n>  Is that what you are saying? Or, could the hook mechanism be\n> exploited to get this behavior?\n\nA merge is defined as a whole tree operation simply because there is no\nsane way to support repeated merges (even a single direction merges)\notherwise.  What I explained was one (note that I am not saying \"one true\"\nhere) workflow that naturally supports \"common version and multiple\nvariants\" pattern that logically follows the definition of what a merge\nis.\n\nI would imagine you could define a custom merge strategy that knows to\nignore changes you made to work.sh file when you merge from work to common\n(and home.sh file when you merge from home to common) to implement what\nyou would want, but for one thing the resulting history would not make\nsense (e.g. a merge from work to central would appear as if it reverts all\nthe changes work made to certain files).  It would be Ok if you were using\ngit as a mere backup+sneakernet medium (in such a case you would not care\nwhat the history would show you), but that is not the intended target of\ngit, so there is no such built-in support.\n\nAlso such a custom merge strategy would be very project specific and as\nyour project grows and/or as you add more deployments, I suspect its rules\nwill have to become a lot more complicated.  I haven't even thought about\nwhat should happen in such a merge strategy when you try to merge work to\nhome.\n\nCompared to that, the two simple rules \"commit chagnes to generic things\nonly to the generic branch\" and \"merge only from generic to specific\" will\nnot grow as your project grows complexity.\n"},{"id":"105270","messageId":"e38bce640902172139h6ddda8e8va089e514e625de52@mail.gmail.com","threadId":"17865","inReplyTo":"7vfxic1p6m.fsf@gitster.siamese.dyndns.org","subject":"Re: Is there a way to exclude user-specified files or directories from participating in merges?","fromName":"Brent Goodrick","fromEmail":"bgoodr@gmail.com","sentAt":"2009-02-18T05:39:12Z","receivedAt":"2009-02-18T05:39:12Z","isPatch":false,"sender":{"key":"bgoodr@gmail.com","avatar":"https://gravatar.com/avatar/2399bf5a3468b3516a892183edfd43a7fa0300a2e9d5072189020186961150bc?d=mp&s=160"},"body":"On Tue, Feb 17, 2009 at 5:58 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Compared to that, the two simple rules \"commit changes to generic things\n> only to the generic branch\" and \"merge only from generic to specific\" will\n> not grow as your project grows in complexity.\n\nI now I see the wisdom of the above statement.  You've given me a lot\nof approaches to think about and try. Thanks for your help!\n\nbg\n"},{"id":"105303","messageId":"slrngpo3hp.boq.sitaramc@sitaramc.homelinux.net","threadId":"17865","inReplyTo":"7v1vtw367w.fsf@gitster.siamese.dyndns.org","subject":"Re: Is there a way to exclude user-specified files or directories from participating in merges?","fromName":"Sitaram Chamarty","fromEmail":"sitaramc@gmail.com","sentAt":"2009-02-18T13:33:45Z","receivedAt":"2009-02-18T13:33:45Z","isPatch":false,"sender":{"key":"sitaramc@gmail.com","avatar":"https://avatars.githubusercontent.com/u/43316?v=4"},"body":"On 2009-02-18, Junio C Hamano <gitster@pobox.com> wrote:\n> And stick to the following two rules:\n>\n>  - You make edits to common files only on the common branch.\n>  - You merge from common to deployment, never the other way.\n>\n> So at work, you would have a checkout of your work \"deployment branch\",\n> and find needs to change things.  It is Ok to edit both work.sh and\n> generic.sh (without being able to edit both, it would be hard to verify if\n> the changes would work together) at this time, but don't commit the result\n> in the work branch.\n>\n> Save the changes to work.sh away (e.g. \"git diff work.sh >P.diff\" and then\n> \"git checkout HEAD work.sh\"), switch to the common branch, and commit the\n> changes to the generic file.  Switch back to the deployment branch, merge\n> the common branch (to pick up the changes to home.sh), reapply the changes\n> specific to the deployment you saved earlier (e.g. \"git apply P.diff\"),\n> tne commit the result.\n\n[I did read your followup also; my question applies to both\nversions of the technique]\n\nLet me explain where I'm coming from: this is very often\nneeded when you maintain customer specific branches, and the\nworkflows in both your posts in this thread so far are too\ncomplex for, err, me <sheepish grin> :-)\n\nWould it not be easier to do something like this?  (I suck\nat 2-d drawing, even line... but this should still be\nunderstandable)\n\n(W = work, T = temporary, C = common)\n\n  - make granular commits and test etc, from W to T\n\n        O---a---b+1---c---2---d---3\n        W is pointing at commit O\n        T is pointing at commit 3\n        b+1 is a commit that contains both types of changes\n\n  - use rebase -i (including split commits if needed, as\n    described in 'git help rebase') to put all the changes\n    that go to master before the ones that only go to work.\n\n        O---a---b---c---d---1---2---3\n\n  - (retest if needed)\n\n  - cherry pick the first set of changes to common (in this\n    example, a, b, c, d will become a', etc on common)\n\n  - merge from common to work (x, y, etc are some other\n    changes that went into common since the last time you\n    merged)\n\n        O---x---y---a'---b'---c'---d'\n        W is now pointing at d'\n\n  - cherry pick the stuff that remains\n\n        O---x---y---a'---b'---c'---d'---1'---2'---3'\n        W is now pointing at 3'\n"},{"id":"105331","messageId":"7v3aeby3eh.fsf@gitster.siamese.dyndns.org","threadId":"17865","inReplyTo":"slrngpo3hp.boq.sitaramc@sitaramc.homelinux.net","subject":"Re: Is there a way to exclude user-specified files or directories from participating in merges?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-18T19:02:30Z","receivedAt":"2009-02-18T19:02:30Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sitaram Chamarty <sitaramc@gmail.com> writes:\n\n> Let me explain where I'm coming from: this is very often needed when you\n> maintain customer specific branches, and the workflows in both your\n> posts in this thread so far are too complex for, err, me <sheepish grin>\n> :-)\n>\n> Would it not be easier to do something like this?  (I suck at 2-d\n> drawing, even line... but this should still be understandable)\n\nWhat you drew is a detailed discussion on a technique to use to group\ntogether common part and customer specific part, and I think it is Ok to\ndo whatever you feel comfortable with.  It is essentially the same as my\n\"in real life, 'git diff >P.diff' is not how I would do this\" example,\njust going into more detail on what you would do to sift 'common only' vs\n'specific to work branch' apart, and I think what you are doing is sane.\n\nBut if you wrote it as a draft of a document to explain how-to to new\npeople, I think you need to clarify a few things.\n\nIt is unclear in your description how the \"common\" branch progressed in\nthe whole process, and how the resulting history looks.  I can guess that\nyou meant commits marked with alphabet letters are of common kind and\nnumbers are of work kind, but you do not want to force readers to guess.\n\nIt also is not quite clear that you are using a temporary branch in\naddition to common and work, and where in your sequence you are doing \"git\ncheckout\" to switch branches.\n"},{"id":"105461","messageId":"slrngpqo5k.j03.sitaramc@sitaramc.homelinux.net","threadId":"17865","inReplyTo":"7v3aeby3eh.fsf@gitster.siamese.dyndns.org","subject":"Re: Is there a way to exclude user-specified files or directories from participating in merges?","fromName":"Sitaram Chamarty","fromEmail":"sitaramc@gmail.com","sentAt":"2009-02-19T13:37:56Z","receivedAt":"2009-02-19T13:37:56Z","isPatch":false,"sender":{"key":"sitaramc@gmail.com","avatar":"https://avatars.githubusercontent.com/u/43316?v=4"},"body":"On 2009-02-18, Junio C Hamano <gitster@pobox.com> wrote:\n> Sitaram Chamarty <sitaramc@gmail.com> writes:\n>\n> > Let me explain where I'm coming from: this is very often needed when you\n> > maintain customer specific branches, and the workflows in both your\n> > posts in this thread so far are too complex for, err, me <sheepish grin>\n> > :-)\n> >\n> > Would it not be easier to do something like this?  (I suck at 2-d\n> > drawing, even line... but this should still be understandable)\n> \n> What you drew is a detailed discussion on a technique to use to group\n> together common part and customer specific part, and I think it is Ok to\n> do whatever you feel comfortable with.  It is essentially the same as my\n> \"in real life, 'git diff >P.diff' is not how I would do this\" example,\n> just going into more detail on what you would do to sift 'common only' vs\n> 'specific to work branch' apart, and I think what you are doing is sane.\n\nThanks -- I mainly wanted confirmation that one does *not*\nhave to do diff/patch/apply or plumbing commands to achieve\nwhat the original poster was asking.\n\n> But if you wrote it as a draft of a document to explain how-to to new\n> people, I think you need to clarify a few things.\n\n> It is unclear in your description how the \"common\" branch progressed in\n> the whole process, and how the resulting history looks.  I can guess that\n> you meant commits marked with alphabet letters are of common kind and\n> numbers are of work kind, but you do not want to force readers to guess.\n\n> It also is not quite clear that you are using a temporary branch in\n> addition to common and work, and where in your sequence you are doing \"git\n> checkout\" to switch branches.\n\nI did not write it in that light then, but I will do so now,\nand if you have a few minutes to critique it that would be\ngreat.  If it's crap, sorry for the noise.\n\n----->8-----\n\nThe following document explains how to maintain a 'common'\nbranch, with one or more 'customer specific' branches that\nhang off of the common branch.  The inspiration was a\nquestion about maintaining 'work' and 'home' configurations\nwhich differ perhaps slightly from a 'common' configuration,\nwhich leads to the same sort of situation.\n\nThe basic rules are best described by Junio in\nhttp://permalink.gmane.org/gmane.comp.version-control.git/110489\n\n>  - You make edits to common files only on the common branch.\n>  - You merge from common to deployment, never the other way.\n\nThis is one way to follow those rules.\n\nWe use the following terminology:\n\n'common' is the branch representing the base product.  All\nregular customers get this version.\n\n'special' is a special branch for a specific customer.  This\ncustomer needs changes unique to his environment, which\nshould not be merged back into the common branch.  However,\nthis branch must regularly get the benefit of changes in the\nmainline 'common' branch.  (This is the genesis of the two\nrules above).\n\nIf you have more than one special customer the same logic\nwill apply for each of them separately, although if you have\ntoo many such customers you may also want to look at \"Never\nmerging back\" (http://gitster.livejournal.com/26540.html)\nfor an additional tip on this.\n\nAlso, we assume the actual development and testing needs to\nbe done on one branch, so you will have a mix of 'common'\nand 'special' changes all together.\n\nThe history looks like this in the beginning:\n\n    -----o          <- special branch (current)\n        /\n    ---o            <- common branch\n\nBefore you start, make a temporary branch TEMP from\n'special'; leave special where it was.\n\n    git checkout -b TEMP special\n\nYou now make some changes for the special customer, which\nalso involve some 'common' changes that need to be ported\nback to the common branch.  The topology now looks like\nthis, where A, B, C, are changes that logically belong on\n'common', and 1, 2, 3, are changes that are specific to this\ncustomer.\n\nNotice that the 2 sets of changes are intermixed because\nthat is how the development happened, and that there is even\none commit where common and special changes are mixed\n(perhaps you realised this only later).\n\n    -----o--A--B1--2--3--C          <- \"TEMP\" branch (current)\n        /\n    ---o                            <- common\n\nMeanwhile, just to make things interesting, the common\nbranch has also had some other, unrelated changes which you\neventually want on the special branch as well.\n\n    -----o--A--B1--2--3--C          <- \"TEMP\" branch (current)\n        /                                            \n    ---o--X--Y                      <- common\n\nThe first thing to do is to tease the tangled commits apart\nusing rebase.\n\nUsing 'git rebase -i special', get the topology into this\nshape.  Note that we have split the \"B1\" commit into B and 1\nseparately.  'git help rebase' has a very simple and clear\nsection on splitting commits, so I will not detail that\nhere.\n\n    -----o--A--B--C--1--2--3        <- \"TEMP\" branch (current)\n        /                                              \n    ---o--X--Y                      <- common\n\nAt this point you may want to retest, just to be sure.\n\nNow switch to the 'common' branch and cherry pick the\nchanges that belong on 'common'.  The simplest way to cherry\npick is gitk.\n\n    git checkout common\n    gitk\n    # and cherry pick first A, then B, then C, in order\n\n    -----o--A--B--C--1--2--3        <- \"TEMP\" branch\n        /                                              \n    ---o--X--Y--A'--B'--C'          <- common (current)\n\nNow merge from 'common' to 'special'\n\n    git checkout special\n    git merge common\n\n           A--B--C--1--2--3     <- TEMP\n          /\n     ----o-----------------o    <- special (current)\n        /                 /\n    ---o--X--Y--A'--B'--C'\n\nNow all we need is to get commits 1, 2, and 3 onto\n'special'; this is easiest done by rebasing TEMP first...\n\n    git rebase special TEMP\n\n                             1'--2'--3'     <- TEMP (current)\n                            /\n     ----o-----------------o    <- special\n        /                 /\n    ---o--X--Y--A'--B'--C'\n\n...and then making special equal to TEMP\n\n    git checkout special\n    git merge TEMP\n\n                             1'--2'--3'     <- special (current)\n                            /\n     ----o-----------------o\n        /                 /\n    ---o--X--Y--A'--B'--C'\n\nNow you don't need TEMP anymore, and can delete it:\n\n    git branch -d TEMP\n"}]}