{"thread":{"id":"16349","subject":"[PATCHv3 0/4] gitweb: remote heads feature","startedAt":"2008-11-16T13:28:05Z","lastAt":"2008-11-17T13:31:16Z","messageCount":14,"participants":["Giuseppe Bilotta","Junio C Hamano","Jakub Narebski"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"95937","messageId":"1226842089-1159-1-git-send-email-giuseppe.bilotta@gmail.com","threadId":"16349","inReplyTo":null,"subject":"[PATCHv3 0/4] gitweb: remote heads feature","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-11-16T13:28:05Z","receivedAt":"2008-11-16T13:28:05Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"A new version of the remote heads feature patchset. This is considerably\nstripped down in comparison to the previous version, as it's limited to\nimplementing the remote_heads feature and the minimal amount of UI changes to\naccomodate it cleanly. Other features such as grouping of heads and supporting\ndetached HEAD will be implemented separately.\n\n*NOTE*: this patchset is based on my previous\n\n\"gitweb: fixes to gitweb feature check code\"\n\npatch http://article.gmane.org/gmane.comp.version-control.git/101070\n\nGiuseppe Bilotta (4):\n  gitweb: introduce remote_heads feature\n  gitweb: git_get_heads_list accepts an optional list of refs.\n  gitweb: separate heads and remotes lists\n  gitweb: link heads and remotes view\n\n gitweb/gitweb.perl |   74 +++++++++++++++++++++++++++++++++++++++++++++++----\n 1 files changed, 68 insertions(+), 6 deletions(-)\n"},{"id":"95938","messageId":"1226842089-1159-2-git-send-email-giuseppe.bilotta@gmail.com","threadId":"16349","inReplyTo":"1226842089-1159-1-git-send-email-giuseppe.bilotta@gmail.com","subject":"[PATCHv3 1/4] gitweb: introduce remote_heads feature","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-11-16T13:28:06Z","receivedAt":"2008-11-16T13:28:06Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"With this feature enabled, remotes are retrieved (and displayed)\nwhen getting (and displaying) the heads list. Typical usage would be for\nlocal repository browsing, e.g. by using git-instaweb (or even a more\npermanent gitweb setup), to check the repository status and the relation\nbetween tracking branches and the originating remotes.\n\nSigned-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n---\n gitweb/gitweb.perl |   31 +++++++++++++++++++++++++++++--\n 1 files changed, 29 insertions(+), 2 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex b0d00ea..e1f81f6 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -329,6 +329,18 @@ our %feature = (\n \t'ctags' => {\n \t\t'override' => 0,\n \t\t'default' => [0]},\n+\n+\t# Make gitweb show remotes too in the heads list\n+\n+\t# To enable system wide have in $GITWEB_CONFIG\n+\t# $feature{'remote_heads'}{'default'} = [1];\n+\t# To have project specific config enable override in $GITWEB_CONFIG\n+\t# $feature{'remote_heads'}{'override'} = 1;\n+\t# and in project config gitweb.remote_heads = 0|1;\n+\t'remote_heads' => {\n+\t\t'sub' => \\&feature_remote_heads,\n+\t\t'override' => 0,\n+\t\t'default' => [0]},\n );\n \n # retrieve the value of a given feature, as an array\n@@ -410,6 +422,18 @@ sub feature_pickaxe {\n \treturn ($_[0]);\n }\n \n+sub feature_remote_heads {\n+\tmy ($val) = git_get_project_config('remote_heads', '--bool');\n+\n+\tif ($val eq 'true') {\n+\t\treturn (1);\n+\t} elsif ($val eq 'false') {\n+\t\treturn (0);\n+\t}\n+\n+\treturn ($_[0]);\n+}\n+\n # checking HEAD file with -e is fragile if the repository was\n # initialized long time ago (i.e. symlink HEAD) and was pack-ref'ed\n # and then pruned.\n@@ -2660,10 +2684,12 @@ sub git_get_heads_list {\n \tmy $limit = shift;\n \tmy @headslist;\n \n+\tmy $remote_heads = gitweb_check_feature('remote_heads');\n+\n \topen my $fd, '-|', git_cmd(), 'for-each-ref',\n \t\t($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate',\n \t\t'--format=%(objectname) %(refname) %(subject)%00%(committer)',\n-\t\t'refs/heads'\n+\t\t'refs/heads', ( $remote_heads ? 'refs/remotes' : '')\n \t\tor return;\n \twhile (my $line = <$fd>) {\n \t\tmy %ref_item;\n@@ -2674,8 +2700,9 @@ sub git_get_heads_list {\n \t\tmy ($committer, $epoch, $tz) =\n \t\t\t($committerinfo =~ /^(.*) ([0-9]+) (.*)$/);\n \t\t$ref_item{'fullname'}  = $name;\n-\t\t$name =~ s!^refs/heads/!!;\n+\t\t$name =~ s!^refs/(head|remote)s/!!;\n \n+\t\t$ref_item{'class'} = $1;\n \t\t$ref_item{'name'}  = $name;\n \t\t$ref_item{'id'}    = $hash;\n \t\t$ref_item{'title'} = $title || '(no commit message)';\n-- \n1.5.6.5\n"},{"id":"95940","messageId":"1226842089-1159-3-git-send-email-giuseppe.bilotta@gmail.com","threadId":"16349","inReplyTo":"1226842089-1159-2-git-send-email-giuseppe.bilotta@gmail.com","subject":"[PATCHv3 2/4] gitweb: git_get_heads_list accepts an optional list of refs.","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-11-16T13:28:07Z","receivedAt":"2008-11-16T13:28:07Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"git_get_heads_list(limit, class1, class2, ...) can now be used to retrieve\nrefs/class1, refs/class2 etc. Defaults to ('heads') or ('heads', 'remotes')\ndepending on the remote_heads option.\n\nSigned-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n---\n gitweb/gitweb.perl |   11 +++++++----\n 1 files changed, 7 insertions(+), 4 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex e1f81f6..0512020 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -2681,15 +2681,18 @@ sub parse_from_to_diffinfo {\n ## parse to array of hashes functions\n \n sub git_get_heads_list {\n-\tmy $limit = shift;\n+\tmy ($limit, @class) = @_;\n+\tunless (defined @class) {\n+\t\tmy $remote_heads = gitweb_check_feature('remote_heads');\n+\t\t@class = ('heads', $remote_heads ? 'remotes' : undef);\n+\t}\n+\tmy @refs = map { \"refs/$_\" } @class;\n \tmy @headslist;\n \n-\tmy $remote_heads = gitweb_check_feature('remote_heads');\n-\n \topen my $fd, '-|', git_cmd(), 'for-each-ref',\n \t\t($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate',\n \t\t'--format=%(objectname) %(refname) %(subject)%00%(committer)',\n-\t\t'refs/heads', ( $remote_heads ? 'refs/remotes' : '')\n+\t\t@refs\n \t\tor return;\n \twhile (my $line = <$fd>) {\n \t\tmy %ref_item;\n-- \n1.5.6.5\n"},{"id":"95941","messageId":"1226842089-1159-4-git-send-email-giuseppe.bilotta@gmail.com","threadId":"16349","inReplyTo":"1226842089-1159-3-git-send-email-giuseppe.bilotta@gmail.com","subject":"[PATCHv3 3/4] gitweb: separate heads and remotes lists","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-11-16T13:28:08Z","receivedAt":"2008-11-16T13:28:08Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"We specialize the 'heads' action to only display local branches, and\nintroduce a 'remotes' action to display the remote branches (only\navailable when the remotes_head feature is enabled).\n\nMirroring this, we also split the heads list in summary view into\nlocal and remote lists, each linking to the appropriate action.\n\nSigned-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n---\n gitweb/gitweb.perl |   30 ++++++++++++++++++++++++++++--\n 1 files changed, 28 insertions(+), 2 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 0512020..6b09918 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -527,6 +527,7 @@ our %actions = (\n \t\"heads\" => \\&git_heads,\n \t\"history\" => \\&git_history,\n \t\"log\" => \\&git_log,\n+\t\"remotes\" => \\&git_remotes,\n \t\"rss\" => \\&git_rss,\n \t\"atom\" => \\&git_atom,\n \t\"search\" => \\&git_search,\n@@ -4467,6 +4468,7 @@ sub git_summary {\n \tmy %co = parse_commit(\"HEAD\");\n \tmy %cd = %co ? parse_date($co{'committer_epoch'}, $co{'committer_tz'}) : ();\n \tmy $head = $co{'id'};\n+\tmy $remote_heads = gitweb_check_feature('remote_heads');\n \n \tmy $owner = git_get_project_owner($project);\n \n@@ -4474,7 +4476,8 @@ sub git_summary {\n \t# These get_*_list functions return one more to allow us to see if\n \t# there are more ...\n \tmy @taglist  = git_get_tags_list(16);\n-\tmy @headlist = git_get_heads_list(16);\n+\tmy @headlist = git_get_heads_list(16, 'heads');\n+\tmy @remotelist = $remote_heads ? git_get_heads_list(16, 'remotes') : ();\n \tmy @forklist;\n \tmy $check_forks = gitweb_check_feature('forks');\n \n@@ -4553,6 +4556,13 @@ sub git_summary {\n \t\t               $cgi->a({-href => href(action=>\"heads\")}, \"...\"));\n \t}\n \n+\tif (@remotelist) {\n+\t\tgit_print_header_div('remotes');\n+\t\tgit_heads_body(\\@remotelist, $head, 0, 15,\n+\t\t               $#remotelist <= 15 ? undef :\n+\t\t               $cgi->a({-href => href(action=>\"remotes\")}, \"...\"));\n+\t}\n+\n \tif (@forklist) {\n \t\tgit_print_header_div('forks');\n \t\tgit_project_list_body(\\@forklist, 'age', 0, 15,\n@@ -4729,13 +4739,29 @@ sub git_heads {\n \tgit_print_page_nav('','', $head,undef,$head);\n \tgit_print_header_div('summary', $project);\n \n-\tmy @headslist = git_get_heads_list();\n+\tmy @headslist = git_get_heads_list(undef, 'heads');\n \tif (@headslist) {\n \t\tgit_heads_body(\\@headslist, $head);\n \t}\n \tgit_footer_html();\n }\n \n+sub git_remotes {\n+\tgitweb_check_feature('remote_heads')\n+\t\tor die_error(403, \"Remote heads view is disabled\");\n+\n+\tmy $head = git_get_head_hash($project);\n+\tgit_header_html();\n+\tgit_print_page_nav('','', $head,undef,$head);\n+\tgit_print_header_div('summary', $project);\n+\n+\tmy @remotelist = git_get_heads_list(undef, 'remotes');\n+\tif (@remotelist) {\n+\t\tgit_heads_body(\\@remotelist, $head);\n+\t}\n+\tgit_footer_html();\n+}\n+\n sub git_blob_plain {\n \tmy $type = shift;\n \tmy $expires;\n-- \n1.5.6.5\n"},{"id":"95939","messageId":"1226842089-1159-5-git-send-email-giuseppe.bilotta@gmail.com","threadId":"16349","inReplyTo":"1226842089-1159-4-git-send-email-giuseppe.bilotta@gmail.com","subject":"[PATCHv3 4/4] gitweb: link heads and remotes view","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-11-16T13:28:09Z","receivedAt":"2008-11-16T13:28:09Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"Add a link in heads view to remotes view (if the feature is\nenabled), and conversely from remotes to heads.\n---\n gitweb/gitweb.perl |   10 ++++++++--\n 1 files changed, 8 insertions(+), 2 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 6b09918..95162db 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -4736,7 +4736,10 @@ sub git_tags {\n sub git_heads {\n \tmy $head = git_get_head_hash($project);\n \tgit_header_html();\n-\tgit_print_page_nav('','', $head,undef,$head);\n+\tmy $heads_nav = gitweb_check_feature('remote_heads') ?\n+\t\t$cgi->a({-href => href(action=>\"remotes\", -replay=>1)},\n+\t\t        \"remotes\") : undef;\n+\tgit_print_page_nav('','', $head,undef,$head, $heads_nav);\n \tgit_print_header_div('summary', $project);\n \n \tmy @headslist = git_get_heads_list(undef, 'heads');\n@@ -4752,7 +4755,10 @@ sub git_remotes {\n \n \tmy $head = git_get_head_hash($project);\n \tgit_header_html();\n-\tgit_print_page_nav('','', $head,undef,$head);\n+\tmy $heads_nav =\n+\t\t$cgi->a({-href => href(action=>\"heads\", -replay=>1)},\n+\t\t        \"heads\");\n+\tgit_print_page_nav('','', $head,undef,$head, $heads_nav);\n \tgit_print_header_div('summary', $project);\n \n \tmy @remotelist = git_get_heads_list(undef, 'remotes');\n-- \n1.5.6.5\n"},{"id":"95955","messageId":"7vvdun3827.fsf@gitster.siamese.dyndns.org","threadId":"16349","inReplyTo":"1226842089-1159-2-git-send-email-giuseppe.bilotta@gmail.com","subject":"Re: [PATCHv3 1/4] gitweb: introduce remote_heads feature","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-11-16T17:16:32Z","receivedAt":"2008-11-16T17:16:32Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Giuseppe Bilotta <giuseppe.bilotta@gmail.com> writes:\n\n> With this feature enabled, remotes are retrieved (and displayed)\n> when getting (and displaying) the heads list.\n\nWouldn't it be easier to read if you just said: \"Include 'remotes' in the\nheads_list\", because:\n\n - \"heads list\" does not sound like a proper English phrase but you are\n   referring to the sub \"heads_list\";\n\n - it is obvious and unnecessary to say \"when getting, they are retrieved,\n   when displaying, they are displayed\", which is what your parenthesized\n   parts of the sentence is about;\n\nI am also suggesting to drop \"With this feature enabled\"; I do not think\nof a case where somebody runs gitweb on a repository with refs/remotes and\ndoes not want to show them.\n\n> Typical usage would be for\n> local repository browsing, e.g. by using git-instaweb (or even a more\n> permanent gitweb setup), to check the repository status and the relation\n> between tracking branches and the originating remotes.\n\nWhen proofreading what you've written, it is usually a good idea to read\nit without anything you wrote in parentheses once, and then re-read it\nwith parentheses removed (but the stuff in your parentheses kept), and\ncompare which one you like better.  More often than not, you'd find that\neither parenthesized parts are unnecessary, or they are important enough\nthat you shouldn't put them in parentheses.\n\nIn this case, because you made it clear that you are giving just an\nexample and not trying to be exhaustive by saying \"e.g.\", I think dropping\nthe parenthesized part from the description is better.\n\nAlso I think the description is better without \"to check...originating\nremotes.\", because:\n\n - \"to check the repository status\"?  what status?  it is too broad to be\n   a meaningful description;\n\n - \"relation between tracking vs origin\" is one thing gitweb is very bad\n   at doing, because it flattens the history, compared to things like\n   gitk, which you need to compete with especially because you are\n   advocating the feature to help local browsing.\n\n> diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\n> index b0d00ea..e1f81f6 100755\n> --- a/gitweb/gitweb.perl\n> +++ b/gitweb/gitweb.perl\n> @@ -329,6 +329,18 @@ our %feature = (\n> ...\n> @@ -410,6 +422,18 @@ sub feature_pickaxe {\n> ...\n> +sub feature_remote_heads {\n> ...\n> +}\n\nWhen would somebody want to disable this?  Please explain; I'd like to\nunderstand the motivation behind it.\n\nOne argument for making this feature optional I can think of is to retain\nbackward compatibility because we didn't show them before, but I would say\nthat is a weak argument.  Before release 1.5.0 made the separate remotes\nlayout the default, everything was in refs/heads/, so you could even argue\nthat this \"fixes\" the gitweb bug introduced in that release that stopped\nshowing the branches you copied from elsewhere.\n\n> @@ -2660,10 +2684,12 @@ sub git_get_heads_list {\n>  \tmy $limit = shift;\n>  \tmy @headslist;\n>  \n> +\tmy $remote_heads = gitweb_check_feature('remote_heads');\n> +\n>  \topen my $fd, '-|', git_cmd(), 'for-each-ref',\n>  \t\t($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate',\n>  \t\t'--format=%(objectname) %(refname) %(subject)%00%(committer)',\n> -\t\t'refs/heads'\n> +\t\t'refs/heads', ( $remote_heads ? 'refs/remotes' : '')\n>  \t\tor return;\n>  \twhile (my $line = <$fd>) {\n>  \t\tmy %ref_item;\n\nImagine a later version of git may introduce 'refs/frotz/nitfol' namespace\nhierarchy that is commonly known as the 'xyzzy class' and is also useful\nto show.  Wouldn't it be easier to update gitweb to match such a change if\nthis part of the code were written like this?\n\n\tmy %head_class = ('refs/heads' => 'head');\n\t$head_class{'refs/remotes'} = 'remote'\n\t        if ( this feature is used );\n\t$head_class{'refs/frotz/nitfol'} = 'xyzzy'\n\t        if ( the xyzzy class is used);\n        open my $fd, ... (keys %head_class);\n\n> @@ -2674,8 +2700,9 @@ sub git_get_heads_list {\n>  \t\tmy ($committer, $epoch, $tz) =\n>  \t\t\t($committerinfo =~ /^(.*) ([0-9]+) (.*)$/);\n>  \t\t$ref_item{'fullname'}  = $name;\n> -\t\t$name =~ s!^refs/heads/!!;\n> +\t\t$name =~ s!^refs/(head|remote)s/!!;\n>  \n> +\t\t$ref_item{'class'} = $1;\n\nAnd then outside the loop, you'd prepare:\n\n\tmy $headpat = join('|', map { quotemeta($_) } keys %head_class);\n\nand inside the loop you would do:\n\n\tif ($name =~ s{^($headpat)/}{}) {\n        \t$ref_item{'class'} = $head_class{$1};\n\t\t...\n\nOnly one place to configure the list of classes, and make everybody use\nthat list instead of hardcoding the assumption that there are two and only\ntwo kinds of things \"head\" vs \"remote\".\n"},{"id":"95956","messageId":"7vod0f37gr.fsf@gitster.siamese.dyndns.org","threadId":"16349","inReplyTo":"1226842089-1159-3-git-send-email-giuseppe.bilotta@gmail.com","subject":"Re: [PATCHv3 2/4] gitweb: git_get_heads_list accepts an optional list of refs.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-11-16T17:29:24Z","receivedAt":"2008-11-16T17:29:24Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Giuseppe Bilotta <giuseppe.bilotta@gmail.com> writes:\n\n> git_get_heads_list(limit, class1, class2, ...) can now be used to retrieve\n> refs/class1, refs/class2 etc. Defaults to ('heads') or ('heads', 'remotes')\n> depending on the remote_heads option.\n>\n> Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n> ---\n>  gitweb/gitweb.perl |   11 +++++++----\n>  1 files changed, 7 insertions(+), 4 deletions(-)\n>\n> diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\n> index e1f81f6..0512020 100755\n> --- a/gitweb/gitweb.perl\n> +++ b/gitweb/gitweb.perl\n> @@ -2681,15 +2681,18 @@ sub parse_from_to_diffinfo {\n>  ## parse to array of hashes functions\n>  \n>  sub git_get_heads_list {\n> -\tmy $limit = shift;\n> +\tmy ($limit, @class) = @_;\n> +\tunless (defined @class) {\n> +\t\tmy $remote_heads = gitweb_check_feature('remote_heads');\n> +\t\t@class = ('heads', $remote_heads ? 'remotes' : undef);\n> +\t}\n> +\tmy @refs = map { \"refs/$_\" } @class;\n\nMakes sense, except that I'd suggest passing a hash of \"refs/$path\" =>\n$class as I illustrated in my comments to [1/4], instead of passing a list\nof (\"head\", \"remote\"), because that will later allow you to have\nmulti-level $path that does not necessarily limited to a $class that is a\nsubstring of $path, and doing so does not make the code any more complex.\nThere is another reason to do so I'll mention in I comment on [3/4].\n"},{"id":"95957","messageId":"7viqqn377m.fsf@gitster.siamese.dyndns.org","threadId":"16349","inReplyTo":"1226842089-1159-4-git-send-email-giuseppe.bilotta@gmail.com","subject":"Re: [PATCHv3 3/4] gitweb: separate heads and remotes lists","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-11-16T17:34:53Z","receivedAt":"2008-11-16T17:34:53Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Giuseppe Bilotta <giuseppe.bilotta@gmail.com> writes:\n\n> We specialize the 'heads' action to only display local branches, and\n> introduce a 'remotes' action to display the remote branches (only\n> available when the remotes_head feature is enabled).\n>\n> Mirroring this, we also split the heads list in summary view into\n> local and remote lists, each linking to the appropriate action.\n>\n> Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n> ---\n>  gitweb/gitweb.perl |   30 ++++++++++++++++++++++++++++--\n>  1 files changed, 28 insertions(+), 2 deletions(-)\n>\n> diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\n> index 0512020..6b09918 100755\n> --- a/gitweb/gitweb.perl\n> +++ b/gitweb/gitweb.perl\n> @@ -527,6 +527,7 @@ our %actions = (\n>  \t\"heads\" => \\&git_heads,\n>  \t\"history\" => \\&git_history,\n>  \t\"log\" => \\&git_log,\n> +\t\"remotes\" => \\&git_remotes,\n>  \t\"rss\" => \\&git_rss,\n>  \t\"atom\" => \\&git_atom,\n>  \t\"search\" => \\&git_search,\n> @@ -4467,6 +4468,7 @@ sub git_summary {\n>  \tmy %co = parse_commit(\"HEAD\");\n>  \tmy %cd = %co ? parse_date($co{'committer_epoch'}, $co{'committer_tz'}) : ();\n>  \tmy $head = $co{'id'};\n> +\tmy $remote_heads = gitweb_check_feature('remote_heads');\n>  \n>  \tmy $owner = git_get_project_owner($project);\n>  \n> @@ -4474,7 +4476,8 @@ sub git_summary {\n>  \t# These get_*_list functions return one more to allow us to see if\n>  \t# there are more ...\n>  \tmy @taglist  = git_get_tags_list(16);\n> -\tmy @headlist = git_get_heads_list(16);\n> +\tmy @headlist = git_get_heads_list(16, 'heads');\n> +\tmy @remotelist = $remote_heads ? git_get_heads_list(16, 'remotes') : ();\n\nWasteful to run one for-each-ref for each list.\n\nYou earlier introduced $ref_item{'class'} so that you can differenciate\nwhat you got from git_get_heads_list(); make use of it, perhaps like:\n\n\tmy @heads_list = git_get_heads_list(16, \\%head_class);\n        my @headlist = grep { $_->{'class'} eq 'head' } @heads_list;\n        my @remotelist = grep { $_->{'class'} eq 'remote' } @heads_list;\n\nBy the way, your [2/4] used \"heads\" and \"remotes\" as class, while your\n[1/4] stored 'head' and 'remote' in $ref_item{'class'}.  Notice the above\nsuggestion corrects this discrepancy as well.\n"},{"id":"95958","messageId":"cb7bb73a0811160940wd3624ccl4f1f184cff729b6@mail.gmail.com","threadId":"16349","inReplyTo":"7vvdun3827.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCHv3 1/4] gitweb: introduce remote_heads feature","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-11-16T17:40:19Z","receivedAt":"2008-11-16T17:40:19Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"On Sun, Nov 16, 2008 at 6:16 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Giuseppe Bilotta <giuseppe.bilotta@gmail.com> writes:\n>\n>> With this feature enabled, remotes are retrieved (and displayed)\n>> when getting (and displaying) the heads list.\n>\n> Wouldn't it be easier to read if you just said: \"Include 'remotes' in the\n> heads_list\", because:\n\n[snip]\n\n> I am also suggesting to drop \"With this feature enabled\"; I do not think\n> of a case where somebody runs gitweb on a repository with refs/remotes and\n> does not want to show them.\n\n[snip]\n\n> When proofreading what you've written, it is usually a good idea to read\n> it without anything you wrote in parentheses once, and then re-read it\n> with parentheses removed (but the stuff in your parentheses kept), and\n> compare which one you like better.  More often than not, you'd find that\n> either parenthesized parts are unnecessary, or they are important enough\n> that you shouldn't put them in parentheses.\n\nGood points, I'll rewrite the commit messagge following the suggestions.\n\n>> diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\n>> index b0d00ea..e1f81f6 100755\n>> --- a/gitweb/gitweb.perl\n>> +++ b/gitweb/gitweb.perl\n>> @@ -329,6 +329,18 @@ our %feature = (\n>> ...\n>> @@ -410,6 +422,18 @@ sub feature_pickaxe {\n>> ...\n>> +sub feature_remote_heads {\n>> ...\n>> +}\n>\n> When would somebody want to disable this?  Please explain; I'd like to\n> understand the motivation behind it.\n>\n> One argument for making this feature optional I can think of is to retain\n> backward compatibility because we didn't show them before, but I would say\n> that is a weak argument.  Before release 1.5.0 made the separate remotes\n> layout the default, everything was in refs/heads/, so you could even argue\n> that this \"fixes\" the gitweb bug introduced in that release that stopped\n> showing the branches you copied from elsewhere.\n\nFor example, because the only remote for the tree is the author's own\nprivate tree, or because the only remotes are the mirrors on gitorious\nor github. In both cases, there would be no reaso to waste resources,\nbandwidth and screen estate loading and displaying the remote\nreferences.\n\nOTOH, it might make sense to make remote_heads enabled by default (and\noverridable).\n\n>> @@ -2660,10 +2684,12 @@ sub git_get_heads_list {\n>>       my $limit = shift;\n>>       my @headslist;\n>>\n>> +     my $remote_heads = gitweb_check_feature('remote_heads');\n>> +\n>>       open my $fd, '-|', git_cmd(), 'for-each-ref',\n>>               ($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate',\n>>               '--format=%(objectname) %(refname) %(subject)%00%(committer)',\n>> -             'refs/heads'\n>> +             'refs/heads', ( $remote_heads ? 'refs/remotes' : '')\n>>               or return;\n>>       while (my $line = <$fd>) {\n>>               my %ref_item;\n>\n> Imagine a later version of git may introduce 'refs/frotz/nitfol' namespace\n> hierarchy that is commonly known as the 'xyzzy class' and is also useful\n> to show.  Wouldn't it be easier to update gitweb to match such a change if\n> this part of the code were written like this?\n>\n>        my %head_class = ('refs/heads' => 'head');\n>        $head_class{'refs/remotes'} = 'remote'\n>                if ( this feature is used );\n>        $head_class{'refs/frotz/nitfol'} = 'xyzzy'\n>                if ( the xyzzy class is used);\n>        open my $fd, ... (keys %head_class);\n>\n>> @@ -2674,8 +2700,9 @@ sub git_get_heads_list {\n>>               my ($committer, $epoch, $tz) =\n>>                       ($committerinfo =~ /^(.*) ([0-9]+) (.*)$/);\n>>               $ref_item{'fullname'}  = $name;\n>> -             $name =~ s!^refs/heads/!!;\n>> +             $name =~ s!^refs/(head|remote)s/!!;\n>>\n>> +             $ref_item{'class'} = $1;\n>\n> And then outside the loop, you'd prepare:\n>\n>        my $headpat = join('|', map { quotemeta($_) } keys %head_class);\n>\n> and inside the loop you would do:\n>\n>        if ($name =~ s{^($headpat)/}{}) {\n>                $ref_item{'class'} = $head_class{$1};\n>                ...\n>\n> Only one place to configure the list of classes, and make everybody use\n> that list instead of hardcoding the assumption that there are two and only\n> two kinds of things \"head\" vs \"remote\".\n\nAh, good point. This change, and the one about extending\ngit_get_heads_list, could also be turned into prelliminary patches to\nthe actual remote_heads feature.\n\n-- \nGiuseppe \"Oblomov\" Bilotta\n"},{"id":"95960","messageId":"7vabbz35d9.fsf@gitster.siamese.dyndns.org","threadId":"16349","inReplyTo":"cb7bb73a0811160940wd3624ccl4f1f184cff729b6@mail.gmail.com","subject":"Re: [PATCHv3 1/4] gitweb: introduce remote_heads feature","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-11-16T18:14:42Z","receivedAt":"2008-11-16T18:14:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Giuseppe Bilotta\" <giuseppe.bilotta@gmail.com> writes:\n\n> For example, because the only remote for the tree is the author's own\n> private tree, or because the only remotes are the mirrors on gitorious\n> or github. In both cases, there would be no reaso to waste resources,\n> bandwidth and screen estate loading and displaying the remote\n> references.\n\nSorry, but you are not making sense.  The above may be a reason not to run\ngitweb in such a repository, but if you are viewing such a private tree,\nperhaps thru instaweb, wouldn't you be interested in viewing them?\n\n> OTOH, it might make sense to make remote_heads enabled by default (and\n> overridable).\n\nPerhaps.  I'll stop commenting on \"should this be optional, if so what\nshould be the default\" and let others chime in.  Honestly I do not care\nthat deeply either way.\n"},{"id":"95961","messageId":"cb7bb73a0811161021n250d2719qbdf80781b6f04a35@mail.gmail.com","threadId":"16349","inReplyTo":"7vabbz35d9.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCHv3 1/4] gitweb: introduce remote_heads feature","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-11-16T18:21:21Z","receivedAt":"2008-11-16T18:21:21Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"On Sun, Nov 16, 2008 at 7:14 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> \"Giuseppe Bilotta\" <giuseppe.bilotta@gmail.com> writes:\n>\n>> For example, because the only remote for the tree is the author's own\n>> private tree, or because the only remotes are the mirrors on gitorious\n>> or github. In both cases, there would be no reaso to waste resources,\n>> bandwidth and screen estate loading and displaying the remote\n>> references.\n>\n> Sorry, but you are not making sense.  The above may be a reason not to run\n> gitweb in such a repository, but if you are viewing such a private tree,\n> perhaps thru instaweb, wouldn't you be interested in viewing them?\n\nNo, I'm talking about the PUBLIC tree whose only remote is the private\none, or the gitorious/github mirrors, an example of the latter being\nthe rbot tree http://www.ruby-rbot.org/gitweb/rbot.git\n\n>> OTOH, it might make sense to make remote_heads enabled by default (and\n>> overridable).\n>\n> Perhaps.  I'll stop commenting on \"should this be optional, if so what\n> should be the default\" and let others chime in.  Honestly I do not care\n> that deeply either way.\n\nMe either, actually. 8-D\n\n\n-- \nGiuseppe \"Oblomov\" Bilotta\n"},{"id":"96000","messageId":"200811170209.54696.jnareb@gmail.com","threadId":"16349","inReplyTo":"7vod0f37gr.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCHv3 2/4] gitweb: git_get_heads_list accepts an optional list of refs.","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-11-17T01:09:54Z","receivedAt":"2008-11-17T01:09:54Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Sun, 16 Nov 2008, Junio C Hamano wrote:\n> Giuseppe Bilotta <giuseppe.bilotta@gmail.com> writes:\n> \n> > git_get_heads_list(limit, class1, class2, ...) can now be used to retrieve\n> > refs/class1, refs/class2 etc. Defaults to ('heads') or ('heads', 'remotes')\n> > depending on the remote_heads option.\n> >\n> > Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n> > ---\n> >  gitweb/gitweb.perl |   11 +++++++----\n> >  1 files changed, 7 insertions(+), 4 deletions(-)\n> >\n> > diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\n> > index e1f81f6..0512020 100755\n> > --- a/gitweb/gitweb.perl\n> > +++ b/gitweb/gitweb.perl\n> > @@ -2681,15 +2681,18 @@ sub parse_from_to_diffinfo {\n> >  ## parse to array of hashes functions\n> >  \n> >  sub git_get_heads_list {\n> > -\tmy $limit = shift;\n> > +\tmy ($limit, @class) = @_;\n> > +\tunless (defined @class) {\n> > +\t\tmy $remote_heads = gitweb_check_feature('remote_heads');\n> > +\t\t@class = ('heads', $remote_heads ? 'remotes' : undef);\n> > +\t}\n> > +\tmy @refs = map { \"refs/$_\" } @class;\n> \n> Makes sense, except that I'd suggest passing a hash of \"refs/$path\" =>\n> $class as I illustrated in my comments to [1/4], instead of passing a list\n> of (\"head\", \"remote\"), because that will later allow you to have\n> multi-level $path that does not necessarily limited to a $class that is a\n> substring of $path, and doing so does not make the code any more complex.\n> There is another reason to do so I'll mention in I comment on [3/4].\n\nBy the way, with %head_class hash passed as reference git_get_head_list\ncould be done in such way, that you can write \n\n  git_get_heads_list(\\%head_class);\n\ninstead of longer\n\n  git_get_heads_list(undef, \\%head_class);\n\nwhen there is no limit(er).\n-- \nJakub Narebski\nPoland\n"},{"id":"96037","messageId":"cb7bb73a0811170511s4df6efbbl220fa89469388aca@mail.gmail.com","threadId":"16349","inReplyTo":"7viqqn377m.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCHv3 3/4] gitweb: separate heads and remotes lists","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-11-17T13:11:02Z","receivedAt":"2008-11-17T13:11:02Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"On Sun, Nov 16, 2008 at 6:34 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Giuseppe Bilotta <giuseppe.bilotta@gmail.com> writes:\n>> -     my @headlist = git_get_heads_list(16);\n>> +     my @headlist = git_get_heads_list(16, 'heads');\n>> +     my @remotelist = $remote_heads ? git_get_heads_list(16, 'remotes') : ();\n>\n> Wasteful to run one for-each-ref for each list.\n>\n> You earlier introduced $ref_item{'class'} so that you can differenciate\n> what you got from git_get_heads_list(); make use of it, perhaps like:\n>\n>        my @heads_list = git_get_heads_list(16, \\%head_class);\n>        my @headlist = grep { $_->{'class'} eq 'head' } @heads_list;\n>        my @remotelist = grep { $_->{'class'} eq 'remote' } @heads_list;\n>\n> By the way, your [2/4] used \"heads\" and \"remotes\" as class, while your\n> [1/4] stored 'head' and 'remote' in $ref_item{'class'}.  Notice the above\n> suggestion corrects this discrepancy as well.\n\nAlthough I agree with the head_class idea, I would like to point out\nthat doing a single git call to retrieve all refs and then selecting\nthe ones we want and doing multiple git calls are not equivalent.\n\nFirst of all, with multiple calls we can limit the calls to retrieve\nat most 16 refs of each kind, whereas this cannot be done with a\nsingle call for all the refs. I'm not sure however, performance-wise,\nif it's faster to filter the first 16 refs of each after retrieving\nall of them, or doing multiple calls, especially with lots of refs.\n\nMoreover, gitweb is already doing multiple for-each-ref calls to get\ntags and heads. I guess that at this point we could go the extra mile\nand include tags in the refs management. Of course, the problem of how\nto handle the rate limiting remains.\n\n\n-- \nGiuseppe \"Oblomov\" Bilotta\n"},{"id":"96038","messageId":"cb7bb73a0811170531o45f0970cyf225ecab087ccb5@mail.gmail.com","threadId":"16349","inReplyTo":"cb7bb73a0811170511s4df6efbbl220fa89469388aca@mail.gmail.com","subject":"Re: [PATCHv3 3/4] gitweb: separate heads and remotes lists","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-11-17T13:31:16Z","receivedAt":"2008-11-17T13:31:16Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"On Mon, Nov 17, 2008 at 2:11 PM, Giuseppe Bilotta\n<giuseppe.bilotta@gmail.com> wrote:\n> On Sun, Nov 16, 2008 at 6:34 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Giuseppe Bilotta <giuseppe.bilotta@gmail.com> writes:\n>>> -     my @headlist = git_get_heads_list(16);\n>>> +     my @headlist = git_get_heads_list(16, 'heads');\n>>> +     my @remotelist = $remote_heads ? git_get_heads_list(16, 'remotes') : ();\n>>\n>> Wasteful to run one for-each-ref for each list.\n>>\n>> You earlier introduced $ref_item{'class'} so that you can differenciate\n>> what you got from git_get_heads_list(); make use of it, perhaps like:\n>>\n>>        my @heads_list = git_get_heads_list(16, \\%head_class);\n>>        my @headlist = grep { $_->{'class'} eq 'head' } @heads_list;\n>>        my @remotelist = grep { $_->{'class'} eq 'remote' } @heads_list;\n>>\n>> By the way, your [2/4] used \"heads\" and \"remotes\" as class, while your\n>> [1/4] stored 'head' and 'remote' in $ref_item{'class'}.  Notice the above\n>> suggestion corrects this discrepancy as well.\n>\n> Although I agree with the head_class idea, I would like to point out\n> that doing a single git call to retrieve all refs and then selecting\n> the ones we want and doing multiple git calls are not equivalent.\n>\n> First of all, with multiple calls we can limit the calls to retrieve\n> at most 16 refs of each kind, whereas this cannot be done with a\n> single call for all the refs. I'm not sure however, performance-wise,\n> if it's faster to filter the first 16 refs of each after retrieving\n> all of them, or doing multiple calls, especially with lots of refs.\n>\n> Moreover, gitweb is already doing multiple for-each-ref calls to get\n> tags and heads. I guess that at this point we could go the extra mile\n> and include tags in the refs management. Of course, the problem of how\n> to handle the rate limiting remains.\n\nSorry, replying to myself here. After more careful reading and some\nmore accurate testing, I gather that tags and heads management is\ndifferent enough to justify totally separate methods, and the cost of\nan additional git call. It *could* still be merged (possibly with a\nslightly different format string to accomodate both cases), but we\nwould have to do sorting ourselves, and such stuff. Not sure it's\nworth it (yet).\n\nMy perplexity about rate limiting and separate calls for separate head\nclasses still remains, though.\n\n\n-- \nGiuseppe \"Oblomov\" Bilotta\n"}]}