{"thread":{"id":"1760","subject":"git-merge-cache / StGIT - gitmergeonefile.py: merging one tree into another rather than two trees into merge base","startedAt":"2005-09-10T18:27:28Z","lastAt":"2005-09-19T18:54:39Z","messageCount":14,"participants":["Blaisorblade","Catalin Marinas","Chuck Lever","Junio C Hamano","Daniel Barkalow","Matthias Urlichs"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"8252","messageId":"200509102027.28812.blaisorblade@yahoo.it","threadId":"1760","inReplyTo":null,"subject":"git-merge-cache / StGIT - gitmergeonefile.py: merging one tree into another rather than two trees into merge base","fromName":"Blaisorblade","fromEmail":"blaisorblade@yahoo.it","sentAt":"2005-09-10T18:27:28Z","receivedAt":"2005-09-10T18:27:28Z","isPatch":false,"sender":{"key":"blaisorblade@yahoo.it","avatar":null},"body":"(Please CC me on replies as I'm not subscribed).\n\nI experienced a (performance) problem with StGit, but I don't know if it's the \nculprit or if git-merge-cache is.\n\nToday I was pushing my patch stack (which was against Linux 2.6.13) on top of \nthe latest snapshot I have (i.e. upstream will likely have some mega of \npatches). And it was *really* slow (say it pushed 8 patches in 5 minutes).\n\nAfter the analisys, it's more or less logical - it'd take more or less the \nsame time to merge upstream changes against local ones. The problem is that \nit's not how things should go.\n\nI looked with \"top\" at what was happening, and I saw a lot of time spent by \neither gitmergeonefile.py or git-update-cache --remove*. And looking at the \nmerge algorithm, I realized it merges both HEAD and patch top into the patch \nbottom (or something like that).\n\nI.e. if upstream rewrote everything, it will merge this rewrite into the patch \nbottom, together with the patch itself. So, the merge time will depend on the \nbiggest of the two changed trees, not on the least one.\n\nA more reasonable algorithm would be along \"read-tree HEAD\"; merge \"stg diff \n-r /\" (i.e. the current patch) in it.\n\nI don't know if there's any real difference between cg-Xmergefile, \ngitmergeonefile.py and git-merge-one-file-script, and if that would matter in \nthis case.\n\n* About --remove, it was called on files which were present in stage1, removed \nin stage2 (i.e. upstream) and unchanged in stage3 (i.e. patch).\n\nIn the git-read-tree manpage (which is probably outdated), this is documented \nas follows:\n\n       o  stage 1 and stage 3 are the same and stage 2 is different: \n           take stage 2 (some work has been done on stage 2)\n\nBut it didn't happen, which is strange.\n\nAdditional note: in StGIT, git-read-tree is called with stage1 which is not \nthe merge base between stage2 and stage3.\n\nIt is passed the patch bottom, the current HEAD and the patch top.\n\nFor the first patch, the patch bottom is the merge base, but not otherwise; so \ndifferences between either stage1 or stage3, and stage2, include files \nchanged in previous patches.\n\nSo, would stgit delete a file created in patch #1 when merge-applying patch \n#2?\n-- \nInform me of my mistakes, so I can keep imitating Homer Simpson's \"Doh!\".\nPaolo Giarrusso, aka Blaisorblade (Skype ID \"PaoloGiarrusso\", ICQ 215621894)\nhttp://www.user-mode-linux.org/~blaisorblade\n\n\t\n\n\t\n\t\t\n___________________________________ \nYahoo! Mail: gratis 1GB per i messaggi e allegati da 10MB \nhttp://mail.yahoo.it\n"},{"id":"8270","messageId":"1126427087.8457.33.camel@localhost.localdomain","threadId":"1760","inReplyTo":"200509102027.28812.blaisorblade@yahoo.it","subject":"Re: git-merge-cache / StGIT - gitmergeonefile.py: merging one tree into another rather than two trees into merge base","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2005-09-11T08:24:47Z","receivedAt":"2005-09-11T08:24:47Z","isPatch":false,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"On Sat, 2005-09-10 at 20:27 +0200, Blaisorblade wrote:\n> I experienced a (performance) problem with StGit, but I don't know if it's the \n> culprit or if git-merge-cache is.\n\n('s/cache/index/g' below since I still use the old names)\n\nMaybe both. I did some profiling in StGIT but only for trivial patches\nwhich did not involved calling gitmergeonefile.py. It was taking around\n2.5s to push a patch with a changed base (involving merge) on an\nNFS-mounted directory but most of the time, 1.8s, was spent in\ngit-read-tree to do the actual merge.\n\nSomeone else (Bcc'ed, not sure he wants his address to be public) did\nsome profiling on GIT and his conclusion was that most of the time was\nspend in memmove() called from add_cache_entry() in read-cache.c called\nfrom read-tree.c.\n\n> Today I was pushing my patch stack (which was against Linux 2.6.13) on top of \n> the latest snapshot I have (i.e. upstream will likely have some mega of \n> patches). And it was *really* slow (say it pushed 8 patches in 5 minutes).\n\nThat's indeed very slow. How may files are modified in each patch? Do\nyou run it over NFS? Also for profiling, it is useful to run a 'stg\nstatus' just to warm up the cache a little bit.\n\n> I looked with \"top\" at what was happening, and I saw a lot of time spent by \n> either gitmergeonefile.py or git-update-cache --remove*. And looking at the \n> merge algorithm, I realized it merges both HEAD and patch top into the patch \n> bottom (or something like that).\n\nIt does a three-way merge between 'HEAD' and 'top' with 'bottom' as the\ncommon ancestor. The new 'bottom' will become 'HEAD' and the new 'top'\nwill become the result of the merge.\n\n> I.e. if upstream rewrote everything, it will merge this rewrite into the patch \n> bottom, together with the patch itself. So, the merge time will depend on the \n> biggest of the two changed trees, not on the least one.\n\nActually, it will three-way merge the diff between top and bottom with\nthe diff between HEAD and bottom. The time will depend on the size of\nboth diffs, not just the maximum. If the merge is not trivial, StGIT\nwill call git-merge-cache which calls gitmergeonefile.py. The Python\nscript is pretty simple and it simply calls diff3 or updates the cache\nbut if this happens for many files, the cumulated time might be big.\nIt's also worth profiling git-update-cache to check how it re-shuffles\nthe index file. Again, I haven't looked at the algorithm and I can't\ncomment more on this.\n\n> A more reasonable algorithm would be along \"read-tree HEAD\"; merge \"stg diff \n> -r /\" (i.e. the current patch) in it.\n\nThat's not a three-way diff algorithm. I could generate the diff of the\npatch and apply it with git-apply but this might fail and you wouldn't\neven get reject files (not sure whether git-apply supports this).\nAnother problem is that it won't detect upstream merges of your patch,\nyou would need to check it by hand. If all you need is a way to apply a\npatch using the 'patch' tool, have a look at Quilt. It has similar\ncommands (since StGIT is based on its ideas) but uses the diff/patch\ntools and is much faster. It also generates rejects if a patch doesn't\napply cleanly but I find the diff3 information, together with the\noriginal files left in place, much more useful.\n\n> I don't know if there's any real difference between cg-Xmergefile, \n> gitmergeonefile.py and git-merge-one-file-script, and if that would matter in \n> this case.\n\nThere is not big difference since these are only scripts that simply\ncall other tools.\n\n> In the git-read-tree manpage (which is probably outdated), this is documented \n> as follows:\n> \n>        o  stage 1 and stage 3 are the same and stage 2 is different: \n>            take stage 2 (some work has been done on stage 2)\n> \n> But it didn't happen, which is strange.\n\nThis means that the file is not modified by an StGIT patch but it is\nmodified upstream. This case works fine for me (it's a bug if it\ndoesn't). Did you get a conflict? Are the original files left in place?\n\n> Additional note: in StGIT, git-read-tree is called with stage1 which is not \n> the merge base between stage2 and stage3.\n\nstage1 is the bottom of the patch, stage2 is the HEAD (the upstream\nhash) and stage3 is the top of the patch.\n\n> For the first patch, the patch bottom is the merge base, but not otherwise; so \n> differences between either stage1 or stage3, and stage2, include files \n> changed in previous patches.\n\nFor the first patch, the bottom is the *old* base (== stage1), stage2 is\nthe new base and stage3 is the top of the patch.\n\n> So, would stgit delete a file created in patch #1 when merge-applying patch \n> #2?\n\nDefinitely not.\n\n-- \nCatalin\n"},{"id":"8375","messageId":"43257BB3.5020506@citi.umich.edu","threadId":"1760","inReplyTo":"1126427087.8457.33.camel@localhost.localdomain","subject":"Re: git-merge-cache / StGIT - gitmergeonefile.py: merging one tree into another rather than two trees into merge base","fromName":"Chuck Lever","fromEmail":"cel@citi.umich.edu","sentAt":"2005-09-12T12:59:31Z","receivedAt":"2005-09-12T12:59:31Z","isPatch":false,"sender":{"key":"cel@citi.umich.edu","avatar":null},"body":"Catalin Marinas wrote:\n> On Sat, 2005-09-10 at 20:27 +0200, Blaisorblade wrote:\n> \n>>I experienced a (performance) problem with StGit, but I don't know if it's the \n>>culprit or if git-merge-cache is.\n> \n> \n> ('s/cache/index/g' below since I still use the old names)\n> \n> Maybe both. I did some profiling in StGIT but only for trivial patches\n> which did not involved calling gitmergeonefile.py. It was taking around\n> 2.5s to push a patch with a changed base (involving merge) on an\n> NFS-mounted directory but most of the time, 1.8s, was spent in\n> git-read-tree to do the actual merge.\n> \n> Someone else (Bcc'ed, not sure he wants his address to be public) did\n\nthat's me!  thanks catalin.\n\n> some profiling on GIT and his conclusion was that most of the time was\n> spend in memmove() called from add_cache_entry() in read-cache.c called\n> from read-tree.c.\n> \n> \n>>Today I was pushing my patch stack (which was against Linux 2.6.13) on top of \n>>the latest snapshot I have (i.e. upstream will likely have some mega of \n>>patches). And it was *really* slow (say it pushed 8 patches in 5 minutes).\n> \n> \n> That's indeed very slow. How may files are modified in each patch? Do\n> you run it over NFS? Also for profiling, it is useful to run a 'stg\n> status' just to warm up the cache a little bit.\n\ni've probably seen similar behavior with git-update-index, but i never \nbothered to measure it.  blaisorblade, how are you profiling git?\n\njunio asked me to port my cache abstraction helpers over daniel's \nread-tree changes, which i have done.  i want to post those changes here \ntoday for comments.\n\n\nbegin:vcard\nfn:Chuck Lever\nn:Lever;Charles\norg:Network Appliance, Incorporated;Linux NFS Client Development\nadr:535 West William Street, Suite 3100;;Center for Information Technology Integration;Ann Arbor;MI;48103-4943;USA\nemail;internet:cel@citi.umich.edu\ntitle:Member of Technical Staff\ntel;work:+1 734 763-4415\ntel;fax:+1 734 763 4434\ntel;home:+1 734 668-1089\nx-mozilla-html:FALSE\nurl:http://www.monkey.org/~cel/\nversion:2.1\nend:vcard\n\n"},{"id":"8541","messageId":"200509141946.35002.blaisorblade@yahoo.it","threadId":"1760","inReplyTo":"43257BB3.5020506@citi.umich.edu","subject":"Re: git-merge-cache / StGIT - gitmergeonefile.py: merging one tree into another rather than two trees into merge base","fromName":"Blaisorblade","fromEmail":"blaisorblade@yahoo.it","sentAt":"2005-09-14T17:46:33Z","receivedAt":"2005-09-14T17:46:33Z","isPatch":false,"sender":{"key":"blaisorblade@yahoo.it","avatar":null},"body":"On Monday 12 September 2005 14:59, Chuck Lever wrote:\n> Catalin Marinas wrote:\n> > On Sat, 2005-09-10 at 20:27 +0200, Blaisorblade wrote:\n\n> >>Today I was pushing my patch stack (which was against Linux 2.6.13) on\n> >> top of the latest snapshot I have (i.e. upstream will likely have some\n> >> mega of patches). And it was *really* slow (say it pushed 8 patches in 5\n> >> minutes).\n\n> > That's indeed very slow. How may files are modified in each patch? Do\n> > you run it over NFS? Also for profiling, it is useful to run a 'stg\n> > status' just to warm up the cache a little bit.\n\n> i've probably seen similar behavior with git-update-index, but i never\n> bothered to measure it.  blaisorblade, how are you profiling git?\n\nI'm not, I just did the \"testing\" (actually I was simply using StGIT) I \nnoticed and reported this behaviour (I even had time to run top to watch what \nwas happening).\n\nAs said in the other answer, yes, I verified that it wasn't only for time \nspent getting cache-hot, and I'm not running on NFS, nor running big things \nin background.\n-- \nInform me of my mistakes, so I can keep imitating Homer Simpson's \"Doh!\".\nPaolo Giarrusso, aka Blaisorblade (Skype ID \"PaoloGiarrusso\", ICQ 215621894)\nhttp://www.user-mode-linux.org/~blaisorblade\n\n\t\n\n\t\n\t\t\n___________________________________ \nYahoo! Mail: gratis 1GB per i messaggi e allegati da 10MB \nhttp://mail.yahoo.it\n"},{"id":"8546","messageId":"200509142016.28390.blaisorblade@yahoo.it","threadId":"1760","inReplyTo":"1126427087.8457.33.camel@localhost.localdomain","subject":"Re: git-merge-cache / StGIT - gitmergeonefile.py: merging one tree into another rather than two trees into merge base","fromName":"Blaisorblade","fromEmail":"blaisorblade@yahoo.it","sentAt":"2005-09-14T18:16:27Z","receivedAt":"2005-09-14T18:16:27Z","isPatch":false,"sender":{"key":"blaisorblade@yahoo.it","avatar":null},"body":"On Sunday 11 September 2005 10:24, Catalin Marinas wrote:\n> On Sat, 2005-09-10 at 20:27 +0200, Blaisorblade wrote:\n> > I experienced a (performance) problem with StGit, but I don't know if\n> > it's the culprit or if git-merge-cache is.\n\n> ('s/cache/index/g' below since I still use the old names)\n\n> Maybe both. I did some profiling in StGIT but only for trivial patches\n> which did not involved calling gitmergeonefile.py.\n\n> It was taking around \n> 2.5s to push a patch with a changed base (involving merge) on an\n> NFS-mounted directory but most of the time, 1.8s, was spent in\n> git-read-tree to do the actual merge.\nYes, I even remember you mentioned that.\n> > Today I was pushing my patch stack (which was against Linux 2.6.13) on\n> > top of the latest snapshot I have (i.e. upstream will likely have some\n> > mega of patches). And it was *really* slow (say it pushed 8 patches in 5\n> > minutes).\n\n> That's indeed very slow. How may files are modified in each patch?\n1 files, in most cases - biggest one had 5 files changed (and is big 4,8K).\n\n> Do \n> you run it over NFS?\nNo, local reiserfs.\n> Also for profiling, it is useful to run a 'stg \n> status' just to warm up the cache a little bit.\nYes, I realized that -  but processing kept the same speed all the time (it's \nnot like it spent 4:30 minutes for warming the cache).\n\n> > I looked with \"top\" at what was happening, and I saw a lot of time spent\n> > by either gitmergeonefile.py or git-update-cache --remove*. And looking\n> > at the merge algorithm, I realized it merges both HEAD and patch top into\n> > the patch bottom (or something like that).\n\n> It does a three-way merge between 'HEAD' and 'top' with 'bottom' as the\n> common ancestor. The new 'bottom' will become 'HEAD' and the new 'top'\n> will become the result of the merge.\n\n> > I.e. if upstream rewrote everything, it will merge this rewrite into the\n> > patch bottom, together with the patch itself. So, the merge time will\n> > depend on the biggest of the two changed trees, not on the least one.\n\n> Actually, it will three-way merge the diff between top and bottom with\n> the diff between HEAD and bottom. The time will depend on the size of\n> both diffs, not just the maximum.\nYes, true, but the problem in this case was that one diff (the upstream one) \nwas extremely huge. And it even involved some files removal - I almost never \ncaught, with top, anything else than gitmergeonefile.py or git-update-cache \n--remove.\n\nI guess that moves between stages don't have the big memmove() problem, while \ncalling --remove shows it.\n\nAnd, with master being the SHA1 I pushed onto \n(8920e8f94c44e31a73bdf923b04721e26e88cadd), \n\ngit-diff-tree -r v2.6.13 master |grep ' D'|wc -l\ngives 189.\n\nI guess that 2.5 seconds (more or less) per each removal are enough to justify \nthe time which was needed above. So fixing this should fix the behaviour I \nmet.\n> If the merge is not trivial, StGIT \n> will call git-merge-cache which calls gitmergeonefile.py. The Python\n> script is pretty simple and it simply calls diff3 or updates the cache\n> but if this happens for many files, the cumulated time might be big.\n> It's also worth profiling git-update-cache to check how it re-shuffles\n> the index file. Again, I haven't looked at the algorithm and I can't\n> comment more on this.\n\n> > A more reasonable algorithm would be along \"read-tree HEAD\"; merge \"stg\n> > diff -r /\" (i.e. the current patch) in it.\n\n> That's not a three-way diff algorithm. I could generate the diff of the\n> patch and apply it with git-apply but this might fail and you wouldn't\n> even get reject files (not sure whether git-apply supports this).\nWell, true, but either diff3 or merge would work fairly well. Also, trying to \napply the patch and resorting to something more complex wouldn't create so \nmany problems.\n> Another problem is that it won't detect upstream merges of your patch,\n> you would need to check it by hand. If all you need is a way to apply a\n> patch using the 'patch' tool, have a look at Quilt. It has similar\n> commands (since StGIT is based on its ideas) but uses the diff/patch\n> tools and is much faster. It also generates rejects if a patch doesn't\n> apply cleanly but I find the diff3 information, together with the\n> original files left in place, much more useful.\n\nYes, in most cases. I've had something to complain with diff3, however.\n\n> > I don't know if there's any real difference between cg-Xmergefile,\n> > gitmergeonefile.py and git-merge-one-file-script, and if that would\n> > matter in this case.\n\n> There is not big difference since these are only scripts that simply\n> call other tools.\n\n> > In the git-read-tree manpage (which is probably outdated), this is\n> > documented as follows:\n> >\n> >        o  stage 1 and stage 3 are the same and stage 2 is different:\n> >            take stage 2 (some work has been done on stage 2)\n> >\n> > But it didn't happen, which is strange.\n\n> This means that the file is not modified by an StGIT patch but it is\n> modified upstream. This case works fine for me (it's a bug if it\n> doesn't). Did you get a conflict? Are the original files left in place?\nNo, it's not a correctness bug for me - just a performance bug. Why did \ngitupdateonefile.py need to call git-update-cache --remove? If git-read-tree \nhad done his duty, this wouldn't be needed.\n\n> > Additional note: in StGIT, git-read-tree is called with stage1 which is\n> > not the merge base between stage2 and stage3.\n\n> stage1 is the bottom of the patch, stage2 is the HEAD (the upstream\n> hash) and stage3 is the top of the patch.\nYes, saw that in the code.\n> > For the first patch, the patch bottom is the merge base, but not\n> > otherwise; so differences between either stage1 or stage3, and stage2,\n> > include files changed in previous patches.\n\n> For the first patch, the bottom is the *old* base (== stage1), stage2 is\n> the new base and stage3 is the top of the patch.\nYes, but the *old* base happens to be, in this case (i.e. upgrading the stack \nbase from upstream), also the merge base.\n> > So, would stgit delete a file created in patch #1 when merge-applying\n> > patch #2?\n\n> Definitely not.\nGonna test - but if you look at the manpage of read-tree, this would probably \nbe the expected behaviour.\n-- \nInform me of my mistakes, so I can keep imitating Homer Simpson's \"Doh!\".\nPaolo Giarrusso, aka Blaisorblade (Skype ID \"PaoloGiarrusso\", ICQ 215621894)\nhttp://www.user-mode-linux.org/~blaisorblade\n\n\n\t\t\n___________________________________ \nYahoo! Messenger: chiamate gratuite in tutto il mondo \nhttp://it.messenger.yahoo.com\n"},{"id":"8545","messageId":"200509142019.04667.blaisorblade@yahoo.it","threadId":"1760","inReplyTo":"1126427087.8457.33.camel@localhost.localdomain","subject":"Re: git-merge-cache / StGIT - gitmergeonefile.py: merging one tree into another rather than two trees into merge base","fromName":"Blaisorblade","fromEmail":"blaisorblade@yahoo.it","sentAt":"2005-09-14T18:19:04Z","receivedAt":"2005-09-14T18:19:04Z","isPatch":false,"sender":{"key":"blaisorblade@yahoo.it","avatar":null},"body":"On Sunday 11 September 2005 10:24, Catalin Marinas wrote:\n> On Sat, 2005-09-10 at 20:27 +0200, Blaisorblade wrote:\n> > I experienced a (performance) problem with StGit, but I don't know if\n> > it's the culprit or if git-merge-cache is.\n\n> ('s/cache/index/g' below since I still use the old names)\n\n> Maybe both. I did some profiling in StGIT but only for trivial patches\n> which did not involved calling gitmergeonefile.py.\n\n> It was taking around \n> 2.5s to push a patch with a changed base (involving merge) on an\n> NFS-mounted directory but most of the time, 1.8s, was spent in\n> git-read-tree to do the actual merge.\nYes, I even remember you mentioned that.\n> > Today I was pushing my patch stack (which was against Linux 2.6.13) on\n> > top of the latest snapshot I have (i.e. upstream will likely have some\n> > mega of patches). And it was *really* slow (say it pushed 8 patches in 5\n> > minutes).\n\n> That's indeed very slow. How may files are modified in each patch?\n1 files, in most cases - biggest one had 5 files changed (and is big 4,8K).\n\n> Do \n> you run it over NFS?\nNo, local reiserfs.\n> Also for profiling, it is useful to run a 'stg \n> status' just to warm up the cache a little bit.\nYes, I realized that -  but processing kept the same speed all the time (it's \nnot like it spent 4:30 minutes for warming the cache).\n\n> > I looked with \"top\" at what was happening, and I saw a lot of time spent\n> > by either gitmergeonefile.py or git-update-cache --remove*. And looking\n> > at the merge algorithm, I realized it merges both HEAD and patch top into\n> > the patch bottom (or something like that).\n\n> It does a three-way merge between 'HEAD' and 'top' with 'bottom' as the\n> common ancestor. The new 'bottom' will become 'HEAD' and the new 'top'\n> will become the result of the merge.\n\n> > I.e. if upstream rewrote everything, it will merge this rewrite into the\n> > patch bottom, together with the patch itself. So, the merge time will\n> > depend on the biggest of the two changed trees, not on the least one.\n\n> Actually, it will three-way merge the diff between top and bottom with\n> the diff between HEAD and bottom. The time will depend on the size of\n> both diffs, not just the maximum.\nYes, true, but the problem in this case was that one diff (the upstream one) \nwas extremely huge. And it even involved some files removal - I almost never \ncaught, with top, anything else than gitmergeonefile.py or git-update-cache \n--remove.\n\nI guess that moves between stages don't have the big memmove() problem, while \ncalling --remove shows it.\n\nAnd, with master being the SHA1 I pushed onto \n(8920e8f94c44e31a73bdf923b04721e26e88cadd), \n\ngit-diff-tree -r v2.6.13 master |grep ' D'|wc -l\n\ngives 189. I guess that 2.5 seconds per each removal are enough to justify the \ntime which was needed above. Actually, it even had to be less than a second \nper removal, otherwise it'd have been even slower.\n> If the merge is not trivial, StGIT \n> will call git-merge-cache which calls gitmergeonefile.py. The Python\n> script is pretty simple and it simply calls diff3 or updates the cache\n> but if this happens for many files, the cumulated time might be big.\n> It's also worth profiling git-update-cache to check how it re-shuffles\n> the index file. Again, I haven't looked at the algorithm and I can't\n> comment more on this.\n\n> > A more reasonable algorithm would be along \"read-tree HEAD\"; merge \"stg\n> > diff -r /\" (i.e. the current patch) in it.\n\n> That's not a three-way diff algorithm. I could generate the diff of the\n> patch and apply it with git-apply but this might fail and you wouldn't\n> even get reject files (not sure whether git-apply supports this).\nWell, true, but either diff3 or merge would work fairly well. Also, trying to \napply the patch and resorting to something more complex wouldn't create so \nmany problems.\n> Another problem is that it won't detect upstream merges of your patch,\n> you would need to check it by hand. If all you need is a way to apply a\n> patch using the 'patch' tool, have a look at Quilt. It has similar\n> commands (since StGIT is based on its ideas) but uses the diff/patch\n> tools and is much faster. It also generates rejects if a patch doesn't\n> apply cleanly but I find the diff3 information, together with the\n> original files left in place, much more useful.\n\nYes, in most cases. I've had something to complain with diff3, however (that's \na separate story). Maybe merge would be even better?\n\n> > I don't know if there's any real difference between cg-Xmergefile,\n> > gitmergeonefile.py and git-merge-one-file-script, and if that would\n> > matter in this case.\n\n> There is not big difference since these are only scripts that simply\n> call other tools.\n\n> > In the git-read-tree manpage (which is probably outdated), this is\n> > documented as follows:\n> >\n> >        o  stage 1 and stage 3 are the same and stage 2 is different:\n> >            take stage 2 (some work has been done on stage 2)\n> >\n> > But it didn't happen, which is strange.\n\n> This means that the file is not modified by an StGIT patch but it is\n> modified upstream. This case works fine for me (it's a bug if it\n> doesn't). Did you get a conflict? Are the original files left in place?\nNo, it's not a correctness bug for me - just a performance bug. Why did \ngitupdateonefile.py need to call git-update-cache --remove? If git-read-tree \nhad done his duty, this wouldn't be needed.\n\n> > Additional note: in StGIT, git-read-tree is called with stage1 which is\n> > not the merge base between stage2 and stage3.\n\n> stage1 is the bottom of the patch, stage2 is the HEAD (the upstream\n> hash) and stage3 is the top of the patch.\nYes, saw that in the code.\n> > For the first patch, the patch bottom is the merge base, but not\n> > otherwise; so differences between either stage1 or stage3, and stage2,\n> > include files changed in previous patches.\n\n> For the first patch, the bottom is the *old* base (== stage1), stage2 is\n> the new base and stage3 is the top of the patch.\nYes, but the *old* base happens to be, in this case (i.e. upgrading the stack \nbase from upstream), also the merge base.\n> > So, would stgit delete a file created in patch #1 when merge-applying\n> > patch #2?\n\n> Definitely not.\nGonna test - but if you look at the manpage of read-tree, this would probably \nbe the expected behaviour.\n-- \nInform me of my mistakes, so I can keep imitating Homer Simpson's \"Doh!\".\nPaolo Giarrusso, aka Blaisorblade (Skype ID \"PaoloGiarrusso\", ICQ 215621894)\nhttp://www.user-mode-linux.org/~blaisorblade\n\n\t\n\n\t\n\t\t\n___________________________________ \nYahoo! Mail: gratis 1GB per i messaggi e allegati da 10MB \nhttp://mail.yahoo.it\n"},{"id":"8595","messageId":"tnxslw6d4qt.fsf@arm.com","threadId":"1760","inReplyTo":"200509142019.04667.blaisorblade@yahoo.it","subject":"Re: git-merge-cache / StGIT - gitmergeonefile.py: merging one tree into another rather than two trees into merge base","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2005-09-15T10:06:50Z","receivedAt":"2005-09-15T10:06:50Z","isPatch":false,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"Blaisorblade <blaisorblade@yahoo.it> wrote:\n> On Sunday 11 September 2005 10:24, Catalin Marinas wrote:\n>> That's indeed very slow. How may files are modified in each patch?\n>\n> 1 files, in most cases - biggest one had 5 files changed (and is big\n> 4,8K).\n\nOK, this doesn't really matters since the diff between the new HEAD\nand the old bottom of the patch is big.\n\n>> Actually, it will three-way merge the diff between top and bottom with\n>> the diff between HEAD and bottom. The time will depend on the size of\n>> both diffs, not just the maximum.\n>\n> Yes, true, but the problem in this case was that one diff (the\n> upstream one) was extremely huge. And it even involved some files\n> removal - I almost never caught, with top, anything else than\n> gitmergeonefile.py or git-update-cache --remove.\n\ngit-read-tree -m doesn't handle the case when a file is removed from\none branch and unmodified in the other, which is what happens in your\ntest. For each of these removed files, git-merge-cache will call\ngitmergeonefile.py which calls 'git-update-cache --remove'.\n\nAn improvement would be to make git-read-tree smarter and only leave\nout the three-way merges and the conflicts. Otherwise, implementing my\nown git-merge-cache which includes gitmergeonefile.py or implementing\ngitmergeonefile in C would be an improvement but I'm not sure it is\nthat significant.\n\n> I guess that moves between stages don't have the big memmove()\n> problem, while calling --remove shows it.\n>\n> And, with master being the SHA1 I pushed onto \n> (8920e8f94c44e31a73bdf923b04721e26e88cadd), \n>\n> git-diff-tree -r v2.6.13 master |grep ' D'|wc -l\n>\n> gives 189. I guess that 2.5 seconds per each removal are enough to\n> justify the time which was needed above. Actually, it even had to be\n> less than a second per removal, otherwise it'd have been even\n> slower.\n\nThe 2.5 figure was for trivial merges and most of the time was spent\nin git-read-tree.\n\n>> That's not a three-way diff algorithm. I could generate the diff of the\n>> patch and apply it with git-apply but this might fail and you wouldn't\n>> even get reject files (not sure whether git-apply supports this).\n>\n> Well, true, but either diff3 or merge would work fairly well. Also,\n> trying to apply the patch and resorting to something more complex\n> wouldn't create so many problems.\n\nBut this would slow things down for people pulling changes on a daily\n(or even more often) basis. It could be added as an option to 'stg\npush', i.e. when you expect something like this, just pass a\n'--nothreeway' option.\n\n>> Another problem is that it won't detect upstream merges of your patch,\n>> you would need to check it by hand. If all you need is a way to apply a\n>> patch using the 'patch' tool, have a look at Quilt. It has similar\n>> commands (since StGIT is based on its ideas) but uses the diff/patch\n>> tools and is much faster. It also generates rejects if a patch doesn't\n>> apply cleanly but I find the diff3 information, together with the\n>> original files left in place, much more useful.\n>\n> Yes, in most cases. I've had something to complain with diff3,\n> however (that's a separate story). Maybe merge would be even better?\n\nI couldn't find the difference between merge and diff3 -E. Is there\nany?\n\n>> > In the git-read-tree manpage (which is probably outdated), this is\n>> > documented as follows:\n>> >\n>> >        o  stage 1 and stage 3 are the same and stage 2 is different:\n>> >            take stage 2 (some work has been done on stage 2)\n>> >\n>> > But it didn't happen, which is strange.\n>\n>> This means that the file is not modified by an StGIT patch but it is\n>> modified upstream. This case works fine for me (it's a bug if it\n>> doesn't). Did you get a conflict? Are the original files left in place?\n>\n> No, it's not a correctness bug for me - just a performance bug. Why did \n> gitupdateonefile.py need to call git-update-cache --remove? If git-read-tree \n> had done his duty, this wouldn't be needed.\n\nDo you mean it wasn't modified by the StGIT patch (and hence stage 3\nis the same as stage 1) but it was removed in stage 2. This case is\n*not* handled by git-read-tree, though I think it should deal with\nthis trivial case as well, it's not that different from the case\nbelow.\n\nIf stage 2 is a simple SHA1 modification (not file removal) the case\nwas already handled by git-read-tree and there should only be a stage\n0 entry for this file. git-merge-cache should *not* call\ngitmergeonefile.py.\n\nYou can run git-read-tree manually and check the stages for this case.\n\n>> > So, would stgit delete a file created in patch #1 when merge-applying\n>> > patch #2?\n>\n>> Definitely not.\n>\n> Gonna test - but if you look at the manpage of read-tree, this would\n> probably be the expected behaviour.\n\nIf patch #2 didn't explicitely removed this file and if patch #1 is\napplied, it won't delete it (unless there is a bug).\n\n-- \nCatalin\n"},{"id":"8702","messageId":"200509162045.13713.blaisorblade@yahoo.it","threadId":"1760","inReplyTo":"tnxslw6d4qt.fsf@arm.com","subject":"Re: git-merge-cache / StGIT - gitmergeonefile.py: merging one tree into another rather than two trees into merge base","fromName":"Blaisorblade","fromEmail":"blaisorblade@yahoo.it","sentAt":"2005-09-16T18:45:13Z","receivedAt":"2005-09-16T18:45:13Z","isPatch":false,"sender":{"key":"blaisorblade@yahoo.it","avatar":null},"body":"On Thursday 15 September 2005 12:06, Catalin Marinas wrote:\n> Blaisorblade <blaisorblade@yahoo.it> wrote:\n> > On Sunday 11 September 2005 10:24, Catalin Marinas wrote:\n> >> That's indeed very slow. How may files are modified in each patch?\n> >\n> > 1 files, in most cases - biggest one had 5 files changed (and is big\n> > 4,8K).\n\n> OK, this doesn't really matters since the diff between the new HEAD\n> and the old bottom of the patch is big.\nIn fact.\n> >> Actually, it will three-way merge the diff between top and bottom with\n> >> the diff between HEAD and bottom. The time will depend on the size of\n> >> both diffs, not just the maximum.\n\n> git-read-tree -m doesn't handle the case when a file is removed from\n> one branch and unmodified in the other, which is what happens in your\n> test. For each of these removed files, git-merge-cache will call\n> gitmergeonefile.py which calls 'git-update-cache --remove'.\n\n> An improvement would be to make git-read-tree smarter and only leave\n> out the three-way merges and the conflicts. Otherwise, implementing my\n> own git-merge-cache which includes gitmergeonefile.py or implementing\n> gitmergeonefile in C would be an improvement but I'm not sure it is\n> that significant.\ngitmergeonefile in C wouldn't matter that much (I hope) - you'd rather move \nthe code to a module to have it byte-compiled would be enough, if this \nmatters.\n\nWhat could make more sense is to make sure that the file removals are done in \none step, which can be accomplished only if the Porcelain merge script is \ncalled at once with a file list on stdin.\n\nBut implementing the behaviour we discuss below (the one I quote from man page \nbut which is unimplemented) would fix this particular problem. So yes, \nimplementing this would speed things up.\n> > I guess that moves between stages don't have the big memmove()\n> > problem, while calling --remove shows it.\n> >\n> > And, with master being the SHA1 I pushed onto\n> > (8920e8f94c44e31a73bdf923b04721e26e88cadd),\n> >\n> > git-diff-tree -r v2.6.13 master |grep ' D'|wc -l\n\n> > gives 189. I guess that 2.5 seconds per each removal are enough to\n> > justify the time which was needed above. Actually, it even had to be\n> > less than a second per removal, otherwise it'd have been even\n> > slower.\n\n> The 2.5 figure was for trivial merges and most of the time was spent\n> in git-read-tree.\nYes, but I think it's a reasonable figure here too (we'll have to do memmove() \nanyway, if things are reasonable - never looked at the code, though).\n> >> That's not a three-way diff algorithm. I could generate the diff of the\n> >> patch and apply it with git-apply but this might fail and you wouldn't\n> >> even get reject files (not sure whether git-apply supports this).\n\n> > Well, true, but either diff3 or merge would work fairly well. Also,\n> > trying to apply the patch and resorting to something more complex\n> > wouldn't create so many problems.\n\n> But this would slow things down for people pulling changes on a daily\n> (or even more often) basis. It could be added as an option to 'stg\n> push', i.e. when you expect something like this, just pass a\n> '--nothreeway' option.\nUsing \"merge\" by hand *is* a three-way merge, indeed (done with older tools, I \nagree).\n> >> Another problem is that it won't detect upstream merges of your patch,\n> >> you would need to check it by hand. If all you need is a way to apply a\n> >> patch using the 'patch' tool, have a look at Quilt. It has similar\n> >> commands (since StGIT is based on its ideas) but uses the diff/patch\n> >> tools and is much faster. It also generates rejects if a patch doesn't\n> >> apply cleanly but I find the diff3 information, together with the\n> >> original files left in place, much more useful.\n\n> > Yes, in most cases. I've had something to complain with diff3,\n> > however (that's a separate story). Maybe merge would be even better?\n\n> I couldn't find the difference between merge and diff3 -E. Is there\n> any?\nI didn't see any difference in my (limited) use. So I switched to wiggle, \nwhich is smart enough for my needs.\n\n> >> > In the git-read-tree manpage (which is probably outdated), this is\n> >> > documented as follows:\n> >> >\n> >> >        o  stage 1 and stage 3 are the same and stage 2 is different:\n> >> >            take stage 2 (some work has been done on stage 2)\n> >> >\n> >> > But it didn't happen, which is strange.\n> >>\n> >> This means that the file is not modified by an StGIT patch but it is\n> >> modified upstream. This case works fine for me (it's a bug if it\n> >> doesn't). Did you get a conflict? Are the original files left in place?\n> >\n> > No, it's not a correctness bug for me - just a performance bug. Why did\n> > gitupdateonefile.py need to call git-update-cache --remove? If\n> > git-read-tree had done his duty, this wouldn't be needed.\n\n> Do you mean it wasn't modified by the StGIT patch (and hence stage 3\n> is the same as stage 1) but it was removed in stage 2. This case is\n> *not* handled by git-read-tree, though I think it should deal with\n> this trivial case as well, it's not that different from the case\n> below.\nOk, manpage is out-of-date, as I guessed. The above excerpt says yes, you say \nno, I verified no, please fix man page.\n> If stage 2 is a simple SHA1 modification (not file removal) the case\n> was already handled by git-read-tree and there should only be a stage\n> 0 entry for this file. git-merge-cache should *not* call\n> gitmergeonefile.py.\n\n> >> > So, would stgit delete a file created in patch #1 when merge-applying\n> >> > patch #2?\n> >>\n> >> Definitely not.\n\n> > Gonna test - but if you look at the manpage of read-tree, this would\n> > probably be the expected behaviour.\n\n> If patch #2 didn't explicitely removed this file and if patch #1 is\n> applied, it won't delete it (unless there is a bug).\nYes, sorry, here you're right - I wasn't careful enough. It's true that the \nfile is only in stage 2 (current HEAD) but not in stage1 (bottom) or stage3 \n(top), but that is assumed as \"work done in the HEAD\" so it's kept.\n-- \nInform me of my mistakes, so I can keep imitating Homer Simpson's \"Doh!\".\nPaolo Giarrusso, aka Blaisorblade (Skype ID \"PaoloGiarrusso\", ICQ 215621894)\nhttp://www.user-mode-linux.org/~blaisorblade\n\n\n\t\n\n\t\n\t\t\n___________________________________ \nYahoo! Mail: gratis 1GB per i messaggi e allegati da 10MB \nhttp://mail.yahoo.it\n"},{"id":"8717","messageId":"7vvf10hji1.fsf@assigned-by-dhcp.cox.net","threadId":"1760","inReplyTo":"tnxslw6d4qt.fsf@arm.com","subject":"Re: git-merge-cache / StGIT - gitmergeonefile.py: merging one tree into another rather than two trees into merge base","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-09-16T19:59:02Z","receivedAt":"2005-09-16T19:59:02Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Catalin Marinas <catalin.marinas@gmail.com> writes:\n\n> git-read-tree -m doesn't handle the case when a file is removed from\n> one branch and unmodified in the other, which is what happens in your\n> test. For each of these removed files, git-merge-cache will call\n> gitmergeonefile.py which calls 'git-update-cache --remove'.\n>\n> An improvement would be to make git-read-tree smarter...\n\nI think this was once discussed but the primary reason for the\nbehaviour is that Linus wanted to leave as much merge policy\ndecision to be scriptable without hardcoding it in read-tree.\n\nFor example, you would see branch A removing a path while branch\nB keeping the path if A renamed it to somewhere else while B\nkept it -- a cleverer merge policy than one-path-at-a-time we\ncurrently have _could_ take a hint from the unmerged cache, go\nlook for the other half of the rename in branch A, and ask the\nuser if the rename should be honored in the merge result for\nexample.  If you always do \"added or removed in only one head\nmeans take that head\", most likely in the above example B would\nnot have a new path (rename target of A) so you would end up\nalways taking the file rename.\n\n>> git-diff-tree -r v2.6.13 master |grep ' D'|wc -l\n>>\n>> gives 189.\n\nA completely different topic:  would it please people if I did this?\n\n    $ git-diff-tree -r --names-and-changes A B\n    M\tfrotz\n    R93\trezrov\tnitfol\n    D\tyomin\n"},{"id":"8757","messageId":"1126949517.6941.19.camel@localhost.localdomain","threadId":"1760","inReplyTo":"7vvf10hji1.fsf@assigned-by-dhcp.cox.net","subject":"Re: git-merge-cache / StGIT - gitmergeonefile.py: merging one tree into another rather than two trees into merge base","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2005-09-17T09:31:57Z","receivedAt":"2005-09-17T09:31:57Z","isPatch":false,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"On Fri, 2005-09-16 at 12:59 -0700, Junio C Hamano wrote:\n> Catalin Marinas <catalin.marinas@gmail.com> writes:\n> \n> > git-read-tree -m doesn't handle the case when a file is removed from\n> > one branch and unmodified in the other, which is what happens in your\n> > test. For each of these removed files, git-merge-cache will call\n> > gitmergeonefile.py which calls 'git-update-cache --remove'.\n> >\n> > An improvement would be to make git-read-tree smarter...\n> \n> I think this was once discussed but the primary reason for the\n> behaviour is that Linus wanted to leave as much merge policy\n> decision to be scriptable without hardcoding it in read-tree.\n\nThis could be OK for git-read-tree but maybe git-merge-index could have\na --smart option to deal with trivial cases like below (or a separate\ntool). Whoever wants to write a more interactive script would not pass\nthis option.\n\n> If you always do \"added or removed in only one head\n> means take that head\", most likely in the above example B would\n> not have a new path (rename target of A) so you would end up\n> always taking the file rename.\n\nThat's what happens with the current merge scripts.\n\nAnother option for me would be to try to interface Python with libgit.a\nand emulate the git-merge-index behaviour but I've never tried mixing\nPython and C before.\n\n> A completely different topic:  would it please people if I did this?\n> \n>     $ git-diff-tree -r --names-and-changes A B\n>     M\tfrotz\n>     R93\trezrov\tnitfol\n>     D\tyomin\n\nIt might help for people using git directly (me as well). StGIT parses\nthe git-diff-tree output anyway.\n\n-- \nCatalin\n"},{"id":"8872","messageId":"432EDE3F.7070407@citi.umich.edu","threadId":"1760","inReplyTo":"1126949517.6941.19.camel@localhost.localdomain","subject":"omitted test scripts?","fromName":"Chuck Lever","fromEmail":"cel@citi.umich.edu","sentAt":"2005-09-19T15:50:23Z","receivedAt":"2005-09-19T15:50:23Z","isPatch":false,"sender":{"key":"cel@citi.umich.edu","avatar":null},"body":"Catalin Marinas wrote:\n> On Fri, 2005-09-16 at 12:59 -0700, Junio C Hamano wrote:\n> \n>>Catalin Marinas <catalin.marinas@gmail.com> writes:\n>>\n>>\n>>>git-read-tree -m doesn't handle the case when a file is removed from\n>>>one branch and unmodified in the other, which is what happens in your\n>>>test. For each of these removed files, git-merge-cache will call\n>>>gitmergeonefile.py which calls 'git-update-cache --remove'.\n>>>\n>>>An improvement would be to make git-read-tree smarter...\n>>\n>>I think this was once discussed but the primary reason for the\n>>behaviour is that Linus wanted to leave as much merge policy\n>>decision to be scriptable without hardcoding it in read-tree.\n> \n> \n> This could be OK for git-read-tree but maybe git-merge-index could have\n> a --smart option to deal with trivial cases like below (or a separate\n> tool). Whoever wants to write a more interactive script would not pass\n> this option.\n\ni noticed while testing the new cache API that there are no tests under \nt/ for git-merge-index.\n\nthere is also no test script that covers the prune_cache() function in \nls-files.c.\n\n\nbegin:vcard\nfn:Chuck Lever\nn:Lever;Charles\norg:Network Appliance, Incorporated;Linux NFS Client Development\nadr:535 West William Street, Suite 3100;;Center for Information Technology Integration;Ann Arbor;MI;48103-4943;USA\nemail;internet:cel@citi.umich.edu\ntitle:Member of Technical Staff\ntel;work:+1 734 763 4415\ntel;fax:+1 734 763 4434\ntel;home:+1 734 668 1089\nx-mozilla-html:FALSE\nurl:http://www.monkey.org/~cel/\nversion:2.1\nend:vcard\n\n"},{"id":"8875","messageId":"7v1x3lrpxi.fsf@assigned-by-dhcp.cox.net","threadId":"1760","inReplyTo":"432EDE3F.7070407@citi.umich.edu","subject":"Re: omitted test scripts?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-09-19T16:19:05Z","receivedAt":"2005-09-19T16:19:05Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Chuck Lever <cel@citi.umich.edu> writes:\n\n> i noticed while testing the new cache API that there are no tests under \n> t/ for git-merge-index.\n\nIn the past, when I did any major butchering of existing code or\nmade nontrivial additions, I wrote test scripts to cover what\nshould happen (and what to be preserved) first to make sure the\nchanges or additions would not introduce regression.  I think we\nhave been reasonably successful (Daniel could fill us in with\nexperiences with read-tree tests).\n\nI have been expecting people to follow suit, without explicitly\nasking them to do, so when I took over the project.  Further I\ngot sloppy when accepting any sizable patches.  Sorry about\nthat.\n\n> there is also no test script that covers the prune_cache() function in \n> ls-files.c.\n\nThat's one of the item on the TODO list and patches to extend\ntest coverage are always welcomed.\n"},{"id":"8883","messageId":"Pine.LNX.4.63.0509191239090.23242@iabervon.org","threadId":"1760","inReplyTo":"7v1x3lrpxi.fsf@assigned-by-dhcp.cox.net","subject":"Re: omitted test scripts?","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-09-19T17:01:11Z","receivedAt":"2005-09-19T17:01:11Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Mon, 19 Sep 2005, Junio C Hamano wrote:\n\n> Chuck Lever <cel@citi.umich.edu> writes:\n> \n> > i noticed while testing the new cache API that there are no tests under \n> > t/ for git-merge-index.\n> \n> In the past, when I did any major butchering of existing code or\n> made nontrivial additions, I wrote test scripts to cover what\n> should happen (and what to be preserved) first to make sure the\n> changes or additions would not introduce regression.  I think we\n> have been reasonably successful (Daniel could fill us in with\n> experiences with read-tree tests).\n\nI think the only thing missing from the read-tree tests was for refusing \nto create directory/file conflicts which would otherwise be permitted when \nnot using the --emu23 flag. Other than that, everything I neglected to \nhandle caused something to fail. That reminds me that I still owe you a \nreplacement test for this case.\n\n> I have been expecting people to follow suit, without explicitly\n> asking them to do, so when I took over the project.  Further I\n> got sloppy when accepting any sizable patches.  Sorry about\n> that.\n\nI think I also owe you some tests for fetch. Any suggestions on writing \nunit tests? (I'd like to test that fetch.c actually calls functions in the \nright order and such, even in complicated cases)\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"8888","messageId":"pan.2005.09.19.18.54.38.742376@smurf.noris.de","threadId":"1760","inReplyTo":"7v1x3lrpxi.fsf@assigned-by-dhcp.cox.net","subject":"Re: omitted test scripts?","fromName":"Matthias Urlichs","fromEmail":"smurf@smurf.noris.de","sentAt":"2005-09-19T18:54:39Z","receivedAt":"2005-09-19T18:54:39Z","isPatch":false,"sender":{"key":"matthias@urlichs.de","avatar":"https://gravatar.com/avatar/2708905af227313eba6f2b2ae0f7d0259b5ac5d71baef58fe5a13c699ce0bbf0?d=mp&s=160"},"body":"Hi, Junio C Hamano wrote:\n\n> In the past, when I did any major butchering of existing code or\n> made nontrivial additions, I wrote test scripts to cover what\n> should happen (and what to be preserved) first to make sure the\n> changes or additions would not introduce regression.\n\n... which is very good programming practice regardless.\n\nOne of the better tenets of Extreme Programming says that any feature\nfor which you don't have a test basically doesn't exist. \n\n-- \nMatthias Urlichs   |   {M:U} IT Design @ m-u-it.de   |  smurf@smurf.noris.de\nDisclaimer: The quote was selected randomly. Really. | http://smurf.noris.de\n - -\nBuddha most emphatically insists that what he teaches is nothing\nunusual, being simply the recognition of a plain fact which can be\nattested to by every mortal...\n"}]}