{"thread":{"id":"21787","subject":"What is the best way to backport a feature?","startedAt":"2009-11-29T16:28:17Z","lastAt":"2009-11-30T19:08:05Z","messageCount":10,"participants":["Peter Weseloh","Björn Steinbrink","Pascal Obry","Michael J Gruber","Johannes Sixt","Greg A. Woods"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"128688","messageId":"loom.20091129T164518-669@post.gmane.org","threadId":"21787","inReplyTo":null,"subject":"What is the best way to backport a feature?","fromName":"Peter Weseloh","fromEmail":"peter.weseloh@gmail.com","sentAt":"2009-11-29T16:28:17Z","receivedAt":"2009-11-29T16:28:17Z","isPatch":false,"sender":{"key":"peter.weseloh@gmail.com","avatar":null},"body":"Hi,\n\nSuppose I have the following situation:\n\n  o--o--o                    Release_1.0\n /    \\  \\                  \no-o-o--o--o-o-o-o-o-o---o--o Mainline\n     \\       \\       \\ /    \n      F1--F2--M1--F3--M2     Feature_A\n\nNow I want to backport \"Feature_A\" to the \"Release_1.0\" branch so that it gets\nincluded into the next minor release, i.e. I want to apply the commits F1, F2\nand F3 onto the \"Release_1.0\" branch.\nI cannot just merge \"Feature_A\" into \"Release_1.0\" because that would also bring\nin the merges M1 and M2 so a lot of other stuff from the Mainline.\n\nI played with cherry-pick but that means I have to manually find the commits F1,\nF2 and F3 (which in reality could be many more if Feature_A is big) which is not\nvery nice.\n\nI also tried 'rebase -i' but that means I have to manually delete all the lines\nfor changesets from the mainline. Also not very nice.\n\nIs there a better way? To me this scenario sounds not unusual but I could not\nfind a solution.\n\nThanks,\nPeter\n"},{"id":"128690","messageId":"20091129164748.GB7921@atjola.homenet","threadId":"21787","inReplyTo":"loom.20091129T164518-669@post.gmane.org","subject":"Re: What is the best way to backport a feature?","fromName":"Björn Steinbrink","fromEmail":"b.steinbrink@gmx.de","sentAt":"2009-11-29T16:47:48Z","receivedAt":"2009-11-29T16:47:48Z","isPatch":false,"sender":{"key":"b.steinbrink@gmx.de","avatar":"https://avatars.githubusercontent.com/u/230962?v=4"},"body":"On 2009.11.29 16:28:17 +0000, Peter Weseloh wrote:\n> Suppose I have the following situation:\n>\n>   o--o--o                    Release_1.0\n>  /    \\  \\\n> o-o-o--o--o-o-o-o-o-o---o--o Mainline\n>      \\       \\       \\ /\n>       F1--F2--M1--F3--M2     Feature_A\n>\n> Now I want to backport \"Feature_A\" to the \"Release_1.0\" branch so that\n> it gets included into the next minor release, i.e. I want to apply the\n> commits F1, F2 and F3 onto the \"Release_1.0\" branch.\n\n> Is there a better way? To me this scenario sounds not unusual but I\n> could not find a solution.\n\nWhat's unusual there is that you merged from Mainline to Feature_A.\nUsually, the history would look like this:\n\n   o--o--o                    Release_1.0\n  /    \\  \\\n o-o-o--o--o-o-o-o-o-o---o--o Mainline\n      \\                 /\n       F1-----F2------F3      Feature_A\n\nAnd then you could easily use rebase to get the job done.\n\nHad you known beforehand that Feature_A is a candidate for backporting,\nyou would have even branch from an older commit like this:\n\n   o--o--o                    Release_1.0\n  /    \\  \\\n o-o-o--o--o-o-o-o-o-o---o--o Mainline\n  \\                     /\n   F1--------F2-------F3      Feature_A\n\nThen you could easily merge Feature_A to Release_1.0 as well, without\nmerging anything unrelated.\n\nBut that's just for the future...\n\nGiven you current history, you could use format-patch + am like this:\n\ngit format-patch --stdout --first-parent Mainline..Feature_A > fa.mbox\ngit checkout Release_1.0\ngit am -3 fa.mbox\n\nThe --first-parent options make it follow the first parent of the merge\ncommits only, so the whole stuff on the Mainline branch is ignored. And\nyou just get F1, F2 and F3 in fa.mbox, which you then apply using am.\n\nA long time ago, I hacked the --first-parent thing into rebase, but (of\ncourse) the first iteration of the patch wasn't quite perfect and as\nI've not been scratching my own itch there, I never got around to\nactually polish the patch so it could get into git.git. Maybe you want\nto pick it up?\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/62782\n\nBjörn\n"},{"id":"128691","messageId":"4B12A631.8020200@obry.net","threadId":"21787","inReplyTo":"loom.20091129T164518-669@post.gmane.org","subject":"Re: What is the best way to backport a feature?","fromName":"Pascal Obry","fromEmail":"pascal@obry.net","sentAt":"2009-11-29T16:49:53Z","receivedAt":"2009-11-29T16:49:53Z","isPatch":false,"sender":{"key":"pascal@obry.net","avatar":"https://avatars.githubusercontent.com/u/467069?v=4"},"body":"Le 29/11/2009 17:28, Peter Weseloh a écrit :\n> Hi,\n>\n> Suppose I have the following situation:\n>\n>    o--o--o                    Release_1.0\n>   /    \\  \\\n> o-o-o--o--o-o-o-o-o-o---o--o Mainline\n>       \\       \\       \\ /\n>        F1--F2--M1--F3--M2     Feature_A\n>\n> Now I want to backport \"Feature_A\" to the \"Release_1.0\" branch so that it gets\n> included into the next minor release, i.e. I want to apply the commits F1, F2\n> and F3 onto the \"Release_1.0\" branch.\n> I cannot just merge \"Feature_A\" into \"Release_1.0\" because that would also bring\n> in the merges M1 and M2 so a lot of other stuff from the Mainline.\n>\n> I played with cherry-pick but that means I have to manually find the commits F1,\n> F2 and F3 (which in reality could be many more if Feature_A is big) which is not\n> very nice.\n>\n> I also tried 'rebase -i' but that means I have to manually delete all the lines\n> for changesets from the mainline. Also not very nice.\n>\n> Is there a better way? To me this scenario sounds not unusual but I could not\n> find a solution.\n\nIn such a case I would use a rebase onto:\n\n    $ git co Feature_A\n    $ git rebase --onto Release_1.0 F1 F3\n\nThen\n\n    $ git co Release_1.0\n    $ git merge Feature_A\n\nPascal.\n\n-- \n\n--|------------------------------------------------------\n--| Pascal Obry                           Team-Ada Member\n--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE\n--|------------------------------------------------------\n--|    http://www.obry.net  -  http://v2p.fr.eu.org\n--| \"The best way to travel is by means of imagination\"\n--|\n--| gpg --keyserver keys.gnupg.net --recv-key F949BD3B\n"},{"id":"128693","messageId":"4B12A6E8.8050803@obry.net","threadId":"21787","inReplyTo":"20091129164748.GB7921@atjola.homenet","subject":"Re: What is the best way to backport a feature?","fromName":"Pascal Obry","fromEmail":"pascal@obry.net","sentAt":"2009-11-29T16:52:56Z","receivedAt":"2009-11-29T16:52:56Z","isPatch":false,"sender":{"key":"pascal@obry.net","avatar":"https://avatars.githubusercontent.com/u/467069?v=4"},"body":"Le 29/11/2009 17:47, Björn Steinbrink a écrit :\n> What's unusual there is that you merged from Mainline to Feature_A.\n> Usually, the history would look like this:\n\nRight, I missed that! It is indeed very unusual at the point that I \nmissed to read it properly :) So my reply is wrong.\n\nPascal.\n\n-- \n\n--|------------------------------------------------------\n--| Pascal Obry                           Team-Ada Member\n--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE\n--|------------------------------------------------------\n--|    http://www.obry.net  -  http://v2p.fr.eu.org\n--| \"The best way to travel is by means of imagination\"\n--|\n--| gpg --keyserver keys.gnupg.net --recv-key F949BD3B\n"},{"id":"128694","messageId":"4B12A928.2000401@drmicha.warpmail.net","threadId":"21787","inReplyTo":"loom.20091129T164518-669@post.gmane.org","subject":"Re: What is the best way to backport a feature?","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2009-11-29T17:02:32Z","receivedAt":"2009-11-29T17:02:32Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Peter Weseloh venit, vidit, dixit 29.11.2009 17:28:\n> Hi,\n> \n> Suppose I have the following situation:\n> \n>   o--o--o                    Release_1.0\n>  /    \\  \\                  \n> o-o-o--o--o-o-o-o-o-o---o--o Mainline\n>      \\       \\       \\ /    \n>       F1--F2--M1--F3--M2     Feature_A\n> \n> Now I want to backport \"Feature_A\" to the \"Release_1.0\" branch so that it gets\n> included into the next minor release, i.e. I want to apply the commits F1, F2\n> and F3 onto the \"Release_1.0\" branch.\n> I cannot just merge \"Feature_A\" into \"Release_1.0\" because that would also bring\n> in the merges M1 and M2 so a lot of other stuff from the Mainline.\n> \n> I played with cherry-pick but that means I have to manually find the commits F1,\n> F2 and F3 (which in reality could be many more if Feature_A is big) which is not\n> very nice.\n> \n> I also tried 'rebase -i' but that means I have to manually delete all the lines\n> for changesets from the mainline. Also not very nice.\n> \n> Is there a better way? To me this scenario sounds not unusual but I could not\n> find a solution.\n\nThe problem is that you've been a bad boy to begin with ;)\n\nSeriously, I suggest reading up on \"topic branches\". Feature_A should\nhave been based off the common merge base of Mainline and Release_1.0,\nand, even more importantly, there should not have been any merges from\nMainline into Feature_A. So, that branch is not at all what one would\ncall a feature branch/topic branch. Hopefully, this scenario is very\nuncommon :)\n\nI assume you have to deal with the given structure anyhow, and merge\nwill not help. The only solution is to try and replay your Feature_A\ncommits on top of the release branch. (Since you have merged Feature_A\ninto Mainline already, you probabably don't want to redo that branch and\nmerge.)\n\nI you have many commits to deal with I suggest finding a good\nsemi-automated way to list the commits you are after, such as git\nrev-list --no-merges sha1..Feature_A (with sha1 being the fork point). A\ngood way to find out could be git log --no-merges sha1..Feature_A.\n\nThen, try and cherry-pick those onto the release branch. Alternatively,\nyou can use format-patch/am, or in fact try with rebase (I thought it\nwould ignore merges), which basically does what cherry-pick does.\n\nCheers,\nMichael\n"},{"id":"128695","messageId":"4db3b0200911290945r34a73346w148ee42e59868876@mail.gmail.com","threadId":"21787","inReplyTo":"4db3b0200911290941j42c5a0aaq2c6a9836b38066b2@mail.gmail.com","subject":"Fwd: What is the best way to backport a feature?","fromName":"Peter Weseloh","fromEmail":"peter.weseloh@googlemail.com","sentAt":"2009-11-29T17:45:34Z","receivedAt":"2009-11-29T17:45:34Z","isPatch":false,"sender":{"key":"peter.weseloh@googlemail.com","avatar":null},"body":"Hi Björn,\n\nFirst of all thank you very much for your quick reply (actually my\nthanks go to all that have replied so far).\nNote that at the moment it is just a brain exercise. We are currently\nusing CVS (yes, I know) and want to switch to something else and I'm\ntrying to push for git. During our discussions this scenario came up\nand I could not give a simple answer. That's why I thought I'd better\nask the experts.\n\n\n> What's unusual there is that you merged from Mainline to Feature_A.\n> Usually, the history would look like this:\n>\n>   o--o--o                    Release_1.0\n>  /    \\  \\\n>  o-o-o--o--o-o-o-o-o-o---o--o Mainline\n>      \\                 /\n>       F1-----F2------F3      Feature_A\n>\n> And then you could easily use rebase to get the job done.\n\nBut on the other hand the intermediate merges from the Mainline make\nfor much simpler merges, right?.\nIf merging is done only when Feature_A is ready it might become a real\npain. It might take several month to complete it and the mainline\nmight have changed a lot.\n\n>\n> Had you known beforehand that Feature_A is a candidate for backporting,\n> you would have even branch from an older commit like this:\n>\n>   o--o--o                    Release_1.0\n>  /    \\  \\\n>  o-o-o--o--o-o-o-o-o-o---o--o Mainline\n>  \\                     /\n>   F1--------F2-------F3      Feature_A\n>\n>\n> Then you could easily merge Feature_A to Release_1.0 as well, without\n> merging anything unrelated.\n>\n> But that's just for the future...\n>\n\nYes, sure. If I would know the future already today I would not need\nto do any coding anymore :-) But seriously our policy is clear:\nBugfixes (and small enhancements) go to the release branch to end up\nin the next minor release. The release branch gets merged with the\nmainline so that it is always a superset. Big new features are\ndeveloped in seperated branches and are finaly merged to the mainline\nto end up in the next major release. But every now and then the\nmanagment is so excited about such a new feature that they want it in\nthe next minor release. That's life.\n\n>\n> Given you current history, you could use format-patch + am like this:\n>\n> git format-patch --stdout --first-parent Mainline..Feature_A > fa.mbox\n> git checkout Release_1.0\n> git am -3 fa.mbox\n>\n> The --first-parent options make it follow the first parent of the merge\n> commits only, so the whole stuff on the Mainline branch is ignored. And\n> you just get F1, F2 and F3 in fa.mbox, which you then apply using am.\n>\n\nAh, great! I played with format-patch + am but missed the\n'--first-parent' option. I will give it a try. Thanks a lot!\n\n>\n> A long time ago, I hacked the --first-parent thing into rebase, but (of\n> course) the first iteration of the patch wasn't quite perfect and as\n> I've not been scratching my own itch there, I never got around to\n> actually polish the patch so it could get into git.git. Maybe you want\n> to pick it up?\n>\n> http://thread.gmane.org/gmane.comp.version-control.git/62782\n\nIn case we go for git this might very well be the case.\n>\n> Björn\n\nPeter\n"},{"id":"128696","messageId":"20091129181758.GA9533@atjola.homenet","threadId":"21787","inReplyTo":"4db3b0200911290941j42c5a0aaq2c6a9836b38066b2@mail.gmail.com","subject":"Re: What is the best way to backport a feature?","fromName":"Björn Steinbrink","fromEmail":"b.steinbrink@gmx.de","sentAt":"2009-11-29T18:17:58Z","receivedAt":"2009-11-29T18:17:58Z","isPatch":false,"sender":{"key":"b.steinbrink@gmx.de","avatar":"https://avatars.githubusercontent.com/u/230962?v=4"},"body":"On 2009.11.29 18:41:35 +0100, Peter Weseloh wrote:\n> >  What's unusual there is that you merged from Mainline to Feature_A.\n> > Usually, the history would look like this:\n> >\n> >   o--o--o                    Release_1.0\n> >  /    \\  \\\n> >  o-o-o--o--o-o-o-o-o-o---o--o Mainline\n> >      \\                 /\n> >       F1-----F2------F3      Feature_A\n> >\n> > And then you could easily use rebase to get the job done.\n> \n> But on the other hand the intermediate merges from the Mainline make for\n> much simpler merges, right?.\n> If merging is done only when Feature_A is ready it might become a real pain.\n\nThat's usually more often true with CVS or SVN than with git, but ...\n\n> It might take several month to complete it and the mainline might have\n> changed a lot.\n\n... over such a long timeframe, yes, things might become ugly. OTOH such\na long timeframe might also mean that the topic branch actually does too\nmuch. Splitting such a large thing into more manageable pieces would\nhelp there, as you could merge completed topic branch to your mainline\nbranch earlier and more often.\n\n> > Had you known beforehand that Feature_A is a candidate for backporting,\n> > you would have even branch from an older commit like this:\n> >\n> >   o--o--o                    Release_1.0\n> >  /    \\  \\\n> >  o-o-o--o--o-o-o-o-o-o---o--o Mainline\n> >  \\                     /\n> >   F1--------F2-------F3      Feature_A\n> >\n> > Then you could easily merge Feature_A to Release_1.0 as well, without\n> > merging anything unrelated.\n> >\n> > But that's just for the future...\n> >\n> Yes, sure. If I would know the future already today I would not need to do\n> any coding anymore :-)\n\nI meant something like \"I just said that, so you can avoid problems in\nthe future\" ;-) But yeah, knowing beforehand that things should go into\na maintenance branch isn't common, unless it's about a bugfix.\n\n> > Given you current history, you could use format-patch + am like this:\n> >\n> > git format-patch --stdout --first-parent Mainline..Feature_A > fa.mbox\n> > git checkout Release_1.0\n> > git am -3 fa.mbox\n> >\n> > The --first-parent options make it follow the first parent of the merge\n> > commits only, so the whole stuff on the Mainline branch is ignored. And\n> > you just get F1, F2 and F3 in fa.mbox, which you then apply using am.\n> >\n> >\n> Ah, great! I played with format-patch + am but missed the '--first-parent'\n> option. I will give it a try. Thanks a lot!\n\nWell, it's a rev-list option, which might work by accident. Junio\nrecently said that the fact that format-patch accepts path limiting is\nby accident, might be true for --first-parent as well... No clue. Junio?\n\nBjörn\n"},{"id":"128700","messageId":"200911291933.54301.j6t@kdbg.org","threadId":"21787","inReplyTo":"4db3b0200911290945r34a73346w148ee42e59868876@mail.gmail.com","subject":"Re: Fwd: What is the best way to backport a feature?","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2009-11-29T18:33:53Z","receivedAt":"2009-11-29T18:33:53Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"[please keep the Cc list]\n\nOn Sonntag, 29. November 2009, Peter Weseloh wrote:\n> But on the other hand the intermediate merges from the Mainline make\n> for much simpler merges, right?.\n> If merging is done only when Feature_A is ready it might become a real\n> pain. It might take several month to complete it and the mainline\n> might have changed a lot.\n\nIncidentally, Junio has blogged about this just the other day:\n\nhttp://gitster.livejournal.com/42247.html\n\nBasically, as soon as you merge Mainline into Feature_A, you change the topic \nof Feature_A from \"Feature for Release_1.0\" to \"Feature for this Mainline\". \nClearly, this topic is not suitable for Release_1.0 anymore.\n\nThere is a way around this that doesn't sacrifice the topic-oriented nature of \nthe branch: You keep developing Feature_A as planned for Release_1.0 and when \nyou notice that merging this feature to Mainline will become increasingly \ncomplex, you fork off a new branch Feature_A_for_Release_2.0 from Mainline \nand merge Feature_A into this new branch:\n\n   o--o--o                    Release_1.0\n  /    \\  \\\n o-o-o--o--o-o-o-o-X-o---o--o Mainline\n      \\             \\\n       F1            o--o     Feature_A_for_Release_2.0   \n        \\           /  /\n         F2--------F3-F4      Feature_A\n\nThe fork point X must be in Release_2.0.\n\n-- Hannes\n"},{"id":"128701","messageId":"4db3b0200911291103x6430e563rb86330284a4c2c7b@mail.gmail.com","threadId":"21787","inReplyTo":"200911291933.54301.j6t@kdbg.org","subject":"Re: Fwd: What is the best way to backport a feature?","fromName":"Peter Weseloh","fromEmail":"peter.weseloh@googlemail.com","sentAt":"2009-11-29T19:03:28Z","receivedAt":"2009-11-29T19:03:28Z","isPatch":false,"sender":{"key":"peter.weseloh@googlemail.com","avatar":null},"body":"2009/11/29 Johannes Sixt <j6t@kdbg.org>:\n> [please keep the Cc list]\nSorry!\n>\n> http://gitster.livejournal.com/42247.html\n>\n> Basically, as soon as you merge Mainline into Feature_A, you change the topic\n> of Feature_A from \"Feature for Release_1.0\" to \"Feature for this Mainline\".\n> Clearly, this topic is not suitable for Release_1.0 anymore.\n>\n> There is a way around this that doesn't sacrifice the topic-oriented nature of\n> the branch: You keep developing Feature_A as planned for Release_1.0 and when\n> you notice that merging this feature to Mainline will become increasingly\n> complex, you fork off a new branch Feature_A_for_Release_2.0 from Mainline\n> and merge Feature_A into this new branch:\n>\n>   o--o--o                    Release_1.0\n>  /    \\  \\\n>  o-o-o--o--o-o-o-o-X-o---o--o Mainline\n>      \\             \\\n>       F1            o--o     Feature_A_for_Release_2.0\n>        \\           /  /\n>         F2--------F3-F4      Feature_A\n>\n> The fork point X must be in Release_2.0.\n\nThat makes perfect sense. I will discuss your suggestion with my\ncolleagues and will send them the link you mentioned. It's just that\nbranching and especially merging with CVS is so painful that they\nmight get scared :-). With git that's completly different, of course.\n\nThanks a lot,\nPeter\n"},{"id":"128798","messageId":"m1NFBbV-000kn2C@most.weird.com","threadId":"21787","inReplyTo":"4B12A928.2000401@drmicha.warpmail.net","subject":"Re: What is the best way to backport a feature?","fromName":"Greg A. Woods","fromEmail":"woods@planix.com","sentAt":"2009-11-30T19:08:05Z","receivedAt":"2009-11-30T19:08:05Z","isPatch":false,"sender":{"key":"woods@planix.com","avatar":null},"body":"Hmmm.... this topic seems in part to be very close to my thread\n\t \"git merge\" merges too much!\n\nAt Sun, 29 Nov 2009 18:02:32 +0100, Michael J Gruber <git@drmicha.warpmail.net> wrote:\nSubject: Re: What is the best way to backport a feature?\n> \n> Seriously, I suggest reading up on \"topic branches\". Feature_A should\n> have been based off the common merge base of Mainline and Release_1.0,\n> and, even more importantly, there should not have been any merges from\n> Mainline into Feature_A. So, that branch is not at all what one would\n> call a feature branch/topic branch. Hopefully, this scenario is very\n> uncommon :)\n\nIFF I understand the original post correctly then actually in my\nexperience this scenario is VERY common in some environments!\n\nThis is exactly how large projects which use the likes of CVS (and SVN?)\nmanage longer-running development branches for important new features.\n\nOne excellent example is NetBSD (and perhaps the other BSDs too).\n\nA developer creates a \"working\" branch from the trunk, then begins to\nmake changes and commits to that branch.  Periodically the (entire)\ntrunk is merged again to the working branch.  I think this is somewhat\nequivalent to using \"git rebase\" to re-apply the feature branch to a new\nfork point from the trunk.  However the actual branch base point remains\nat the original point -- it is only the delta between the last merge\nfrom trunk and the current head of the trunk which is merged onto the\nfeature working branch.  I think this is what people in the CVS world\nmean when they say they want the tool to remember the point on the\nsource branch from where they did the last merge.  They've got their\nwork-flow \"backwards\", but this is the best they can do with CVS.\n\nThese periodic merges from the trunk mean that once the feature is\nfinished the delta between the trunk and the new feature branch is going\nto be just the new feature, and so merging that delta alone to the trunk\nas one commit adds the new feature to the trunk with few or no\nconflicts, and the feature working branch can finally be \"closed\".\n\nI'm guessing that people moving to Git from CVS may choose to stick with\nthis pattern where they periodically merge-from-master to keep\nlong-running feature branches as close to in-sync with the master branch\nas possible (to avoid final merge conflicts).  Ideally, IIUC, perhaps\nthey should use rebase instead.\n\nPerhaps this \"mess\" can indeed be cleaned up using \"git rebase -i\" so\nthat the final version of the feature branch can be back-ported more\neasily (though one will still need to use git-cherry-pick or git-am to\ndo the back-port to the previous release branch).  The result of the\ncleanup, before the merge of Feature_A to 1.0 might look more like this:\n\n  o--o--o                                 Release_1.0\n /    \\  \\\no-o-o--o--o-o-o-o-o-o-o-o---------------o Mainline\n                         \\             /\n                          F1'--F2'--F3'   Feature_A\n\nand then after the merge of Feature_A to Release_1.0:\n\n  o--o--o--F1''--F2''--F3''               Release_1.0\n /    \\  \\\no-o-o--o--o-o-o-o-o-o-o-o---------------o Mainline\n                         \\             /\n                          F1'--F2'--F3'   Feature_A\n\n-- \n\t\t\t\t\t\tGreg A. Woods\n\n+1 416 218-0098                VE3TCP          RoboHack <woods@robohack.ca>\nPlanix, Inc. <woods@planix.com>      Secrets of the Weird <woods@weird.com>\n"}]}