{"thread":{"id":"737","subject":"More gitweb queries..","startedAt":"2005-05-27T19:24:20Z","lastAt":"2005-05-31T02:27:00Z","messageCount":42,"participants":["Linus Torvalds","Thomas Glanzmann","Junio C Hamano","Benjamin Herrenschmidt","Kay Sievers","Daniel Serpell","David Lang","Paul Mackerras","Jeff Epler"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"4069","messageId":"Pine.LNX.4.58.0505271145570.17402@ppc970.osdl.org","threadId":"737","inReplyTo":null,"subject":"More gitweb queries..","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-05-27T19:24:20Z","receivedAt":"2005-05-27T19:24:20Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nKay,\n just a few more quickie suggestions if you don't mind..\n\n - looking around, the ALSA guys aren't the only ones that start off with \n   an empty line, so it's probably worth fixing the summary etc to ignore \n   whitespace at the beginning rather than give empty summary reasons.\n\n - any reason to limit the \"summary\" page to just the last 14 changes? The \n   \"log\" thing you can ask to go back further, it would be nice to have\n   something like a \"last 100\" thing for summaries too, especially since \n   the summary is so nice and dense, so you can actually get a nice view \n   of what has happened without scrolling _too_ much.\n\n - I was in the \"commitdiff\" thing, and initially thought that there was \n   no way to get back to the \"summary\" view.\n\n   It turns out I was wrong (the summary is reachable by just clicking at\n   the project name itself in the top header), but it's a bit strange that\n   the \"commitdiff\" thing has an explicit link back to itself (hey, \n   consistency is good, so I'm not complaining), but the link back to the\n   summary page is implicit.\n\n   So how about adding an explicit \"summary\" link to the list of other \n   explicit links (log, commit, commitdiff and tree) at the top of the \n   page?\n\nI actually like browsing other peoples projects with the gitweb\ninterfaces, it's both responsive and verbose enough to really say\nsomething good. In contrast, cvsweb is always just a mess of \"these are\nthe files, go at it\", which is totally pointless and doesn't tell anything\nabout what is actually happening in the project.\n\nSo dammit, I'm very biased indeed, but I'm just looking at gitweb, and\ncomparing it to both the CVS and SVN web things, and they just reinforce\nmy conviction that CVS is absolute crap, and I find myself surprised by\nhow crap SVN also appears.\n\n[ In other words, while I have all these stupid requests for you, I \n  think gitweb is just _way_ better and more useful than something like\n  viewcvs (or cvsweb). So don't mind my small gripes, I only have them \n  because I like this thing.\n\n  On that small note, I also find \"gitk\" very cool indeed, too bad about \n  the fact that tk/tcl seems to always end up looking so _ugly_. Is there \n  any way to get anti-aliased fonts and a less 'Motify' blocky look from \n  tcl/tk? Every time I see that, I feel like I'm back in the last century  \n  or something.\n\n  Combining some of the features of the two (that über-cool revision \n  history graph from gitk rules, for example) might be cool. I get the \n  urge to do octopus-merges in the kernel just because of how good they\n  look in gitk ;) ]\n\n\t\t\tLinus\n"},{"id":"4071","messageId":"20050527192941.GE7068@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"Pine.LNX.4.58.0505271145570.17402@ppc970.osdl.org","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-27T19:29:41Z","receivedAt":"2005-05-27T19:29:41Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\n\n> I get the urge to do octopus-merges in the kernel just because of how\n> good they look in gitk ;) ]\n\ntalking about octopus-merges ... I don't understand how they work. What\nhappens if one file is touched in every of the 8 trees. How can that be\nhandled?\n\n\tThomas\n"},{"id":"4074","messageId":"20050527193103.GF7068@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"Pine.LNX.4.58.0505271145570.17402@ppc970.osdl.org","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-27T19:31:03Z","receivedAt":"2005-05-27T19:31:03Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\n\n>  - looking around, the ALSA guys aren't the only ones that start off with \n>    an empty line, so it's probably worth fixing the summary etc to ignore \n>    whitespace at the beginning rather than give empty summary reasons.\n\nfor me the formatting of an empty commit comment screw up the layout. I\ndon't know if it already is fixed, if not, I will soon report a patch.\n\n\tThomas\n"},{"id":"4073","messageId":"7voeawxy53.fsf@assigned-by-dhcp.cox.net","threadId":"737","inReplyTo":"Pine.LNX.4.58.0505271145570.17402@ppc970.osdl.org","subject":"Re: More gitweb queries..","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-27T19:32:56Z","receivedAt":"2005-05-27T19:32:56Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"LT\" == Linus Torvalds <torvalds@osdl.org> writes:\n\nLT>   Combining some of the features of the two (that über-cool revision \nLT>   history graph from gitk rules, for example) might be cool. I get the \nLT>   urge to do octopus-merges in the kernel just because of how good they\nLT>   look in gitk ;) ]\n\nHey, Octopus is what you explicitly told me not to do ;-).\n\n\n\n"},{"id":"4075","messageId":"Pine.LNX.4.58.0505271247320.17402@ppc970.osdl.org","threadId":"737","inReplyTo":"7voeawxy53.fsf@assigned-by-dhcp.cox.net","subject":"Re: More gitweb queries..","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-05-27T19:48:16Z","receivedAt":"2005-05-27T19:48:16Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Fri, 27 May 2005, Junio C Hamano wrote:\n>\n> >>>>> \"LT\" == Linus Torvalds <torvalds@osdl.org> writes:\n> \n> LT>   Combining some of the features of the two (that über-cool revision \n> LT>   history graph from gitk rules, for example) might be cool. I get the \n> LT>   urge to do octopus-merges in the kernel just because of how good they\n> LT>   look in gitk ;) ]\n> \n> Hey, Octopus is what you explicitly told me not to do ;-).\n\nI know, I know. I said \"I get urges\", I didn't say I'll do it.\n\nI'll try to control myself.\n\nMaybe.\n\n\t\tLinus\n"},{"id":"4076","messageId":"7vhdgoxx8c.fsf@assigned-by-dhcp.cox.net","threadId":"737","inReplyTo":"20050527192941.GE7068@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-27T19:52:35Z","receivedAt":"2005-05-27T19:52:35Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"TG\" == Thomas Glanzmann <sithglan@stud.uni-erlangen.de> writes:\n\nTG> talking about octopus-merges ... I don't understand how they work. What\nTG> happens if one file is touched in every of the 8 trees. How can that be\nTG> handled?\n\nYou merge by hand and resolve if they have conflicts, just like\nwhat you already do in two head merge case.\n\nOctopus is only about how you record the results.  Instead of\nmaking 7 consecutive \"merge from A\" \"merge from B\" to record two\nhead merges, you just say \"I merged these 8 heads\" in a single\ncommit.\n\n"},{"id":"4077","messageId":"7vd5rcxx5p.fsf@assigned-by-dhcp.cox.net","threadId":"737","inReplyTo":"20050527192941.GE7068@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-27T19:54:10Z","receivedAt":"2005-05-27T19:54:10Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas, could you please stop doing Mail-Followup-To in your\nheader please?  I automatically did 'reply all' and ended up\npreaching Linus (because that was the first mailbox on your\nMail-Followup-to header) how Octopus works, when he knows what\nit is already.\n\n"},{"id":"4078","messageId":"20050527195552.GA6541@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"7vhdgoxx8c.fsf@assigned-by-dhcp.cox.net","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-27T19:55:52Z","receivedAt":"2005-05-27T19:55:52Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\n\n> You merge by hand and resolve if they have conflicts, just like\n> what you already do in two head merge case.\n\nI see. Does that mean that 'git-ls-files --unmerged' will report upto 9\nstages per file?\n\n> Octopus is only about how you record the results.  Instead of\n> making 7 consecutive \"merge from A\" \"merge from B\" to record two\n> head merges, you just say \"I merged these 8 heads\" in a single\n> commit.\n\nI got that part. :-)\n\n\tThomas\n"},{"id":"4079","messageId":"20050527195856.GA7735@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"7vd5rcxx5p.fsf@assigned-by-dhcp.cox.net","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-27T19:58:56Z","receivedAt":"2005-05-27T19:58:56Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\n\n* Junio C Hamano <junkio@cox.net> [050527 21:54]:\n> Thomas, could you please stop doing Mail-Followup-To in your\n> header please?  I automatically did 'reply all' and ended up\n> preaching Linus (because that was the first mailbox on your\n> Mail-Followup-to header) how Octopus works, when he knows what\n> it is already.\n\ntest without the mft.\n\n\tThomas\n"},{"id":"4080","messageId":"Pine.LNX.4.58.0505271248450.17402@ppc970.osdl.org","threadId":"737","inReplyTo":"20050527192941.GE7068@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-05-27T20:03:32Z","receivedAt":"2005-05-27T20:03:32Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Fri, 27 May 2005, Thomas Glanzmann wrote:\n> \n> > I get the urge to do octopus-merges in the kernel just because of how\n> > good they look in gitk ;) ]\n> \n> talking about octopus-merges ... I don't understand how they work. What\n> happens if one file is touched in every of the 8 trees. How can that be\n> handled?\n\nAutomatically? You can do multiple three-way merges, no problem. \n\nIn fact, the general algorithm for an n-way merge is to just do the \n\"git-resolve-script\" n-1 times, but _without_ the commit. Then you just \ncommit the result, and the only thing to keep in mind is to get the \nparents right, because if you don't, you're screwed.\n\nThis does imply a merge ordering, but since we order the parents anyway,\nthat's actually also described 100% by the commit, so the end result is\nclean and good.\n\nThere are two reasons not to do octopus-merges, and neither of them is \nhuge, but they've kept me from doing them..\n\n - if you screw up half-way through the merge, it's a lot harder to \n   recover without blowing away all the other merges too and having to \n   re-do them. You certainly _can_ do it (say, by just recording the trees\n   in between merges - it's definitely not rocket science), but it\n   basically means that you need to keep track of things _outside_ of the\n   normal \"what was the last HEAD\" model.\n\n   More importantly, since an octopus merge has only one commit message \n   associated with it, you really should never use one for anything that \n   needs any manual intervention. Otherwise you'll have to start \n   explaining which merge you needed to fix up manually etc, and it just \n   gets complex for no actual gain.\n\n   IOW, this argument is only against complex merges. The trivial ones can \n   easily be done as octopuses, and in many ways the resulting history may \n   actually reflect what you did better. For example, for somebody like \n   Jeff, who maintains 50 different branches, and merges 5 of them to send \n   them to me, an octopus merge in many ways is much more intuitive: it \n   really says \"I took these five branches and combined them\", while a \n   series of four regular merges just gets messy.\n\n - Compatibility with other systems. \n\n   I don't care one whit about stuff I consider broken (ie CVS), but there \n   are SCM's out there that I _don't_ think are broken, and that don't do\n   multi-parent merges for \"nrparent > 2\".  You can always split an \n   octopus merge that didn't have any manual intervention, so again, this\n   is not a huge argument if you follow rule #1, but unless you have a \n   reason for doing an octopus merge, it means that you should probably \n   avoid it.\n\n   So _I_ usually don't have any reason at all, it would be stupid of me\n   to merge trees from different people as an octopus, but usage like \n   Jeff's (where the merge is due to \"pass these <n> trees upwards\") is \n   different.\n\nSo there you have it. Don't do it just because you can, but if you have a \ngood reason for them and they were done automatically without any human \nintervention (apart from having to change the scripts, of course), I won't \nargue too much against them either. I already took one such merge from \nJunio in the GIT tree, and I actually like having that as a way to make \nsure the tools can handle it.\n\n\t\tLinus\n"},{"id":"4081","messageId":"7vu0kowho9.fsf@assigned-by-dhcp.cox.net","threadId":"737","inReplyTo":"20050527195552.GA6541@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-27T20:13:58Z","receivedAt":"2005-05-27T20:13:58Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"TG\" == Thomas Glanzmann <sithglan@stud.uni-erlangen.de> writes:\n\n>> You merge by hand and resolve if they have conflicts, just like\n>> what you already do in two head merge case.\n\nTG> I see. Does that mean that 'git-ls-files --unmerged' will report upto 9\nTG> stages per file?\n\nNo, I think my description was unclear.  You still merge two at\na time because that is what git-read-tree -m gives you (3-way\nmerge is between $(merge-base $A $B) and $A and $B so you are\nmerging two heads).\n\nTo confess, my workflow to merge with Linus is currently\nprimarily patch based, so I do not even use git-read-tree -m\n3-way merge when I make an Octopus (for that matter, I do not\nmyself do Octopus at all these days).  When I have bunch of\nindependent changes, I would first prepare and test these:\n\n           -- JC#1\n          / - JC#2\n         /  - JC#3\n  Linus#1-  - JC#4  \n         \\    ...\n          \\-- JC#7\n\nBy the time I am done and happy with them, tip of Linus tree may\nhave already advanced and he is at Linus#2.  I would then apply\ndiffs between Linus#1 and JC#n (1 <= n <= 7) on top of Linus #2,\nand commit the result with parents set to Linus #2 and JC#1,\nJC#2, ..., JC#7.\n\n           ------- Linus#2\n          /               \\\n         / -- JC#1 --------\\\n        / /-- JC#2 ---------\\ \n       / /--- JC#3 ----------\\\n  Linus#1---- JC#4 ---------- Octopus \n         \\    ...            /\n          \\-- JC#7 ----------\n\n"},{"id":"4082","messageId":"Pine.LNX.4.58.0505271307510.17402@ppc970.osdl.org","threadId":"737","inReplyTo":"20050527195552.GA6541@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-05-27T20:17:10Z","receivedAt":"2005-05-27T20:17:10Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Fri, 27 May 2005, Thomas Glanzmann wrote:\n\n> > You merge by hand and resolve if they have conflicts, just like\n> > what you already do in two head merge case.\n> \n> I see. Does that mean that 'git-ls-files --unmerged' will report upto 9\n> stages per file?\n\nNo, you must always merge trees one by one against each other. The\nsimplest ordering is to merge trees 1-2 first, then the result of that\nwith 3, then the result of _that_ with 4 etc etc, but you can - if you\nreally want to - do 1-2 and 3-4 separately and then merge those two\ntogether.\n\nThe ordering does actually end up mattering a bit when it comes to\ndeciding on parenthood, but in the end you will have used the same most\nremote common parent for _one_ of the merges anyway, so assuming all the\nmerges were automatically resolved by the regular 3-way thing, I claim\nthat it doesn't really matter noticeably (*).\n\nRegardless, you'd end up with seven \"git-read-tree -m x y z\" invocations\n(plus possibly a few git-merge-cache calls), and one final commit.\n\n\t\tLinus\n\n(*) I bet you could find some case where the ordering either generates a\ncreate-create conflict or it doesn't, depending on how you pair things up. \n\nBut I also claim that you'd be crazy to do a octopus merge for something \nlike that anyway, and that the reason to do one is that you've had five \ntotally disjoint things you've been working on - like updating five \ndifferent drivers or five different filesystems in different branches, and \nthere are no conflicts however you turn.\n\n"},{"id":"4083","messageId":"7voeawwh5x.fsf@assigned-by-dhcp.cox.net","threadId":"737","inReplyTo":"Pine.LNX.4.58.0505271248450.17402@ppc970.osdl.org","subject":"Re: More gitweb queries..","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-27T20:24:58Z","receivedAt":"2005-05-27T20:24:58Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"LT\" == Linus Torvalds <torvalds@osdl.org> writes:\n\nLT>    For example, for somebody like \nLT>    Jeff, who maintains 50 different branches, and merges 5 of them to send \nLT>    them to me, an octopus merge in many ways is much more intuitive: it \nLT>    really says \"I took these five branches and combined them\", while a \nLT>    series of four regular merges just gets messy.\n\nThis really is a good use case for an Octopus.  I hope Jeff is\nreading this thread.\n\n\n\n"},{"id":"4084","messageId":"20050527203227.GA11139@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"Pine.LNX.4.58.0505271248450.17402@ppc970.osdl.org","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-27T20:32:27Z","receivedAt":"2005-05-27T20:32:27Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\nokay thanks for the elaboration on the topic. I will now adopt my\nscripts to handle it. I think I already have a use for it.\n\n            -- mutt-hcache   --\n           /-- mutt-imap     --\\\n          /--- mutt-whatever ---\\\n mutt-cvs ---- ...           ----- mutt-tg (my working tree)\n          \\    ...           ----/\n           \\-- ...             -/\n\nActually, I have already 12 trees with different features which I work on.\n\n 1 mutt-attach-file       5 mutt-hcache            9 mutt-menu-move\n 2 mutt-collapse-flags    6 mutt-headers          10 mutt-move-hook\n 3 mutt-cstatus           7 mutt-imap             11 mutt-setenv-hack\n 4 mutt-edit-threads      8 mutt-maildir-mtime    12 mutt-thread-pattern\n\nBut I guess 8 is the limit, isn't it? Did you thought to make this 8 a\n'n' or is 8 just enough? :-)\n\n\tThomas\n"},{"id":"4086","messageId":"7vk6lkwgfl.fsf@assigned-by-dhcp.cox.net","threadId":"737","inReplyTo":"20050527203227.GA11139@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-27T20:40:46Z","receivedAt":"2005-05-27T20:40:46Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"TG\" == Thomas Glanzmann <sithglan@stud.uni-erlangen.de> writes:\n\nTG> But I guess 8 is the limit, isn't it? Did you thought to make this 8 a\nTG> 'n' or is 8 just enough? :-)\n\nBuilt-in limit of commit object is 16, not 8.\n\n\n"},{"id":"4094","messageId":"Pine.LNX.4.58.0505271457480.17402@ppc970.osdl.org","threadId":"737","inReplyTo":"7vk6lkwgfl.fsf@assigned-by-dhcp.cox.net","subject":"Re: More gitweb queries..","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-05-27T22:00:28Z","receivedAt":"2005-05-27T22:00:28Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Fri, 27 May 2005, Junio C Hamano wrote:\n>\n> >>>>> \"TG\" == Thomas Glanzmann <sithglan@stud.uni-erlangen.de> writes:\n> \n> TG> But I guess 8 is the limit, isn't it? Did you thought to make this 8 a\n> TG> 'n' or is 8 just enough? :-)\n> \n> Built-in limit of commit object is 16, not 8.\n\nActually, even that is not actually built into the commit object itself, \nthat's just a #define in commit-tree.c.\n\nChange the MAXPARENT design from 16 to 1024, and nobody will notice any \ndifference at all, except \"git-commit-tree.c\" will use 20kB more memory ;)\n\nThere's no limit in the data structures, although there clearly is a \n\"sanity\" limit (and I personally suspect it comes before you hit 16 ;)\n\n\t\tLinus\n"},{"id":"4095","messageId":"20050527220417.GC12187@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"Pine.LNX.4.58.0505271457480.17402@ppc970.osdl.org","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-27T22:04:17Z","receivedAt":"2005-05-27T22:04:17Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\n\n> Actually, even that is not actually built into the commit object\n> itself, that's just a #define in commit-tree.c.  Change the MAXPARENT\n> design from 16 to 1024, and nobody will notice any difference at all,\n> except \"git-commit-tree.c\" will use 20kB more memory ;)\n\nThat sounds just way to perfect. :-)\n\n> There's no limit in the data structures, although there clearly is a \n> \"sanity\" limit (and I personally suspect it comes before you hit 16 ;)\n\nI like how this 'simple' git concepts just fits into all this usage\nscenarios. Including this one or the way we can track renames. Name it!\nThanks for giving us this perfect piece of software! :-)\n\n\tThomas\n"},{"id":"4113","messageId":"1117235527.9076.211.camel@gaston","threadId":"737","inReplyTo":"Pine.LNX.4.58.0505271145570.17402@ppc970.osdl.org","subject":"Re: More gitweb queries..","fromName":"Benjamin Herrenschmidt","fromEmail":"benh@kernel.crashing.org","sentAt":"2005-05-27T23:12:06Z","receivedAt":"2005-05-27T23:12:06Z","isPatch":false,"sender":{"key":"benh@kernel.crashing.org","avatar":null},"body":"\n>   On that small note, I also find \"gitk\" very cool indeed, too bad about \n>   the fact that tk/tcl seems to always end up looking so _ugly_. Is there \n>   any way to get anti-aliased fonts and a less 'Motify' blocky look from \n>   tcl/tk? Every time I see that, I feel like I'm back in the last century  \n>   or something.\n\nHeh, tell paulus, he loves Tk :-)\n\nHe told me the next version of Tk will have anti aliased fonts. I don't\nknow about blockyness of the widgets tho.\n\n>   Combining some of the features of the two (that über-cool revision \n>   history graph from gitk rules, for example) might be cool. I get the \n>   urge to do octopus-merges in the kernel just because of how good they\n>   look in gitk ;) ]\n\n\n\n"},{"id":"4115","messageId":"20050527235924.GB19491@vrfy.org","threadId":"737","inReplyTo":"Pine.LNX.4.58.0505271145570.17402@ppc970.osdl.org","subject":"Re: More gitweb queries..","fromName":"Kay Sievers","fromEmail":"kay.sievers@vrfy.org","sentAt":"2005-05-27T23:59:24Z","receivedAt":"2005-05-27T23:59:24Z","isPatch":false,"sender":{"key":"kay.sievers@vrfy.org","avatar":null},"body":"On Fri, May 27, 2005 at 12:24:20PM -0700, Linus Torvalds wrote:\n>  - looking around, the ALSA guys aren't the only ones that start off with \n>    an empty line, so it's probably worth fixing the summary etc to ignore \n>    whitespace at the beginning rather than give empty summary reasons.\n\nThat is already fixed a few days ago, but unfortunately only in my devel\nversion. After the catch-up on the recent format changes of the git-output,\nI need to wait now until the new git-binaries are hitting kernel.org.\n\n>  - any reason to limit the \"summary\" page to just the last 14 changes? The \n>    \"log\" thing you can ask to go back further, it would be nice to have\n>    something like a \"last 100\" thing for summaries too, especially since \n>    the summary is so nice and dense, so you can actually get a nice view \n>    of what has happened without scrolling _too_ much.\n\nYes, I recognized that too. Jeff asked for branches and I did the summary\npage just for the branches. :) With that I realized that the dense log of the\nsummary is sometimes nicer than the full log. How about this:\n  http://ehlo.org/~kay/gitweb.cgi?p=git/git.git;a=shortlog\n\nIt is reachable on the summary page by clicking in the title of the\nshortlog.\n\n>  - I was in the \"commitdiff\" thing, and initially thought that there was \n>    no way to get back to the \"summary\" view.\n> \n>    It turns out I was wrong (the summary is reachable by just clicking at\n>    the project name itself in the top header), but it's a bit strange that\n>    the \"commitdiff\" thing has an explicit link back to itself (hey, \n>    consistency is good, so I'm not complaining)\n\nWell, yes I was trying to get a navigation which is not changing with\nevery new page... It's not an active link now. Maybe that's better.\n\n>    but the link back to the\n>    summary page is implicit.\n> \n>    So how about adding an explicit \"summary\" link to the list of other \n>    explicit links (log, commit, commitdiff and tree) at the top of the \n>    page?\n\nDone! That was easy. It will show up on kernel.org when the actual\ngit-binaries are installed.\n\n> I actually like browsing other peoples projects with the gitweb\n> interfaces, it's both responsive and verbose enough to really say\n> something good. In contrast, cvsweb is always just a mess of \"these are\n> the files, go at it\", which is totally pointless and doesn't tell anything\n> about what is actually happening in the project.\n> \n> So dammit, I'm very biased indeed, but I'm just looking at gitweb, and\n> comparing it to both the CVS and SVN web things, and they just reinforce\n> my conviction that CVS is absolute crap, and I find myself surprised by\n> how crap SVN also appears.\n\nGood to hear that. It's a long road to make software from \"working\" to\n\"nice to use\". That was probably never the goal of some SCM-web-interfaces. :)\n\n>   Combining some of the features of the two (that über-cool revision \n>   history graph from gitk rules, for example) might be cool. I get the \n>   urge to do octopus-merges in the kernel just because of how good they\n>   look in gitk ;) ]\n\nI would like to show something like the graph too, but I don't really know\nhow to do this in html. Seems slippery if not impossible.\nIf anybody has a nice idea how to represent that, I will give it a try.\n\nKay\n"},{"id":"4117","messageId":"f0796bb705052718035cd5dbe2@mail.gmail.com","threadId":"737","inReplyTo":"20050527235924.GB19491@vrfy.org","subject":"Re: More gitweb queries..","fromName":"Daniel Serpell","fromEmail":"daniel.serpell@gmail.com","sentAt":"2005-05-28T01:03:24Z","receivedAt":"2005-05-28T01:03:24Z","isPatch":false,"sender":{"key":"daniel.serpell@gmail.com","avatar":null},"body":"Hi!\n\nOn 5/27/05, Kay Sievers <kay.sievers@vrfy.org> wrote:\n> On Fri, May 27, 2005 at 12:24:20PM -0700, Linus Torvalds wrote:\n> >   Combining some of the features of the two (that über-cool revision\n> >   history graph from gitk rules, for example) might be cool. I get the\n> >   urge to do octopus-merges in the kernel just because of how good they\n> >   look in gitk ;) ]\n> \n> I would like to show something like the graph too, but I don't really know\n> how to do this in html. Seems slippery if not impossible.\n> If anybody has a nice idea how to represent that, I will give it a try.\n\nWell, you could draw them in javascript, using\nhttp://www.walterzorn.com/jsgraphics/jsgraphics_e.htm :-)\n\nAlternatively, you could use a fixed set of little images, a bar \"|\", a\ndot \"o\" and branches like \"Y\", \"7\" and \"\\\". Obviously, octopus-merges\nare very difficult to draw using only those.\n\nBTW, I tried searching on gitweb, and I think that found a problem, see:\nhttp://ehlo.org/~kay/gitweb.cgi?p=git/git.git;a=search;s=check\nAt the bottom of the page, highlighting of the search term stops and the\ncommits are all the same color.\n\n        Daniel.\n"},{"id":"4119","messageId":"7vwtpkytk4.fsf@assigned-by-dhcp.cox.net","threadId":"737","inReplyTo":"Pine.LNX.4.58.0505271457480.17402@ppc970.osdl.org","subject":"Re: More gitweb queries..","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-28T02:26:35Z","receivedAt":"2005-05-28T02:26:35Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"LT\" == Linus Torvalds <torvalds@osdl.org> writes:\n\nLT> There's no limit in the data structures, although there clearly is a \nLT> \"sanity\" limit (and I personally suspect it comes before you hit 16 ;)\n\nI know that my head would start hurting way before I hit 16.\n\nI probably shouldn't have coined the word Octopus in the first\nplace, giving people a false impression that somehow 8 is a\nmagic number.  To begin with, what I inflicted on you was not\neven an Octopus but a Pentapus, merge of 5 IIRC.\n\nAlso we are counting heads, not legs.  Should have said Hydra,\nbut I do not offhand know how many heads it has --- I've never\nmet one.  I know King Ghidorah has 3 heads ;-).\n\n"},{"id":"4120","messageId":"Pine.LNX.4.62.0505271949480.15585@qynat.qvtvafvgr.pbz","threadId":"737","inReplyTo":"f0796bb705052718035cd5dbe2@mail.gmail.com","subject":"Re: More gitweb queries..","fromName":"David Lang","fromEmail":"dlang@digitalinsight.com","sentAt":"2005-05-28T02:51:39Z","receivedAt":"2005-05-28T02:51:39Z","isPatch":false,"sender":{"key":"dlang@digitalinsight.com","avatar":null},"body":"> Hi!\n>\n> On 5/27/05, Kay Sievers <kay.sievers@vrfy.org> wrote:\n>> On Fri, May 27, 2005 at 12:24:20PM -0700, Linus Torvalds wrote:\n>>>   Combining some of the features of the two (that über-cool revision\n>>>   history graph from gitk rules, for example) might be cool. I get the\n>>>   urge to do octopus-merges in the kernel just because of how good they\n>>>   look in gitk ;) ]\n>>\n>> I would like to show something like the graph too, but I don't really know\n>> how to do this in html. Seems slippery if not impossible.\n>> If anybody has a nice idea how to represent that, I will give it a try.\n>\n> Well, you could draw them in javascript, using\n> http://www.walterzorn.com/jsgraphics/jsgraphics_e.htm :-)\n>\n> Alternatively, you could use a fixed set of little images, a bar \"|\", a\n> dot \"o\" and branches like \"Y\", \"7\" and \"\\\". Obviously, octopus-merges\n> are very difficult to draw using only those.\n\nyou could look into SVG (scaleable vector graphics or some such thing) \nthat are supposed to be in the newest browsers (or soon to be added, I'm \nnot sure). this should let you do all the drawing nessasary reasonably \neasily (if you are willing to limit users to that, which is probably not \nthat big of a problem for git)\n\nDavid Lang\n\n-- \nThere are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.\n  -- C.A.R. Hoare\n"},{"id":"4126","messageId":"20050528084255.GA32614@vrfy.org","threadId":"737","inReplyTo":"f0796bb705052718035cd5dbe2@mail.gmail.com","subject":"Re: More gitweb queries..","fromName":"Kay Sievers","fromEmail":"kay.sievers@vrfy.org","sentAt":"2005-05-28T08:42:55Z","receivedAt":"2005-05-28T08:42:55Z","isPatch":false,"sender":{"key":"kay.sievers@vrfy.org","avatar":null},"body":"On Fri, May 27, 2005 at 09:03:24PM -0400, Daniel Serpell wrote:\n> Hi!\n> \n> On 5/27/05, Kay Sievers <kay.sievers@vrfy.org> wrote:\n> > On Fri, May 27, 2005 at 12:24:20PM -0700, Linus Torvalds wrote:\n> > >   Combining some of the features of the two (that über-cool revision\n> > >   history graph from gitk rules, for example) might be cool. I get the\n> > >   urge to do octopus-merges in the kernel just because of how good they\n> > >   look in gitk ;) ]\n> > \n> > I would like to show something like the graph too, but I don't really know\n> > how to do this in html. Seems slippery if not impossible.\n> > If anybody has a nice idea how to represent that, I will give it a try.\n> \n> Well, you could draw them in javascript, using\n> http://www.walterzorn.com/jsgraphics/jsgraphics_e.htm :-)\n\nYou know how that stuff works? :) It is a very nice idea for\nsmall stuff, but it uses a <div> for every pixel/line you draw and\nplaces this in the background and I expect it to kill your browser if\nyou try to draw things like gitk does.\n\n> Alternatively, you could use a fixed set of little images, a bar \"|\", a\n> dot \"o\" and branches like \"Y\", \"7\" and \"\\\". Obviously, octopus-merges\n> are very difficult to draw using only those.\n\nDid you look at gitk? With a all the crossing and long lines, you definitely\nneed to draw the lines with colors. Otherwise you will see _nothing_, but\nrandom characters. :)\n\n> BTW, I tried searching on gitweb, and I think that found a problem, see:\n> http://ehlo.org/~kay/gitweb.cgi?p=git/git.git;a=search;s=check\n> At the bottom of the page, highlighting of the search term stops and the\n> commits are all the same color.\n\nWell, you see a list of files which contain the text, not the text\nitself. I can print the filename in red. :)\n\nThanks,\nKay\n"},{"id":"4131","messageId":"20050528105622.GB32614@vrfy.org","threadId":"737","inReplyTo":"Pine.LNX.4.62.0505271949480.15585@qynat.qvtvafvgr.pbz","subject":"Re: More gitweb queries..","fromName":"Kay Sievers","fromEmail":"kay.sievers@vrfy.org","sentAt":"2005-05-28T10:56:22Z","receivedAt":"2005-05-28T10:56:22Z","isPatch":false,"sender":{"key":"kay.sievers@vrfy.org","avatar":null},"body":"On Fri, May 27, 2005 at 07:51:39PM -0700, David Lang wrote:\n> >Hi!\n> >\n> >On 5/27/05, Kay Sievers <kay.sievers@vrfy.org> wrote:\n> >>On Fri, May 27, 2005 at 12:24:20PM -0700, Linus Torvalds wrote:\n> >>>  Combining some of the features of the two (that über-cool revision\n> >>>  history graph from gitk rules, for example) might be cool. I get the\n> >>>  urge to do octopus-merges in the kernel just because of how good they\n> >>>  look in gitk ;) ]\n> >>\n> >>I would like to show something like the graph too, but I don't really know\n> >>how to do this in html. Seems slippery if not impossible.\n> >>If anybody has a nice idea how to represent that, I will give it a try.\n> >\n> >Well, you could draw them in javascript, using\n> >http://www.walterzorn.com/jsgraphics/jsgraphics_e.htm :-)\n> >\n> >Alternatively, you could use a fixed set of little images, a bar \"|\", a\n> >dot \"o\" and branches like \"Y\", \"7\" and \"\\\". Obviously, octopus-merges\n> >are very difficult to draw using only those.\n> \n> you could look into SVG (scaleable vector graphics or some such thing) \n> that are supposed to be in the newest browsers (or soon to be added, I'm \n> not sure). this should let you do all the drawing nessasary reasonably \n> easily (if you are willing to limit users to that, which is probably not \n> that big of a problem for git)\n\nWell, technology that is \"soon to be added\" since years is probably not\nmy favorite thing to base my work on. SVG could be nice, sure, but nearly\nnoone is able to see it today and I expect, I will need to wait wait for\nanother few years. :)\n\nKay\n"},{"id":"4148","messageId":"1117320229.5228.18.camel@gaston","threadId":"737","inReplyTo":"20050528084255.GA32614@vrfy.org","subject":"Re: More gitweb queries..","fromName":"Benjamin Herrenschmidt","fromEmail":"benh@kernel.crashing.org","sentAt":"2005-05-28T22:43:48Z","receivedAt":"2005-05-28T22:43:48Z","isPatch":false,"sender":{"key":"benh@kernel.crashing.org","avatar":null},"body":"On Sat, 2005-05-28 at 10:42 +0200, Kay Sievers wrote:\n\n> You know how that stuff works? :) It is a very nice idea for\n> small stuff, but it uses a <div> for every pixel/line you draw and\n> places this in the background and I expect it to kill your browser if\n> you try to draw things like gitk does.\n> \n> > Alternatively, you could use a fixed set of little images, a bar \"|\", a\n> > dot \"o\" and branches like \"Y\", \"7\" and \"\\\". Obviously, octopus-merges\n> > are very difficult to draw using only those.\n> \n> Did you look at gitk? With a all the crossing and long lines, you definitely\n> need to draw the lines with colors. Otherwise you will see _nothing_, but\n> random characters. :)\n> \n> > BTW, I tried searching on gitweb, and I think that found a problem, see:\n> > http://ehlo.org/~kay/gitweb.cgi?p=git/git.git;a=search;s=check\n> > At the bottom of the page, highlighting of the search term stops and the\n> > commits are all the same color.\n> \n> Well, you see a list of files which contain the text, not the text\n> itself. I can print the filename in red. :)\n\nBest may be to have the server generate a picture ... ?\n\nBen.\n\n\n"},{"id":"4205","messageId":"20050529230240.GB12290@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"20050527203227.GA11139@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-29T23:02:40Z","receivedAt":"2005-05-29T23:02:40Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\nhere we go!  gitk screenshot:\nhttp://wwwcip.informatik.uni-erlangen.de/~sithglan/shot.png (64k)\n\n(faui00u) [~/work/mutt/git/mutt-test] ../../../git/yagf/git pull ../mutt-attach-file/ ../mutt-collapse-flags/ ../mutt-cstatus/ ../mutt-cvs/ ../mutt-edit-threads/ ../mutt-hcache/ ../mutt-headers/ ../mutt-imap/ ../mutt-maildir-mtime/ ../mutt-move-hook/ ../mutt-setenv-hack/ ../mutt-thread-pattern/ ../mutt-menu-move/\n<chatty output>\n(faui00u) [~/work/mutt/git/mutt-test] git treediff ../mutt-tg-solaris\n(faui00u) [~/work/mutt/git/mutt-test] git changes -m | perl -pe '$a += /^diff-tree/; exit if $a==2'\ndiff-tree 5b22da9792b6f6a968dc0a916275d6c301575f75 (from e8f4a291a81f0a8fb24555f0e36e4b75e2d3f4c8)\nAuthor: Thomas Glanzmann <sithglan@stud.uni-erlangen.de>\nDate:   Mon May 30 00:28:53 2005 +0200\n\n    => faui00u:/home/cip/adm/sithglan/work/mutt/git/mutt-test\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-attach-file/.git (bringing head ahead)\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-collapse-flags/.git (automatic merge)\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-cstatus/.git (threeway merge)\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-cvs/.git (nothing to merge)\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-edit-threads/.git (threeway merge)\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-hcache/.git (threeway merge)\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-headers/.git (threeway merge)\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-imap/.git (automatic merge)\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-maildir-mtime/.git (threeway merge)\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-move-hook/.git (nothing to merge)\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-setenv-hack/.git (automatic merge)\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-thread-pattern/.git (threeway merge)\n    <= /home/cip/adm/sithglan/work/mutt/git/mutt-test/../mutt-menu-move/.git (threeway merge)\n\nCould please someone who has a clue how this merge should work (which it\nhopefully already does) look at my code to check for obvious mistakes in\nthe merge *logic*.  I call 'merge' with all involved trees (with current\nhead first, if there is a current head). If everything is fine. I would\nlike to write a seperate git-resolve script in sh or adopt the current\nto multi head merge - whatever you please.\n\nsub\nmerge\n{\n\n\tmy $message      = undef;\n\tmy $head         = undef;\n\tmy $last_tree    = undef;\n\tmy $fh;\n\tmy @heads        = ();\n\n\tforeach my $r (@_) {\n\t\tmy $current_head = @{$r}[0];\n\t\tmy $current_url  = @{$r}[1];\n\n\t\tprint \"current_head => $current_head\\ncurrent_url => $current_url\\n\";\n\n\t\tpush(@heads, '-p', ${current_head});\n\n\t\tif (! defined($last_tree)) {\n\t\t\t$message    = \"=> ${current_url}\\n\";\n\t\t\t$head       = $current_head;\n\t\t\t$last_tree  = $current_head;\n\t\t\t\n\t\t\tif (@_ == 1) {\n\t\t\t\thead($head);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tnext;\n\t\t}\n\n\t\tmy $merge_base = gitcmdout('git-merge-base', $head, $current_head)\n\t\t\t\t || die (\"no merge-base\");\n\t\tchomp($merge_base);\n\n\t\tprint \"head => $head\\nremote => $current_head\\nbase => $merge_base\\n\";\n\t\n\t\tif ($merge_base eq $current_head) {\n\t\t\t$message .= \"<= ${current_url} (nothing to merge)\\n\";\n\n\t\t\tif (@_ == 2) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tnext;\n\t\t}\n\n\t\tif ($merge_base eq $head) {\n\t\t\t$message   .= \"<= ${current_url} (bringing head ahead)\\n\";\n\t\t\t$head       = ${current_head};\n\t\t\t$last_tree  = ${current_head};\n\n\t\t\tif (@_ == 2) {\n\t\t\t\thead($head);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tnext;\n\t\t}\n\n\t\tgitcmd('git-read-tree', '-m', $merge_base, $last_tree, $current_head);\n\t\tif (! defined($last_tree = write_tree())) {\n\t\t\tsystem('git-merge-cache', '-o', 'git-merge-one-file-script', '-a');\n\t\t\tif (! defined($last_tree = write_tree())) {\n\t\t\t\t# FIXME: Make manual intervention possible\n\t\t\t\t# --tg 23:11 05-05-29\n\t\t\t\tdie(\"Couldn't merge automatically: Call 'git resolve'\");\n\t\t\t}\n\t\t\t$message .= \"<= ${current_url} (threeway merge)\\n\";\n\n\t\t} else {\n\t\t\t$message .= \"<= ${current_url} (automatic merge)\\n\";\n\t\t}\n\t}\n\n\topen($fh, \"+>\", undef);\n\tprint $fh $message;\n\tseek($fh, 0, 0);\n\t$head = gitcmdinout($fh, 'git-commit-tree', $last_tree, @heads);\n\tchomp($head);\n\tclose $fh;\n\n\thead($head);\n\treturn;\n}\n\n\tThomas\n\n\n#!/usr/bin/env perl\n\nuse strict;\nuse warnings;\nuse IO::Handle;\nuse File::Temp qw/ tempfile tempdir /;\nuse File::Copy;\nuse Cwd;\nuse Getopt::Long;\n\nSTDOUT->autoflush(1);\n\nmy $hostname = gitcmdout('hostname');\nchomp($hostname);\n\nmy $DIFF  = undef;\nmy $PATCH = undef;\n\nif (-x '/opt/csw/bin/gdiff') {\n\t$DIFF='/opt/csw/bin/gdiff';\n\n} else {\n\t$DIFF='diff';\n}\n\nif (-x '/usr/bin/gpatch') {\n\t$PATCH='/usr/bin/gpatch';\n\n} else {\n\t$PATCH='patch';\n}\n\nmy %commands = (\n\t\"add\"        => \\&add,\n\t\"checkout\"   => \\&checkout,\n\t\"ci\"         => \\&ci,\n\t\"clone\"      => \\&clone,\n\t\"commit\"     => \\&commit,\n\t\"diff\"       => \\&diff,\n\t\"treediff\"   => \\&treediff,\n\t\"dirty\"      => \\&dirty,\n\t\"help\"       => \\&usage,\n\t\"init-db\"    => \\&init_db,\n\t\"log\"        => \\&log,\n\t\"orphan\"     => \\&orphan,\n\t\"parent\"     => \\&parent,\n\t\"patch\"      => \\&patch,\n\t\"pull\"       => \\&pull,\n\t\"push\"       => \\&_push,\n\t\"refresh\"    => \\&refresh,\n\t\"revert\"     => \\&revert,\n\t\"rm\"         => \\&rm,\n\t\"setup\"      => \\&setup,\n\t\"status\"     => \\&status,\n\t\"undo\"       => \\&undo,\n\t\"changed\"    => \\&changed,\n\t\"resolve\"    => \\&resolve,\n\t\"changes\"    => \\&changes,\n);\n\nmy %touched = ();\n\nsub\nusage\n{\n\tprint STDERR <<\"__EOF__\";\nUsage: $0 COMMAND [ARG]...\n\nAvailable commands:\n\n__EOF__\n\n\tprint \"\\t\" . join(\"\\n\\t\", sort(keys(%commands))) . \"\\n\\n\";\n\n\treturn 1;\n}\n\nsub\nrefresh\n{\n\t`git-update-cache --refresh`;\n}\n\nsub\nprocess_git_diff_output\n{\n\tmy $str = shift || return (());\n\n\tmy @in  = split(\"\\0\", $str);\n\tmy @out = ();\n\n\twhile (@in) {\n\t\tmy @tmp = split(' ', shift(@in));\n\t\t$tmp[0] =~ s/^://g;\n\t\tpush(@tmp, shift(@in));\n\t\tpush(@out, [@tmp]);\n\t}\n\n\treturn(@out);\n}\n\nsub\ndirty_files\n{\n\trefresh();\n\n\tmy @dirty = ();\n\tmy $str = gitcmdout('git-diff-files', '-z', '-r');\n\n\tforeach (process_git_diff_output($str)) {\n\t\tif ((@{$_})[1] ne '000000') {\n\t\t\tpush(@dirty, @{$_}[5]);\n\t\t}\n\t\t#print \"<\" . join(\"> <\", @{$_}) . \">\\n\";\n\t}\n\n\treturn @dirty;\n}\n\nsub\norphan_files\n{\n\tmy @orphan = gitcmdout('git-ls-files', '--others');\n\tchomp(@orphan);\n\n\tmy $regexp = '^\\.';\n\tif (-f '.git/ignore') {\n\t\tmy @ignore = ();\n\t\tchomp (@ignore = _read_file('.git/ignore'));\n\t\t$regexp = join('|', '^\\.', @ignore);\n\t}\n\n\t@orphan = grep(! /$regexp/, @orphan);\n\n\treturn @orphan;\n}\n\nsub\norphan\n{\n\tforeach (orphan_files()) {\n\t\tprint $_ . \"\\n\";\n\t}\n}\n\nsub\ndirty\n{\n\tforeach (dirty_files()) {\n\t\tprint $_ . \"\\n\";\n\t}\n}\n\nsub\nchanged\n{\n\tforeach my $rev (gitcmdout('git-rev-list', 'HEAD')) {\n\t\tchomp($rev);\n\t\tmy %hash = commit_hash($rev);\n\t\t\n\t\tmy $str = gitcmdout('git-diff-tree', '--root', '-r', '-z', $rev);\n\t\tforeach (process_git_diff_output($str)) {\n\t\t\tmy ($time, $rest) = split(/\\s/, $hash{committer_date});\n\t\t\tpush(@{$touched{@{$_}[5]}}, $time);\n\t\t}\n\t}\n}\n\nsub\nstatus\n{\n\tmy %hash = ();\n\t\n\tforeach (orphan_files()) {\n\t\t$hash{$_} = '?';\n\t}\n\n\tforeach (dirty_files()) {\n\t\t$hash{$_} = 'D';\n\t}\n\n\tmy $str = gitcmdout('git-diff-cache', '-r', '--cached', '-z', 'HEAD');\n\tforeach (process_git_diff_output($str)) {\n\t\tif      (@{$_}[0] eq '000000') {\n\t\t\t$hash{@{$_}[5]} .= '+';\n\n\t\t} elsif (@{$_}[1] eq '000000') {\n\t\t\t$hash{@{$_}[5]} .= '-';\n\n\t\t} else {\n\t\t\t$hash{@{$_}[5]} .= '*';\n\t\t}\n\t}\n\n\tforeach (sort(keys(%hash))) {\n\t\tif ($hash{$_} eq \"D\") {\n\t\t\t$hash{$_} = \"D \";\n\t\t}\n\t\tprintf(\"% 2s %s\\n\", $hash{$_}, $_);\n\t}\n}\n\nsub\nwrite_tree\n{\n\tchomp (my $tree = `git-write-tree`);\n\tif ($?) {\n\t\treturn undef;\n\t} else {\n\t\treturn $tree;\n\t}\n}\n\nsub\nretrieve_unmerged\n{\n\tmy %hash = ();\n\t\n\tforeach my $line (gitcmdout('git-ls-files', '--unmerged')) {\n\t\tchomp($line);\n# 100644 cde27275fad8103084d7ed2d08d246ba4ce6eb9c 1 Makefile\n# 100644 d311a35e5e8a09629ea9e6051a43710c76fa8f6d 2 Makefile\n# 100644 ec2b76bf90fb105b2aaf00a66f44b135046d3002 3 Makefile\n\t\tif ($line =~ /^(\\d{6})\\s([a-z0-9]{40})\\s(\\d)\\s(.+)$/) {\n\t\t\tpush(@{$hash{$4}}, $line);\n\t\t} else {\n\t\t\tdie(\"Can't match: <$line>\\n\");\n\t\t}\n\t}\n\n\treturn %hash;\n}\n\nsub\nprocess_unmerged_file\n{\n\tmy $line;\n\tmy $file;\n\tmy @files = ();\n\twhile($line = shift) {\n\t\tif ($line =~ /^(\\d{6})\\s([a-z0-9]{40})\\s(\\d)\\s(.+)$/) {\n\t\t\tif ($3 eq '1') { $file = \"$4.GCA\"; }\n\t\t\tif ($3 eq '2') { $file = \"$4.LOCAL\"; }\n\t\t\tif ($3 eq '3') { $file = \"$4.REMOTE\"; }\n\n\t\t\tmy $mode = substr($1, 2);\n\n\t\t\tif (-f $file) {\n\t\t\t\tdie(\"Please get rid of $file\\n\");\n\t\t\t}\n\n\t\t\tprint STDERR \"Checking out: $file with permissions $mode\\n\";\n\n\t\t\tsystem(\"git-cat-file blob $2 > $file\");\n\t\t\tchmod oct($mode), $file;\n\t\t\tpush(@files, $file);\n\t\t}\n\t}\n\n\tif (@files == 3) {\n\t\tmy $filename = (@files)[0];\n\t\t$filename =~ s#\\.(GCA|LOCAL|REMOTE)$##;\n\n\t\tprint STDERR <<\"EOF\";\n\nYou got GCA, LOCAL and REMOTE, so I run merge for you and leaving the merges in\n${filename} .\\n\n\nEOF\n\n\t\tunlink($filename);\n\t\tsystem('cp', \"${filename}.LOCAL\", \"${filename}\");\n\n\t\tsystem('merge', \"${filename}\", \"${filename}.GCA\", \"${filename}.REMOTE\");\n\t}\n\n\tprint STDERR <<\"EOF\";\n\nPlease resolve the conflict and add the file using the command 'git ci file'.\nDroping you to a login shell now. Please exit the shell as soon as you resolved\nthe conflict.\n\nEOF\n\n\tsystem($ENV{'SHELL'}, '--login');\n\n\tforeach (@files) {\n\t\tunlink($_);\n\t}\n}\n\nsub\nresolve\n{\n\tif (! -f '.git/RESOLVE') {\n\t\tdie(\"Nothing to resolve\");\n\t}\n\tif ( ! -f '.git/HEAD' && ! -l '.git/HEAD') {\n\t\tdie(\"How the hell I am supposed to resolve without a head?\");\n\t}\n\n\tmy $fh;\n\tmy $head = head();\n\tmy $merge_tree = undef;\n\tmy $pwd        = getcwd;\n\tchomp (my ($remote_head, $url) = _read_file('.git/RESOLVE'));\n\n\tprint \"remote_head => $remote_head\\nurl => $url\\n\";\n\n\tmy %unmerged = retrieve_unmerged();\n\n\tforeach my $file (keys(%unmerged)) {\n\t\tprocess_unmerged_file(@{$unmerged{$file}});\n\t}\n\n\tif (! defined($merge_tree = write_tree())) {\n\t\tdie(\"Still unresolved conflicts. Run git resolve again.\");\n\t}\n\n\topen($fh, \"+>\", undef);\n\tprint $fh \"Manual Merge $url => ${hostname}:${pwd}\\n\";\n\tseek($fh, 0, 0);\n\tchomp($head = gitcmdinout($fh, 'git-commit-tree', $merge_tree, '-p', $head, '-p', $remote_head));\n\tclose $fh;\n\n\thead($head);\n\tunlink('.git/RESOLVE');\n\tcheckout('-f');\n\n\tprint STDERR \"All issues resolved manual: Commited as ${head}.\\n\";\n        print STDERR \"Have a pleasant day.\\n\";\n\treturn;\n}\n\nsub\nmerge\n{\n\n\tmy $message      = undef;\n\tmy $head         = undef;\n\tmy $last_tree    = undef;\n\tmy $fh;\n\tmy @heads        = ();\n\n\tforeach my $r (@_) {\n\t\tmy $current_head = @{$r}[0];\n\t\tmy $current_url  = @{$r}[1];\n\n\t\tprint \"current_head => $current_head\\ncurrent_url => $current_url\\n\";\n\n\t\tpush(@heads, '-p', ${current_head});\n\n\t\tif (! defined($last_tree)) {\n\t\t\t$message    = \"=> ${current_url}\\n\";\n\t\t\t$head       = $current_head;\n\t\t\t$last_tree  = $current_head;\n\t\t\t\n\n\t\t\tif (@_ == 1) {\n\t\t\t\tprint \"Setting HEAD\\n\";\n\t\t\t\thead($head);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tprint \"Next round\\n\";\n\n\t\t\tnext;\n\t\t}\n\n\t\tmy $merge_base = gitcmdout('git-merge-base', $head, $current_head)\n\t\t\t\t || die (\"no merge-base\");\n\t\tchomp($merge_base);\n\n\t\tprint \"head => $head\\nremote => $current_head\\nbase => $merge_base\\n\";\n\t\n\t\tif ($merge_base eq $current_head) {\n\t\t\t$message .= \"<= ${current_url} (nothing to merge)\\n\";\n\n\t\t\tif (@_ == 2) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tnext;\n\t\t}\n\n\t\tif ($merge_base eq $head) {\n\t\t\t$message   .= \"<= ${current_url} (bringing head ahead)\\n\";\n\t\t\t$head       = ${current_head};\n\t\t\t$last_tree  = ${current_head};\n\n\t\t\tif (@_ == 2) {\n\t\t\t\thead($head);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tnext;\n\t\t}\n\n\t\tgitcmd('git-read-tree', '-m', $merge_base, $last_tree, $current_head);\n\t\tif (! defined($last_tree = write_tree())) {\n\t\t\tsystem('git-merge-cache', '-o', 'git-merge-one-file-script', '-a');\n\t\t\tif (! defined($last_tree = write_tree())) {\n\t\t\t\t# FIXME: Make manual intervention possible\n\t\t\t\t# --tg 23:11 05-05-29\n\t\t\t\tdie(\"Couldn't merge automatically: Call 'git resolve'\");\n\t\t\t}\n\t\t\t$message .= \"<= ${current_url} (threeway merge)\\n\";\n\n\t\t} else {\n\t\t\t$message .= \"<= ${current_url} (automatic merge)\\n\";\n\t\t}\n\t}\n\n\topen($fh, \"+>\", undef);\n\tprint $fh $message;\n\tseek($fh, 0, 0);\n\t$head = gitcmdinout($fh, 'git-commit-tree', $last_tree, @heads);\n\tchomp($head);\n\tclose $fh;\n\n\thead($head);\n\treturn;\n}\n\nsub\npatch\n{\n\tmy @files = ();\n\tmy ($fh, $patch);\n\tmy $file = shift || die(\"Need at least on argument.\\n\");\n\tmy $head  = undef;\n\tmy $dir   = undef;\n\n\tif (head()\n\t&& (    dirty_files()\n            || `git-diff-cache -r --cached HEAD`)) {\n\t\tprint STDERR \"Get rid of dirty files / uncommited deltas first.\\n\";\n\t\texit 1;\n\t}\n\n\t($fh, $patch) = tempfile(CLEANUP => 1);\n\n\t`filterdiff -x '*/.*' $file > $patch`;\n\n\t@files = `lsdiff --strip 1 $patch`;\n\n\tchomp(@files);\n\n\t$dir = tempdir(CLEANUP => 1);\n\t$ENV{GIT_INDEX_FILE} = \"$dir/.index\";\n\n\tif ($head = head()) {\n\t\tgitcmd('git-read-tree', $head);\n\t\tforeach my $file (@files) {\n\t\t\tgitcmd('git-checkout-cache', '-q', \"--prefix=$dir/\", $file);\n\t\t}\n\t}\n\n\tmy $pwd = getcwd;\n\n\tsymlink(\"$pwd/.git\", \"$dir/.git\");\n\n\tchdir($dir);\n\n\t# FIXME call in batch modus and check return value --tg 08:30 05-05-21\n\tsystem(\"${PATCH} -p1 < $patch\");\n\n\tforeach my $file (@files) {\n\t\tgitcmd('git-update-cache', '--add', '--remove', $file);\n\t}\n\n\tcommit();\n\n\tchdir($pwd);\n\tdelete($ENV{GIT_INDEX_FILE});\n\tcheckout('-f');\n}\n\nsub\ncheckout\n{\n\tmy $head = head();\n\tgitcmd('git-read-tree', '-m', $head);\n\n\t# FIXME if this fails call it without -m --tg 20:25 05-05-09\n\n\tif (defined($_[0]) && $_[0] eq '-f') {\n\t\tgitcmd('git-checkout-cache', '-u', '-f', '-a');\n\n\t} else {\n\t\tgitcmd('git-checkout-cache', '-u', '-q', '-a');\n\t}\n\n#\tchanged();\n#\n#\tforeach my $file (gitcmdout('git-ls-files')) {\n#\t\tchomp($file);\n#\t\tmy $time = (sort {$b <=> $a} @{$touched{$file}})[0];\n#\t\tutime $time, $time, $file;\n#\t}\n}\n\nsub\ngenerate_url\n{\n\tmy $url = shift;\n\n\tif (! defined($url)) {\n\t\tif ( -f '.git/PARENT' || -l '.git/PARENT') {\n\t\t\tchomp ($url = _read_file('.git/PARENT'));\n\t\t} else {\n\t\t\tdie(\"$0: No URL specified and no parent found: Where to pull from?\\n\");\n\t\t}\n\t} else {\n\t\t$url =~ s#\\/$##;\n\n\t\tif (-d $url &&\n\t\t    ! ($url =~ /\\.git$/)) {\n\t\t\t\t$url .= \"/.git\";\n\t\t}\n\n\t\tif (-d $url &&\n\t\t    ! ($url =~ /^\\//)) {\n\t\t\t# FIXME: use Cwd; my $pwd = getcwd; --tg 21:32 05-05-03\n\t\t\tchomp(my $pwd = `pwd`);\n\t\t\t$url = \"${pwd}/${url}\";\n\t\t}\n\t}\n\n\treturn $url;\n}\n\nsub\npull\n{\n\tmy @references = ();\n\tmy %options;\n\tlocal @ARGV = @_;\n\tGetOptions(\\%options, 'o', 'l');\n\t@_ = @ARGV;\n\n\tif (head()\n\t&& (! defined($options{'o'}))\n\t&& (    dirty_files()\n\t    || `git-diff-cache -r --cached HEAD`)) {\n\t\tprint STDERR \"Get rid of dirty files / uncommited deltas first.\\n\";\n\t\texit 1;\n\t}\n\n\t# FIXME SANITY CHECK. It is only possible to pull in 15 trees\n\t# --tg 17:58 05-05-28\n\n\tif (! defined($_[0])) {\n\t\tunshift(@_, generate_url(shift));\n\t}\n\n\tif ( -f '.git/HEAD' || -l '.git/HEAD') {\n\t\tpush(@references, [head(), \"${hostname}:\" . getcwd()]);\n\t}\n\n\twhile(defined (my $url = shift)) {\n\t\t$url = generate_url($url);\n\t\tmy $remote_head = undef;\n\n\t\tif (defined($options{'l'}) && -d $url) {\n\t\t\t$ENV{'GIT_ALTERNATE_OBJECT_DIRECTORIES'} = \"${url}/objects\";\n\n\t\t} else {\n\t\t\tgitcmd('rsync', '-qa', '--ignore-existing', \"$url/objects/.\", \".git/objects/.\");\n\t\t}\n\t\tgitcmd('rsync', '-qL', \"$url/HEAD\", '.git/REMOTE_HEAD');\n\t\tchomp($remote_head = _read_file('.git/REMOTE_HEAD'));\n\t\tpush(@references, [$remote_head, $url]);\n\t}\n\n\tif (! defined($options{'o'})) {\n\t\tmerge(@references);\n\t\tcheckout('-f');\n\t}\n}\n\nsub\nchanges\n{\n\tmy %options;\n\tlocal @ARGV = @_;\n\tGetOptions(\\%options, \"L\", \"R\", \"d\", \"m\", \"n\", \"t=s\", \"S=s\", 'root');\n\t@_ = @ARGV;\n\n\tmy $git_diff_tree_options = '-s';\n\tif (defined ($options{'d'})) {\n\t\t$git_diff_tree_options = '-p';\n\t}\n\tif (defined ($options{'m'})) {\n\t\t$git_diff_tree_options .= ' -m';\n\t}\n\tif (defined ($options{'S'})) {\n\t\t$git_diff_tree_options .= \" -S'$options{'S'}'\";\n\t}\n\tif (defined ($options{'root'})) {\n\t\t$git_diff_tree_options .= \" --root\";\n\t}\n\n\tif (defined ($options{'L'})) {\n\t\tif (! defined ($options{'n'})) {\n\t\t\tpull('-o', '-l', shift);\n\t\t}\n\t\tsystem(\"git-rev-tree HEAD '^REMOTE_HEAD' | sed -e 's/^[0-9]* //' | git-diff-tree --stdin -v $git_diff_tree_options \" . join(' ', @ARGV));\n\n\t} elsif (defined ($options{'R'})) {\n\t\tif (! defined ($options{'n'})) {\n\t\t\tpull('-o', '-l', shift);\n\t\t}\n\t\tsystem(\"git-rev-tree REMOTE_HEAD '^HEAD' | sed -e 's/^[0-9]* //' | git-diff-tree --stdin -v $git_diff_tree_options \" . join(' ', @ARGV));\n\n\t} elsif (defined ($options{'t'})) {\n\t\tsystem(\"git-rev-tree HEAD '^$options{'t'}' | sed -e 's/^[0-9]* //' | git-diff-tree --stdin -v $git_diff_tree_options \" . join (' ', @ARGV));\n\t\n\t} else {\n\t\tsystem(\"git-rev-list HEAD | git-diff-tree --stdin -v $git_diff_tree_options \" . join(' ', @ARGV));\n\t}\n}\n\nsub\n_push\n{\n\tmy $url = generate_url(shift);\n\n\tgitcmd('rsync', '-qL', \"$url/HEAD\", '.git/REMOTE_HEAD');\n\tchomp (my $remote_head = _read_file('.git/REMOTE_HEAD'));\n\tmy $head        = head() || die(\"No local HEAD\\n\");\n\tif ($head eq $remote_head) {\n\t\tprint STDERR \"Nothing to push.\\n\";\n\t\treturn;\n\t}\n\tprint \"head => $head\\nremote => $remote_head\\n\";\n\tmy @revlist     = gitcmdout('git-rev-list', $head);\n\tif (! grep(/^${remote_head}$/, @revlist)) {\n\t\tprint STDERR \"Remote is ahead or unrelated: Need to pull first?\\n\";\n\t\texit 1;\n\t}\n\tgitcmd('rsync', '-qa', '--ignore-existing', \".git/objects/.\", \"$url/objects/.\");\n\tgitcmd('rsync', '-q', '.git/HEAD', \"$url/HEAD\");\n}\n\nsub\nclone\n{\n\tmy %options;\n\n\tGetOptions(\\%options, \"l\");\n\n\tmy $url     = shift(@ARGV);\n\tmy $project = shift(@ARGV);\n\n\tif (! defined($url) || ! defined($project)) {\n\t\tdie(\"Usage: $0 clone <url> <project>\\n\");\n\t}\n\n\t$url = generate_url($url);\n\n\tif (defined($options{l})) {\n\t\tif (-d $url) {\n\t\t\t-d \".git\"              && die(\"$0 clone $project: Don\\'t create repository in a repository.\");\n\t\t\tmkdir($project, 0755)  || die(\"$0 clone $project: mkdir: $!\");\n\t\t\tchdir($project)        || die(\"$0 clone $project: chdir: $!\");\n\t\t\tmkdir('.git', 0755)    || die(\"$0 clone $project: mkdir: $!\");\n\t\t\tsymlink(\"$url/objects\", '.git/objects') || die(\"Can\\'t symlink object database\");\n\n\t\t} else {\n\t\t\tdie(\"Can't symlink from network repositories\\n\");\n\t\t}\n\t} else {\n\t\tsetup($project);\n\t}\n\tparent($url);\n\tpull();\n}\n\nsub\nparent\n{\n\tmy $parent = $_[0];\n\tif (defined($parent)) {\n\t\tif ($parent eq \"-c\") {\n\t\t\tif ( -f \".git/PARENT\" || -l \".git/PARENT\") {\n\t\t\t\tunlink(\".git/PARENT\") || die(\"can't delete .git/PARENT: $!\");\n\t\t\t}\n\t\t\tprint STDERR \"$0 parent: Parent removed\\n\";\n\n\t\t} else {\n\t\t\t$parent = generate_url($parent);\n\n\t\t\t_write_file('.git/PARENT', \"$parent\\n\");\n\t\t}\n\n\t} else {\n\t\tif ( -f \".git/PARENT\" || -l \".git/PARENT\") {\n\t\t\t\n\t\t\tchomp($parent = _read_file('.git/PARENT'));\n\t\t\tprint \"${parent}\\n\";\n\n\t\t} else {\n\t\t\tprint STDERR \"$0 parent: No parent specified\\n\";\n\t\t}\n\t}\n}\n\nsub\ndiff\n{\n\tmy %options;\n\tlocal @ARGV = @_;\n\tGetOptions(\\%options, 'r=s', 'f', 'c', 'v', \"S=s\", 'root');\n\t@_ = @ARGV;\n\n\tmy $dir = tempdir(CLEANUP => 1);\n\n\trefresh();\n\n\tmy $git_diff_tree_options = '';\n\n\tif (defined ($options{'S'})) {\n\t\t$git_diff_tree_options .= \" -S'$options{'S'}'\";\n\t}\n\n\tif (defined ($options{'root'})) {\n\t\t$git_diff_tree_options .= \" --root\";\n\t}\n\n\tif (defined($options{'r'})) {\n\t\tif($options{'r'} =~ /:/) {\n\t\t\tmy ($first, $second) = split(/:/, $options{'r'});\n\t\t\tsystem(\"git-diff-tree -p -r $first $second $git_diff_tree_options \" . join(' ', @_));\n\n\t\t} else {\n\t\t\tif (defined ($options{'v'})) {\n\t\t\t\t$git_diff_tree_options .= ' -v';\n\t\t\t}\n\t\t\tsystem(\"git-diff-tree -p -r $options{'r'} $git_diff_tree_options \" . join(' ', @_));\n\t\t}\n\n\t} elsif (defined($options{\"f\"})) {\n\t\tsystem(\"git-diff-files -r -z $git_diff_tree_options \" . join(' ', @_) . \" | git-diff-helper -z\");\n\n\t} elsif (defined($options{\"c\"})) {\n\t\tsystem(\"git-diff-cache --cached -r -z HEAD $git_diff_tree_options \" . join(' ', @_) . \" | git-diff-helper -z\");\n\n\t} else {\n\t\tsystem(\"git-diff-cache -r -z HEAD $git_diff_tree_options \" . join(' ', @_) . \" | git-diff-helper -z\");\n\t}\n}\n\nsub\ntreediff\n{\n\tmy %options;\n\tlocal @ARGV = @_;\n\tGetopt::Long::Configure(\"pass_through\");\n\tGetOptions(\\%options, 'p=s');\n\tGetopt::Long::Configure(\"no_pass_through\");\n\t@_ = @ARGV;\n\tpull('-o', '-l', $options{'p'});\n\tdiff('-r', 'REMOTE_HEAD:HEAD', @_);\n}\n\nsub\ninit_db\n{\n\tgitcmd( 'init-db', @_ );\n}\n\nsub\nsetup\n{\n\tmy $project = shift    || die (\"usage: $0 setup project\");\n\t-d \".git\"              && die (\"$0 setup $project: Don\\'t create repository in a repository.\");\n\tmkdir($project, 0755)  || die (\"$0 setup $project: mkdir: $!\");\n\tchdir($project)        || die (\"$0 setup $project: chdir: $!\");\n\tgitcmd('git-init-db');\n}\n\nsub\nrevert\n{\n\t# TODO handle revert of add/remove --tg 02:32 05-05-06\n\tmy @in    = ();\n\tmy $fh;\n\n\tif (! defined($_[0])) {\n\t\treturn;\n\t}\n\n\tif ($_[0] eq \"-\") {\n\t\t@in = <STDIN>;\n\n\t} else {\n\t\t@in = @_;\n\t}\n\n\tmy $head = head();\n\t($fh, $ENV{GIT_INDEX_FILE}) = tempfile(CLEANUP => 1);\n\tgitcmd('git-read-tree', $head);\n\n\tforeach (@in) {\n\t\tchomp($_);\n\t\t$_ =~ s#^\\.\\/##;\n\n\t\tif (/^\\./) {\n\t\t\tprint STDERR \"Warning: Skipping $_\\n\";\n\t\t\tnext;\n\t\t}\n\n\t\tif (-d $_) {\n\t\t\tnext;\n\t\t}\n\n\t\tgitcmd('git-checkout-cache', '-f', $_);\n\t}\n\n\tdelete($ENV{GIT_INDEX_FILE});\n\n\tforeach (@in) {\n\t\tchomp($_);\n\t\t$_ =~ s#^\\.\\/##;\n\n\t\tif (/^\\./) {\n\t\t\tnext;\n\t\t}\n\n\t\tif (! -f $_) {\n\t\t\tnext;\n\t\t}\n\n\t\tgitcmd('git-update-cache',  $_);\n\t}\n}\n\nsub\nadd\n{\n\tmy @in    = ();\n\n\tif (defined($_[0]) && $_[0] eq \"-\") {\n\t\t@in = <STDIN>;\n\n\t} else {\n\t\t@in = @_;\n\t}\n\n\tforeach (@in) {\n\t\tchomp($_);\n\t\t$_ =~ s#^\\.\\/##;\n\n\t\tif (/^\\./) {\n\t\t\tprint STDERR \"Warning: Skipping $_\\n\";\n\t\t\tnext;\n\t\t}\n\n\t\tif (-d $_) {\n\t\t\tnext;\n\t\t}\n\n\t\tif (! -f $_) {\n\t\t\tprint STDERR \"Warning: Skipping nonexisting file: $_\\n\";\n\t\t\tnext;\n\t\t}\n\n\t\tgitcmd( 'git-update-cache', '--add', '--', $_ );\n\t}\n\n}\n\nsub\nci\n{\n\tmy @in    = ();\n\n\tif (defined($_[0]) && $_[0] eq \"-\") {\n\t\t@in = <STDIN>;\n\n\t} else {\n\t\t@in = @_;\n\t}\n\n\tforeach (@in) {\n\t\tchomp($_);\n\t\t$_ =~ s#^\\.\\/##;\n\n\t\tif (/^\\./) {\n\t\t\tprint STDERR \"Warning: Skipping $_\\n\";\n\t\t\tnext;\n\t\t}\n\n\t\tif (-d $_) {\n\t\t\tnext;\n\t\t}\n\n\t\tif (! -f $_) {\n\t\t\tprint STDERR \"Warning: Skipping nonexisting file: $_\\n\";\n\t\t\tnext;\n\t\t}\n\n\t\tgitcmd( 'git-update-cache', '--', $_ );\n\t}\n\n}\n\nsub\nrm\n{\n\tmy @in    = ();\n\n\tif (defined($_[0]) && $_[0] eq \"-\") {\n\t\t@in = <STDIN>;\n\n\t} else {\n\t\t@in = @_;\n\t}\n\n\tforeach (@in) {\n\t\tchomp($_);\n\t\t$_ =~ s#^\\.\\/##;\n\n\t\tif (/^\\./) {\n\t\t\tprint STDERR \"Warning: Skipping $_\\n\";\n\t\t\tnext;\n\t\t}\n\n\t\tif (-d $_) {\n\t\t\tnext;\n\t\t}\n\n\t\tif (-f $_) {\n\t\t\tunlink($_) || die (\"$0 rm $_: $!\");\n\t\t}\n\n\t\tgitcmd( 'git-update-cache', '--remove', '--' , $_ );\n\t}\n\n}\n\nsub\nhead\n{\n\tmy $head = $_[0];\n\tif (defined($head)) {\n\t\tif ($head eq \"\") {\n\t\t\tif ( -f \".git/HEAD\" || -l \".git/HEAD\") {\n\t\t\t\tunlink(\".git/HEAD\") || die \"failed to delete .git/HEAD: $!\\n\";\n\t\t\t}\n\t\t} else {\n\t\t\tchomp($head);\n\t\t\t_write_file( '.git/HEAD', \"$head\\n\" );\n\t\t}\n\n\t} else {\n\t\tif (-f '.git/HEAD') {\n\t\t\tchomp( $head = _read_file( '.git/HEAD' ) );\n\t\t} else {\n\t\t\t$head = undef;\n\t\t}\n\t}\n\n\treturn $head;\n}\n\nsub\nprint_commit\n{\n\tmy $commit = shift || die(\"need commit\");\n\n\tprint \"commit $commit\\n\";\n\tforeach (gitcmdout('git-cat-file', 'commit', $commit)) {\n\t\tif (/^(author|committer)(.+>\\s)(\\d+)\\s([+-]?\\d{4})$/) {\n\t\t\t# local $ENV{TZ} = $4;\n\t\t\tprint \"$1$2\" . localtime($3) . \"\\n\";\n\t\t} else {\n\t\t\tprint \"$_\\n\";\n\t\t}\n\t}\n\tprint \"\\n\";\n}\n\nsub\ncommit\n{\n\tmy $head = head();\n\tchomp (my $tree = gitcmdout('git-write-tree'));\n\n\tif (dirty_files()) {\n\t\tdie \"$0 commit: Get rid of dirty files first.\\n\";\n\t}\n\n\tif (defined($head)) {\n\t\tmy %hash = commit_hash($head);\n\n\t\tif ($hash{tree} eq $tree) {\n\t\t\tdie \"$0 commit: The commit wouldn't commit anything different.\\n\";\n\t\t}\n\n\t\t$head = gitcmdout('git-commit-tree', $tree, '-p', $head);\n\t} else {\n\t\t$head = gitcmdout('git-commit-tree', $tree);\n\t}\n\n\thead($head);\n}\n\nsub\nlog\n{\n\tmy $head = head() || return ;\n\n\tmy $pid;\n\tif ( ! -p STDIN && ! -p STDOUT ) {\n\t\tmy ( $r, $w );\n\t\tpipe( $r, $w ) || die \"Failed to pipe: $!\";\n\t\tdefined( $pid = fork ) || die \"Failed to fork: $!\";\n\t\tif ( $pid ) { # Parent\n\t\t\t$SIG{INT} = $SIG{TERM} = $SIG{HUP} = sub {\n\t\t\t\tkill 15, $pid;\n\t\t\t\texit 1;\n\t\t\t};\n\t\t\tclose $r;\n\t\t\tclose STDOUT;\n\t\t\topen STDOUT, '>&', $w || die \"Failed to redirect STDOUT: $!\";\n\t\t} else { # pager child\n\t\t\tclose $w;\n\t\t\tclose STDIN;\n\t\t\topen STDIN, '<&', $r || die \"Failed to redirect STDIN: $!\";\n\t\t\tif ( $ENV{PAGER} ) {\n\t\t\t\texec( $ENV{PAGER} );\n\t\t\t} else {\n\t\t\t\texec( 'less', '-r', '-' );\n\t\t\t}\n\t\t}\n\t}\n\n\tforeach (gitcmdout('git-rev-list', $head)) {\n\t\tprint_commit($_);\n\t}\n\n\tif ( $pid ) {\n\t\tclose STDOUT;\n\t\twaitpid($pid, 0);\n\t}\n}\n\nsub\ncommit_hash\n{\n\tmy %hash    = ();\n\tmy $id      = shift || die (\"$0: commit_hash: expect one argument\");\n\tmy $comment = 0;\n\n \tmy @lines = gitcmdout('git-cat-file', 'commit', $id);\n\n\tforeach (@lines) {\n\t\tchomp;\n\n\t\tif ($comment) {\n\t\t\tpush(@{$hash{comment}}, $_);\n\t\t\tnext;\n\t\t}\n\n\t\tif (/^tree\\s(\\w{40})$/) {\n\t\t\t$hash{tree} = $1;\n\t\t\tnext;\n\t\t}\n\n\t\tif (/^parent\\s(\\w{40})$/) {\n\t\t\tpush(@{$hash{parent}}, $1);\n\t\t\tnext;\n\t\t}\n\n\t\tif (/^author\\s(.*)\\s<(.*)>\\s(.*)$/) {\n\t\t\t$hash{author_name}  = $1;\n\t\t\t$hash{author_eMail} = $2;\n\t\t\t$hash{author_date}  = $3;\n\t\t\tnext;\n\t\t}\n\n\t\tif (/^committer\\s(.*)\\s<(.*)>\\s(.*)$/) {\n\t\t\t$hash{committer_name}  = $1;\n\t\t\t$hash{committer_eMail} = $2;\n\t\t\t$hash{committer_date}  = $3;\n\t\t\tnext;\n\t\t}\n\n\t\tif (/^$/) {\n\t\t\t$comment = 1;\n\t\t}\n\t}\n\n\treturn(%hash);\n}\n\nsub\nfirst_parent\n{\n\tmy $this = shift || die (\"$0: parent called without object\");\n\tmy %hash = commit_hash($this);\n\n\tif (! defined(@{$hash{parent}}[0])) {\n\t\treturn \"\";\n\t}\n\n\treturn(@{$hash{parent}}[0]);\n}\n\nsub\nundo\n{\n\tmy $head = head();\n\n\tif (! defined($head)) {\n\t\treturn;\n\t}\n\n\tif (    dirty_files()\n            || `git-diff-cache -r --cached HEAD`) {\n\t\tprint STDERR \"Get rid of dirty files / uncommited deltas first.\\n\";\n\t\texit 1;\n\t}\n\n\tmy $newhead = first_parent($head);\n\n\tprint \"oldhead $head\\nnewhead $newhead\\n\";\n\n\thead($newhead);\n\tcheckout('-f');\n}\n\nsub\nobject_type\n{\n\tmy $id = shift;\n\tdefined $id && $id =~ /^[A-Za-z0-9]{40}$/ ||\n\t\tdie \"Invalid sha1 id '$id'\";\n\tmy $type = gitcmdout('git-cat-file', '-t', $id );\n\tchomp $type;\n\treturn $type;\n}\n\nsub\ntree_id\n{\n\tmy $id = shift;\n\t( $id ) = grep { defined }\n\t\tmap { /^tree ([A-Za-z0-9]{40})$/ ? $1 : undef }\n\t\t\tgitcmdout( 'git-cat-file', 'commit', $id ) or\n\t\tdie \"Unable to find tree id for commit id $id\";\n\tobject_type( $id ) eq 'tree' ||\n\t\tdie \"tree id from commit is not a tree object!\";\n\treturn $id;\n}\n\nsub\nparent_id\n{\n\tmy $id = shift;\n\tmy ( $pid ) = grep { defined }\n\t\tmap { /^parent ([A-Za-z0-9]{40})$/ ? $1 : undef }\n\t\t\tgitcmdout( 'git-cat-file', 'commit', $id ) or\n\t\tdie \"Unable to determine parent commit of commit $id\";\n\treturn $pid;\n}\n\n# int\n# main(int argc, char **argv)\n# {\n\nif (defined($ARGV[0]) && defined($commands{$ARGV[0]})) {\n\tmy $string = shift;\n\tif ( ! -d \".git\"\n\t&&   ! ($string eq \"setup\"\n             || $string eq \"init-db\"\n             || $string eq \"clone\")) {\n\t\tdie(\"$0 $string: Not in a git BASE directory\");\n\t}\n\t$commands{$string}->(@ARGV);\n\n} else {\n\tif (defined($ARGV[0])) {\n\t\tprint STDERR \"No such command: $ARGV[0]\\n\\n\";\n\t}\t\n\tusage();\n}\n\n# }\n\n{\n\tmy %gitcmd;\n\n\tsub\n\tgitcmdpath\n\t{\n\t\tmy $cmd = shift;\n\t\tunless ( defined $gitcmd{$cmd} ) {\n\t\t\tlocal $/ = \"\\n\";\n\t\t\tchomp( $gitcmd{$cmd} = `which $cmd` );\n\t\t\treturn undef if $gitcmd{$cmd} eq '';\n\t\t}\n\t\treturn $gitcmd{$cmd};\n\t}\n\n\tsub\n\tgitcmd\n\t{\n\t\tmy $cmd = shift;\n\t\tgitcmdpath( $cmd ) || die \"command '$cmd' not found\";\n\t\tmy $r = system( $gitcmd{$cmd}, @_ );\n\t\tdie \"$cmd failed: \" . _gitcmderrmsg( $cmd )\n\t\t\tif $r != 0;\n\t\treturn 1;\n\t}\n\n\tsub\n\tgitcmdinout\n\t{\n\t\tmy $infh = shift;\n\t\tmy $cmd  = shift;\n\t\tgitcmdpath( $cmd ) || die \"command '$cmd' not found\";\n\t\tmy ( $r, $w );\n\t\tpipe( $r, $w ) || die \"Failed to pipe: $!\";\n\t\tmy $pid = fork();\n\t\tdie \"Failed to fork: $!\" unless defined $pid;\n\t\tif ( $pid ) {\n\t\t\tclose $w;\n\t\t\tlocal $/;\n\t\t\tlocal $_ = <$r>;\n\t\t\tclose $r;\n\t\t\tmy $kid = waitpid( $pid, 0 );\n\t\t\tdie \"Hmm, auto reaping in place?\" if $kid == -1;\n\t\t\tdie \"$cmd failed: \" . _gitcmderrmsg( $cmd )\n\t\t\t\tif $? & 127 || $? >> 8 != 0;\n\t\t\tif ( wantarray ) {\n\t\t\t\treturn split( \"\\n\", $_ );\n\t\t\t} else {\n\t\t\t\treturn $_;\n\t\t\t}\n\t\t} else {\n\t\t\tclose $r;\n\t\t\tclose STDOUT;\n\t\t\tclose STDIN;\n\t\t\topen STDIN, '<&', $infh || die \"Failed to rediret STDIN\";\n\t\t\topen STDOUT, '>&', $w || die \"Failed to redirect STDOUT\";\n\t\t\texec( $gitcmd{$cmd}, @_ );\n\t\t}\n\t}\n\n\tsub\n\tgitcmdout\n\t{\n\t\tmy $cmd = shift;\n\t\tgitcmdpath( $cmd ) || die \"command '$cmd' not found\";\n\t\tmy ( $r, $w );\n\t\tpipe( $r, $w ) || die \"Failed to pipe: $!\";\n\t\tmy $pid = fork();\n\t\tdie \"Failed to fork: $!\" unless defined $pid;\n\t\tif ( $pid ) {\n\t\t\tclose $w;\n\t\t\tlocal $/;\n\t\t\tmy $ret = <$r>;\n\t\t\tclose $r;\n\n\t\t\tmy $kid = waitpid( $pid, 0 );\n\t\t\tdie \"Hmm, auto reaping in place?\" if $kid == -1;\n\t\t\tdie \"$cmd failed: \" . _gitcmderrmsg( $cmd )\n\t\t\t\tif $? & 127 || $? >> 8 != 0;\n\n\t\t\tif (wantarray) {\n\t\t\t\treturn split(\"\\n\", $ret);\n\t\t\t} else {\n\t\t\t\treturn $ret;\n\t\t\t}\n\t\t} else {\n\t\t\tclose $r;\n\t\t\tclose STDOUT;\n\t\t\topen STDOUT, '>&', $w || die \"Failed to redirect STDOUT\";\n\t\t\texec( $gitcmd{$cmd}, @_ );\n\t\t}\n\t}\n\n\tsub\n\t_gitcmderrmsg\n\t{\n\t\tmy $cmd = shift;\n\t\tmy $e;\n\t\tif ( $? == -1 ) {\n\t\t\t$e = \"failed to execute $gitcmd{$cmd}: $!\";\n\t\t} elsif ( $? & 127 ) {\n\t\t\t$e = sprintf( 'child die from signal %d', ( $? & 127 ) );\n\t\t\t$e .= ' (with coredump)' if $? & 128;\n\t\t} else {\n\t\t\t$e = sprintf( 'child exit value: %d', $? >> 8 );\n\t\t}\n\t\treturn $e;\n\t}\n}\n\nsub\n_recur_mkdir\n{\n\tmy $dir = shift;\n\tmy @dir = split( /\\//, $dir );\n\tmy $path = '';\n\twhile ( @dir ) {\n\t\t$path .= '/' . shift @dir;\n\t\t( -d $path ) || mkdir( $path ) ||\n\t\t\tdie \"Failed to mkdir $path: $!\";\n\t}\n}\n\nsub\n_read_file\n{\n\tmy $file = shift;\n\tmy $fh;\n\topen $fh, '<', $file || die \"failed to read $file: $!\\n\";\n\tif ( wantarray ) {\n\t\tmy @r = <$fh>;\n\t\tclose $fh || die \"failed to close $file: $!\\n\";\n\t\treturn @r;\n\t} else {\n\t\tlocal $/;\n\t\tmy $r = <$fh>;\n\t\tclose $fh || die \"failed to close $file: $!\\n\";\n\t\treturn $r;\n\t}\n}\n\nsub\n_write_file\n{\n\tmy $file = shift;\n\tmy $fh;\n\topen $fh, '>', $file || die \"failed to write $file: $!\\n\";\n\tif ( @_ ) {\n\t\tprint $fh join( $/, @_ );\n\t}\n\tclose $fh            || die \"failed to close $file: $!\\n\";\n\treturn 1;\n}\n\n# vim:set noexpandtab:\n"},{"id":"4206","messageId":"20050529231053.GD12290@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"20050529230240.GB12290@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-29T23:10:53Z","receivedAt":"2005-05-29T23:10:53Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\none obvious fix:\n\n> \t\t\t$message .= \"<= ${current_url} (nothing to merge)\\n\";\n> \t\t\t$message   .= \"<= ${current_url} (bringing head ahead)\\n\";\n\nthe parents of such 'merges' should *not* be referenced in the commit\nobject E.g. this is wrong: 'git-commit-tree -p nothing_to_merge -p\njust_bringing_head_ahead'. Leaving the message in the log section of the\ncommit object could be useful, maybe. Thoughts?\n\nAnd I should doublecheck if more than 16 parents show up in\ngit-commit-tree when doing the commits and throw an error.\n\n\tThomas\n"},{"id":"4208","messageId":"20050529231621.GE12290@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"20050529231053.GD12290@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-29T23:16:21Z","receivedAt":"2005-05-29T23:16:21Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\n\n> > \t\t\t$message .= \"<= ${current_url} (nothing to merge)\\n\";\n> > \t\t\t$message   .= \"<= ${current_url} (bringing head ahead)\\n\";\n\n> the parents of such 'merges' should *not* be referenced in the commit\n> object E.g. this is wrong: 'git-commit-tree -p nothing_to_merge -p\n> just_bringing_head_ahead'. Leaving the message in the log section of the\n> commit object could be useful, maybe. Thoughts?\n\nWrong, wrong, wrong. If 'head ahead' condition shows up, I have to kick\nthe previous head out (not the current), don't I?\n\n\tThomas\n"},{"id":"4213","messageId":"20050529234606.GF12290@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"20050529231621.GE12290@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-29T23:46:06Z","receivedAt":"2005-05-29T23:46:06Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\nyet another bug. If there is only one head left after the for loop this\nhead is *set* not *commitet* as new HEAD because it comes from a 'pull\ninto empty tree' or from a 'just head ahead'-condition.\n\n\tThomas\n"},{"id":"4218","messageId":"20050529235630.GG12290@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"20050529234606.GF12290@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-29T23:56:31Z","receivedAt":"2005-05-29T23:56:31Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\nhere is the actual version of my merge function. However I have a\nquestion left over: When I do an automatic merge or a threeway merge\nshould I set the head for the next round to the remote one or just let\nit be the current one (this is the current behaviour) or maybe make it\nconfigurable? Note: At the moment the *local* head for the merge-base is only\nmodified during the set of the first head *or* on a head forward condition. I\nhave no clue. I am going to write the 'more on merging chapter' after I have\nfigured this out. ;-)\n\nsub\nmerge\n{\n\n\tmy $message      = undef;\n\tmy $head         = undef;\n\tmy $last_tree    = undef;\n\tmy $fh;\n\tmy @heads        = ();\n\n\tforeach my $r (@_) {\n\t\tmy $current_head = @{$r}[0];\n\t\tmy $current_url  = @{$r}[1];\n\n\t\tprint \"current_head => $current_head\\ncurrent_url => $current_url\\n\";\n\n\t\tpush(@heads, '-p', ${current_head});\n\n\t\tif (! defined($last_tree)) {\n\t\t\t$message    = \"=> ${current_url}\\n\";\n\t\t\t$head       = $current_head;\n\t\t\t$last_tree  = $current_head;\n\t\t\t\n\t\t\tif (@_ == 1) {\n\t\t\t\thead($head);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tnext;\n\t\t}\n\n\t\tmy $merge_base = gitcmdout('git-merge-base', $head, $current_head)\n\t\t\t\t || die (\"no merge-base\");\n\t\tchomp($merge_base);\n\n\t\tprint \"head => $head\\nremote => $current_head\\nbase => $merge_base\\n\";\n\t\n\t\tif ($merge_base eq $current_head) {\n\t\t\t$message .= \"<= ${current_url} (nothing to merge)\\n\";\n\n\t\t\t$#heads -= 2;\n\n\t\t\tnext;\n\t\t}\n\n\t\tif ($merge_base eq $head) {\n\t\t\t$message   .= \"<= ${current_url} (bringing head ahead)\\n\";\n\t\t\t$head       = ${current_head};\n\t\t\t$last_tree  = ${current_head};\n\n\t\t\t$#heads -= 4;\n\t\t\tpush(@heads, '-p', $current_head);\n\n\t\t\tnext;\n\t\t}\n\n\t\tgitcmd('git-read-tree', '-m', $merge_base, $last_tree, $current_head);\n\t\tif (! defined($last_tree = write_tree())) {\n\t\t\tsystem('git-merge-cache', '-o', 'git-merge-one-file-script', '-a');\n\t\t\tif (! defined($last_tree = write_tree())) {\n\t\t\t\t# FIXME: Make manual intervention possible\n\t\t\t\t# --tg 23:11 05-05-29\n\t\t\t\tdie(\"Couldn't merge automatically: Call 'git resolve'\");\n\t\t\t}\n\t\t\t$message .= \"<= ${current_url} (threeway merge)\\n\";\n\n\t\t} else {\n\t\t\t$message .= \"<= ${current_url} (automatic merge)\\n\";\n\t\t}\n\t}\n\n\tif (@heads == 1) {\n\t\thead(@head[0]);\n\t\treturn;\n\t}\n\n\topen($fh, \"+>\", undef);\n\tprint $fh $message;\n\tseek($fh, 0, 0);\n\t$head = gitcmdinout($fh, 'git-commit-tree', $last_tree, @heads);\n\tchomp($head);\n\tclose $fh;\n\n\thead($head);\n\treturn;\n}\n\n\tThomas\n"},{"id":"4223","messageId":"7vsm05bkps.fsf@assigned-by-dhcp.cox.net","threadId":"737","inReplyTo":"20050529235630.GG12290@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-30T00:50:39Z","receivedAt":"2005-05-30T00:50:39Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Instead of inflicting a Perl script on us, maybe writing a\ntextual specification of what you want it to do would help to\nclarify your thinking and help us understand the problem you are\ntrying to describe a lot better.  I think Linus publicly stated\nhe does not do Perl much.  I am OK with Perl but I'd rather\nanswer questions posed in a more reader-friendly manner, rather\nthan having to guess what the caller is expected to give this\n\"merge\" sub, which you do not document well.\n\nI think I've already asked you something quite similar when you\nposted another part of your script for parsing the new diff-raw\nformat, which I responded with something like: \"Without knowing\nhow this sub is supposed to be called, I think you are stripping\nleading colon from a filename if there is one\".  Anyhow.\n\nAre you trying to implement an Octopus capable N-way merger?\nIf so, the way I would do would be something like this:\n\n - Accept N parameters, which are heads being merged.\n\n - Sanity check that given heads are commits, and N <= 16.\n\n - Initialize a set, HTM (heads to be merged), to contain all of\n   the supplied heads.\n\n - Remove one commit from HTM, call it H0.\n\n - Initialize a variable, BASE, with H0.  This variable\n   determines the base of the merge in the commit topology.\n\n - Initialize a variable, T, with tree associated with H0.  This\n   variable holds the \"current intermediate merge result\" tree.\n\n - While HTM is not empty, loop over the following:\n\n   - Remove one commit out of HTM; call it H1.\n\n   - MB = git-merge-base BASE H1;\n\n   - If MB is either BASE or H1, then you have a fast forward.\n     Take either BASE or H1 that is not MB and update variable\n     BASE with it, and update variable T with the tree\n     associated with it.  Continue with the loop (i.e. Perl\n     \"next\").\n\n   - Run your usual read-tree -m MB T H1 and git-merge-cache; as\n     Linus explained, if this step ends up involving any\n     non-trivial merges, you should not do an Octopus.  So in\n     such a case, if HTM is not empty yet, barf (i.e. Perl\n     \"die\", or at least \"last\").\n\n   - Do not touch your ${GIT-.git}/HEAD in any way at this\n     moment.\n\n   - Update variable T with git-write-tree of the resolved cache\n     contents.\n\n   - Update varaible BASE with MB.\n\n   - Continue with the loop. \n\n - We exited the loop by now.  HTM being empty means that T has\n   the result of N-way merge.  Create a single commit object\n   that has all the commits you have merged as its parents, and\n   register T as its associated tree.  I would imagine recording\n   that commit in ${GIT-.git}/HEAD is what the user usually\n   wants but there may be use cases that it may not be\n   appropriate (I do not do Porcelain so I do not know).\n\n"},{"id":"4224","messageId":"7voeatbkey.fsf@assigned-by-dhcp.cox.net","threadId":"737","inReplyTo":"7vsm05bkps.fsf@assigned-by-dhcp.cox.net","subject":"Re: More gitweb queries..","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-30T00:57:09Z","receivedAt":"2005-05-30T00:57:09Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"JCH\" == Junio C Hamano <junkio@cox.net> writes:\n\nJCH>    - If MB is either BASE or H1, then you have a fast forward.\nJCH>      Take either BASE or H1 that is not MB and update variable\nJCH>      BASE with it, and update variable T with the tree\nJCH>      associated with it.  Continue with the loop (i.e. Perl\nJCH>      \"next\").\n\nChuck this part please.  I was not thinking.\n\n"},{"id":"4225","messageId":"20050530013056.GH12290@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"7vsm05bkps.fsf@assigned-by-dhcp.cox.net","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-30T01:30:56Z","receivedAt":"2005-05-30T01:30:56Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\nokay let me try again.\n\nI have a function merge which gets a sorted array of heads. Heads can be\nunlimited at the time because some of the heads can be included into\nother heads (they're a subset) and so they don't show up in the commit\nobject. I call this array MERGE_HEADS.\n\nNote: If I pull into an empty tree (no HEAD) there is only one head in\nthis array which corresponds to the remote_head. Otherwise the first\nelement is *always* the local HEAD.\n\nAfter that I am starting looping over MERGE_HEADS. The first thing I\nhave to do is getting the first element out of this array and safe it\nfor later reference I call this 'head'. Also I have to push this head in\na another array called COMMIT_HEADS which will be used to create the final\ncommit object later on. The latter will be done for every loop pass. next;\n\nNote: If I left the the loop because there are no more MERGE_HEADS to\nwork on and my COMMIT_HEADS array consists only of *one* member I don't\ncreate a COMMIT object, but save it as new HEAD because we're in a fast\nforward condition (this could be pulling into an empty tree; having many\nfast forward object (remote is ahead or included into the current\n'head'). On the contrary if I have *more* than one object I call\ncommit-tree with the COMMIT_HEADS as arguments and save the new head\nreturn from this call.\n\nNow I start processing the second HEAD from MERGE_HEADS. I use\nmerge_base to find out the MERGE_BASE. If this MERGE_BASE ==\nhead than we have a (remote is fast forward condition) so our\nCURRENT_HEAD becomes head and I delete the week of the last element of\nCOMMIT_HEADS (but leaving the CURRENT_HEAD in COMMIT_HEADS). next;\nIf MERGE_BASE == CURRENT_HEAD than CURRENT_HEAD is already included in\nour history so no need to anything, but get it out of COMMIT_HEADS.\nnext; If it isn't a fast forward or already included case, we do\nautomatic/threeway/manual merge and save the resulting tree for the\nmaybe to come next automatic/threeway/manual merge. And of course also\nleaving the CURRENT_HEAD in COMMIT_HEADS. FIXME: Do we need to update\nour 'head' to the REMOTE_HEAD? next;\n\nOh and of course the sanity check: I can't commit-tree more than 16\nparents at a time. (16 is of course the define mentioned by Linus\nbefore).\n\nThat's it.\n\n\tThomas\n"},{"id":"4226","messageId":"20050530013330.GI12290@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"7voeatbkey.fsf@assigned-by-dhcp.cox.net","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-30T01:33:30Z","receivedAt":"2005-05-30T01:33:30Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\n\n> JCH>    - If MB is either BASE or H1, then you have a fast forward.\n> JCH>      Take either BASE or H1 that is not MB and update variable\n> JCH>      BASE with it, and update variable T with the tree\n> JCH>      associated with it.  Continue with the loop (i.e. Perl\n> JCH>      \"next\").\n\n> Chuck this part please.  I was not thinking.\n\nNo, I don't because I think this exactly what I have to do here. And\nyes, there can be fast forwards. :-)\n\nBut note: On a fast forward condition we have to remove a element from\nCOMMIT_HEADS: the (last) or (last - 1). Depending on if 'local' ==\nMERGE_BASE or 'remote' == MERGE_BASE.\n\n\tThomas\n"},{"id":"4243","messageId":"7vmzqd4041.fsf@assigned-by-dhcp.cox.net","threadId":"737","inReplyTo":"20050530013056.GH12290@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-30T07:57:34Z","receivedAt":"2005-05-30T07:57:34Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"TG\" == Thomas Glanzmann <sithglan@stud.uni-erlangen.de> writes:\n\nTG> Note: If I pull into an empty tree (no HEAD) there is only one head in\nTG> this array which corresponds to the remote_head. Otherwise the first\nTG> element is *always* the local HEAD.\n\n\"An empty tree (no HEAD)\"?  Is your definition of \"an empty\ntree\" the same as \"empty\" directory after you do \"mkdir empty &&\ncd empty && git-init-db\", followed by bunch of git-*-pull to get\nthe objects and commits from other reposititories being involved\nin the merge but without touching .git/HEAD?  If so, why cannot\nI do the git-*-pull from multiple repositories and merge them\ntogether?  Why \"there is only one head in this array that is\nremote_head\"?  Oh, I guess I am missing your definition of\n\"remote_head\".  Puzzled...\n\nAnyhow I presume that if your ${GIT-.git}/HEAD exists, you\ninclude it as the first element of MERGE_HEADS.\n\nTG> I have a function merge which gets a sorted array of heads. Heads can be\nTG> unlimited at the time because some of the heads can be included into\nTG> other heads (they're a subset) and so they don't show up in the commit\nTG> object. I call this array MERGE_HEADS.\n\nSorry I am not very good at this \"thinking\" thing, and I need to\ndraw pictures.  Please bear with me.\n\n    (line of dev C)-------------C    We are here, trying to merge\n    (line of dev B)---(merge)---B    these three lines of devs:\n    (line of dev A)---A/             A, B and C\n\n    MERGE_HEADS = (A B C)\n    A is actually a \"subset\" of B\n\nIs this what you mean by \"subset\"?  Are these \"subset\" HEAD the\nonly thing that causes fast forwards?\n\nMy gut feeling without thinking much is that it might be easier\nto first cull such fast forward heads by using N-way rev-tree\nbefore you do anything else.  If only one head survives after\nthat, then that head would be your new head and you do not have\nto go through any merges.  Otherwise you merge those independent\nheads without worrying about fast forwards.  How does that\nsound?\n\n"},{"id":"4247","messageId":"20050530083653.GL12290@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"7vmzqd4041.fsf@assigned-by-dhcp.cox.net","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-30T08:36:53Z","receivedAt":"2005-05-30T08:36:53Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\n\n[ => Skip till next ']' if you want because my approach doesn't work out\nfor all cases in the optimal way.\n\n> \"An empty tree (no HEAD)\"?  Is your definition of \"an empty\n> tree\" the same as \"empty\" directory after you do \"mkdir empty &&\n> cd empty && git-init-db\", followed by bunch of git-*-pull to get\n> the objects and commits from other reposititories being involved\n> in the merge but without touching .git/HEAD?\n\nYep. In practice it isn't anything else than just using the first\n'remote' HEAD as 'local' HEAD if there is no 'local' HEAD. But for merge\nthis doesn't really matter.\n\n> If so, why cannot I do the git-*-pull from multiple repositories and\n> merge them together?  Why \"there is only one head in this array that\n> is remote_head\"?  Oh, I guess I am missing your definition of\n> \"remote_head\".  Puzzled...\n\nMy intention by writing this note was to clear things up. That it also\nworks for cases where you do the 'initial clone' for one and multiple\nremotes.\n\n> Anyhow I presume that if your ${GIT-.git}/HEAD exists, you\n> include it as the first element of MERGE_HEADS.\n\nAffirmative.\n\n> TG> I have a function merge which gets a sorted array of heads. Heads can be\n> TG> unlimited at the time because some of the heads can be included into\n> TG> other heads (they're a subset) and so they don't show up in the commit\n> TG> object. I call this array MERGE_HEADS.\n\nHere is a typo: MERGE_HEADS is *not* sorted. But it is 'ordered'.\n\n> Sorry I am not very good at this \"thinking\" thing, and I need to\n> draw pictures.  Please bear with me.\n\nOf course, I do.\n\n>     (line of dev C)-------------C    We are here, trying to merge\n>     (line of dev B)---(merge)---B    these three lines of devs:\n>     (line of dev A)---A/             A, B and C\n\n>     MERGE_HEADS = (A B C)\n>     A is actually a \"subset\" of B\n\n> Is this what you mean by \"subset\"?  Are these \"subset\" HEAD the\n> only thing that causes fast forwards?\n\nExactly, but it has not to be a merge it also can be a linear\ndevelopment. What matters that A is referenced in any way in the history\nof B.\n\nIn this case where A is referenced in the history of B, we just discard\nHEAD A, because it is already merged. So A will never show up in\ngit-commit-tree in one of its \"-p\" options. But I mention it in the\ncommit-text as 'there was nothing todo'.\n\nIf we take now your example and switch the order A and B we have\n\nMERGE_HEADS = (B A C) and A is still in the history of B:\n\nWe do exactly the same here only that in the above scenario we have to\nkick out the previous COMMIT_HEAD when processing B while we drop the\ncurrent COMMIT_HEAD when processing A in this scenario. So to clear\nthings up:\n\nThe HEAD we are working on is surrouned by '*'s.\n\nMERGE_HEADS = (*B* A C) => COMMIT_HEADS = (B)\nMERGE_HEADS = (B *A* C) => COMMIT_HEADS = (B) /* note: A never did it in COMMIT_HEADS because it was referenced in history of B */\nMERGE_HEADS = (B A *C*) => COMMIT_HEADS = (B C)\n\nwhile in the above example with your initial order it is:\n\nMERGE_HEADS = (*A* B C) => COMMIT_HEADS = (A)\nMERGE_HEADS = (A *B* C) => COMMIT_HEADS = (B) /* note: A is kicked out of COMMIT_HEADS ... see above */\nMERGE_HEADS = (A B *C*) => COMMIT_HEADS = (B C) \n\n]\n\n> My gut feeling without thinking much is that it might be easier\n> to first cull such fast forward heads by using N-way rev-tree\n> before you do anything else.  If only one head survives after\n> that, then that head would be your new head and you do not have\n> to go through any merges.  Otherwise you merge those independent\n> heads without worrying about fast forwards.  How does that\n> sound?\n\nYou're right. Because this would work out bad (unneccessary\nautomatic/threeway/manual merge) if we twist MERGE_HEADS again:\n\nMERGE_HEADS = (*C* A B) => COMMIT_HEADS (C)\nMERGE_HEADS = (C *A* B) => COMMIT_HEADS (C A) /* A stays in because it is not in the history of C; -> unneccessary merge */\nMERGE_HEADS = (C A *B*) => COMMIT_HEADS (C A B)\n\nOkay, so I have to elminate all fast forward conditions in the first\nplace? How do I do this:\n\nforeach CURRENT_HEAD (@MERGE_HEADS) {\n\tforeach COMPARE_HEAD (@MERGE_HEADS) {\n\t\tif (COMPARE_HEAD != CURRENT_HEAD\n\t\t&&  COMPARE_HEAD is_included_into_history_of CURRENT_HEAD) {\n\t\t\t@WIPE_HEADS += COMPARE_HEAD;\n\t\t}\n\t}\n}\n\nforeach (@WIPE_HEADS) {\n\tgrep -v @WIPE_HEADS @MERGE_HEADS;\n}\n\n\tThomas\n"},{"id":"4249","messageId":"20050530092140.GQ12290@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"20050530083653.GL12290@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-30T09:21:40Z","receivedAt":"2005-05-30T09:21:40Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\nI also have to strip duplicate HEADs out. So we do the following:\n\nrun 0: kill dups\n\nrun 1: kill HEADs which are referenced in the history of other HEADs\n\nrun 2: do the merging (still don't know to what I should set the local\n       HEAD to the 'left' or 'right' part. Maybe we should create temporary\n       commit object so that 'merge-base' can better work on them?\n\n\tThomas\n"},{"id":"4250","messageId":"7vhdgl2ext.fsf@assigned-by-dhcp.cox.net","threadId":"737","inReplyTo":"20050530092140.GQ12290@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-30T10:20:14Z","receivedAt":"2005-05-30T10:20:14Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"TG\" == Thomas Glanzmann <sithglan@stud.uni-erlangen.de> writes:\n\nTG> Hello,\nTG> I also have to strip duplicate HEADs out. So we do the following:\n\nTG> run 0: kill dups\nTG> run 1: kill HEADs which are referenced in the history of other HEADs\n\nI think merge-base between A and A is always A, so the second\npass would eliminate the dups anyway...\n\n"},{"id":"4251","messageId":"20050530121100.GS12290@cip.informatik.uni-erlangen.de","threadId":"737","inReplyTo":"7vhdgl2ext.fsf@assigned-by-dhcp.cox.net","subject":"Re: More gitweb queries..","fromName":"Thomas Glanzmann","fromEmail":"sithglan@stud.uni-erlangen.de","sentAt":"2005-05-30T12:11:00Z","receivedAt":"2005-05-30T12:11:00Z","isPatch":false,"sender":{"key":"sithglan@stud.uni-erlangen.de","avatar":null},"body":"Hello,\n\n> I think merge-base between A and A is always A, so the second pass\n> would eliminate the dups anyway...\n\ntwo scenarios come into my mind which could clash (second ommited\nbecause it would rely that the 'local' HEAD is changes on threeway\nmerge)\n\nconsider the follow MERGE_HEADS = (A B B)\n\n    /----- A\n   /\n-GCA------ B\n\nNow B gets twice automatic/threeway/manual merged into A which is just\nstupid and couldn't work out.\n\n------------------------------------------------------------------------------\n\nBut I still don't know how to handle the following scenario:\n\n    /----- A\n   /\n-GCA------GCA---- B\n            \\---- C\n\nMERGES_HEAD = (A B C). I think the best way would be introduce a\ntemporary commit object otherwise  C into AB merge would have merge_base\non the first GCA which is suboptimal and maybe wrong isn't it?\n\n    /----- A -------D---E\n   /               /   /\n-GCA------GCA---- B   /\n            \\------- C\n\nWhere D is a temporary COMMIT obeject to use the second GCA to merge C\nwith D and gets E.\n\nGruesse,\n\tThomas\n"},{"id":"4259","messageId":"7v3bs438gc.fsf@assigned-by-dhcp.cox.net","threadId":"737","inReplyTo":"20050530121100.GS12290@cip.informatik.uni-erlangen.de","subject":"Re: More gitweb queries..","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-05-30T17:54:59Z","receivedAt":"2005-05-30T17:54:59Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"TG\" == Thomas Glanzmann <sithglan@stud.uni-erlangen.de> writes:\n\nDisregard my last MB(A,A)===A thing.  I really was not thinking,\nbut in N-way merge I think rev-tree is your friend.  Unlike\nmerge-base which always does two heads at a time, rev-tree works\nN-way.  You should be able to give many heads to it and have it\nhelp you figure out the ancestory relationship across them.\n\nTG> But I still don't know how to handle the following scenario:\n\nTG>     /----- A\nTG>    /\nTG> -GCA#1---GCA#2--- B\nTG>             \\---- C\n\nTG> MERGES_HEAD = (A B C). I think the best way would be introduce a\nTG> temporary commit object otherwise  C into AB merge would have merge_base\nTG> on the first GCA which is suboptimal and maybe wrong isn't it?\n\nI think you can run the same algorithm for those pairwise\nancestors and favor the less common ones.  In the above drawing,\nyou would first find out the three common pair-wise ancestors.\n\nIn your drawing,\n\n    GCA(A,B) = GCA#1\n    GCA(B,C) = GCA#2\n    GCA(C,A) = GCA#1\n    GCA(GCA#1,GCA#2) = GCA#1\n\nThen you notice that GCA#2 is less common than GCA#1 (indeed\nGCA#1 is contained in GCA#2).  So favoring the GCA#2, you do the\nmerge pair that uses it as the merge base, namely B and C,\nfirst.\n\nYou scan the pairwise list again and find the pair that have not\nmerged and uses the least common GCA as merge base and keep\ngoing.  For the definition of less common, in many cases those\nGCA#n would not be related at all and cannot be compared by\ntopology only, so you would probably need to come up with a\nheuristics to break such ties.  Off the top of my head, you\ncould compare commit timestamps (prefer younger), sum of commit\nchain length from GCA#n to its two head pairs (prefer shorter),\nsum of number of changed files from GCA#n to its two head pairs\n(prefer smaller).\n\nTG>     /----- A -------D---E\nTG>    /               /   /\nTG> -GCA------GCA---- B   /\nTG>             \\------- C\n\nTG> Where D is a temporary COMMIT obeject to use the second GCA to merge C\nTG> with D and gets E.\n\nYes, if you ended up merging A and B first you would have\nsomething like that.  I think you should not do that in the\nfirst place, and try to merge the \"most recently diverged\" pair\nfirst, like this:\n\n         /----- A -----------Y\n        /                   / \n     -GCA#1---GCA#2--- B --X\n                 \\---- C -/\n\nIf we are still talking about Octopus (Tripus in this case), you\nwould not want to actually make a commit X.  When you merge B\nand C, you consider that such a resulting tree resides at GCA#2\n(merge base of B and C) for the purposes of further merge\ncomputation.  Then you merge that resulting tree with A, using\nGCA#1.\n\n"},{"id":"4277","messageId":"17051.39850.556062.543875@cargo.ozlabs.ibm.com","threadId":"737","inReplyTo":"Pine.LNX.4.58.0505271145570.17402@ppc970.osdl.org","subject":"Re: More gitweb queries..","fromName":"Paul Mackerras","fromEmail":"paulus@samba.org","sentAt":"2005-05-30T23:03:06Z","receivedAt":"2005-05-30T23:03:06Z","isPatch":false,"sender":{"key":"paulus@samba.org","avatar":"https://avatars.githubusercontent.com/u/1606439?v=4"},"body":"Linus Torvalds writes:\n\n>   On that small note, I also find \"gitk\" very cool indeed, too bad about \n>   the fact that tk/tcl seems to always end up looking so _ugly_. Is there \n>   any way to get anti-aliased fonts and a less 'Motify' blocky look from \n>   tcl/tk? Every time I see that, I feel like I'm back in the last century  \n>   or something.\n\nTcl/Tk 8.5 will have anti-aliased fonts (8.5a2 is available on\nsourceforge).  There is apparently some support for widget styling in\n8.4 which I will have to look into.  The Motif look doesn't bother me,\nbut it does seem to bother you and Ben H. :)\n\n>   Combining some of the features of the two (that über-cool revision \n>   history graph from gitk rules, for example) might be cool. I get the \n>   urge to do octopus-merges in the kernel just because of how good they\n>   look in gitk ;) ]\n\nYes, it's nice that a relatively simple algorithm without much\nlookahead produces reasonable results.\n\nPaul.\n"},{"id":"4289","messageId":"20050531022656.GA3355@unpythonic.net","threadId":"737","inReplyTo":"17051.39850.556062.543875@cargo.ozlabs.ibm.com","subject":"Re: More gitweb queries..","fromName":"Jeff Epler","fromEmail":"jepler@unpythonic.net","sentAt":"2005-05-31T02:27:00Z","receivedAt":"2005-05-31T02:27:00Z","isPatch":false,"sender":{"key":"jepler@unpythonic.net","avatar":"https://avatars.githubusercontent.com/u/1517291?v=4"},"body":"On Tue, May 31, 2005 at 09:03:06AM +1000, Paul Mackerras wrote:\n> Tcl/Tk 8.5 will have anti-aliased fonts (8.5a2 is available on\n> sourceforge).  There is apparently some support for widget styling in\n> 8.4 which I will have to look into.  The Motif look doesn't bother me,\n> but it does seem to bother you and Ben H. :)\n\nI have a somewhat stale copy of Tk 8.5 CVS and Tile CVS here.  I tried\ngitk on it.  I added the lines\n    package require tile; namespace import -force ::ttk::*\n    tile::setTheme alt\nnear the top, which is a simple way to use the new \"tile\" theme engine\nwith an included, redmond-style theme.\n\nHere's a screenshot:\n    http://emergent.unpy.net/index.cgi-files/sandbox/gitk-tk85+tile.png\n\nI have no idea why the menu is in greek.  The rest of the buttons and\nlabels were too, before I switched to Tile for rendering them.\n\nI get an odd traceback that I don't get using the same gitk with\ntcl-8.4.5:\n    number too large to represent as a Posix time\n        while executing\n    \"return -options $opts $retval\"\n        (procedure \"ConvertUTCToLocal\" line 20)\n        invoked from within\n    \"ConvertUTCToLocal $date[set date {}] $timezone\"\n        (procedure \"::tcl::clock::format\" line 10)\n        invoked from within\n    \"clock format $audate -format \"%Y-%m-%d %H:%M:%S\"\"\n        (procedure \"readcommit\" line 37)\n        invoked from within\n    \"readcommit $p\"\n        (procedure \"drawgraph\" line 52)\n        invoked from within\n    \"drawgraph\"\n        (\"after\" script)\nwhich stops the graph before it's complete.  Laying out the graph seems\nmuch slower than with tk8.4.\n\nJeff\n"}]}