Subject: [PATCH] gitweb: Deal with HEAD pointing to unborn branch in "heads" view

From: Jakub Narebski <[email-masked]>
Date: Fri, 3 Feb 2012 22:33:05 +0100

On Mon, 30 Jan 2012, rajesh boyapati wrote:
> 
> Thank you for your Suggestions in finding the error in my case.
> Do you have a blog, so that, I can know your updates about gitweb.

No, I don't have a blog, though I might use Git page on Google+ to
announce larger changes.  

I am posting this to you to announce partial fix for your problem
in the form of patch to gitweb, which would hopefully made it to
next git version.

> 2012/1/30 Jakub Narebski <[email-masked]>
>> On Mon, 30 Jan 2012, rajesh boyapati wrote:
>>> 2012/1/28 Jakub Narebski <[email-masked]>
>>>> On Fri, 27 Jan 2012, rajesh boyapati wrote:

>>>>>     my $alternate = 1;
>>>>>     for (my $i = $from; $i <= $to; $i++) {
>>>>>         my $entry = $headlist->[$i];
>>>>>         my %ref = %$entry;
>>>>>         my $curr = $ref{'id'} eq $head;
>>>>>         if ($alternate) {
>>>>>             print "<tr class=\"dark\">\n";
>>>>>         } else {
>>>>>             print "<tr class=\"light\">\n";
>>>>>         }
>>>>>         $alternate ^= 1;
>>>>
>>>> Hmmmm... I see that we do not check if $head is defined here before using
>>>> it.  This can happen legitimately if we are on yet to be born orphan branch
>>>> (so $head, which should be named $head_at, is undefined) but there exist
>>>> other branches (so $headlist is not empty).

This was simple to fix.

>>>>>>> [2012-01-25 18:50:35,658] ERROR
>>>>>>> com.google.gerrit.httpd.gitweb.GitWebServlet : CGI: [Wed Jan 25
>>>>>>> 18:50:35 2012] gitweb.cgi: Use of uninitialized value $commit_id
>>>>>>> in open at /usr/lib/cgi-bin/gitweb.cgi line 2817.

>>>>> sub parse_commits {
>>>>>     my ($commit_id, $maxcount, $skip, $filename, @args) = @_;
>>>>>     my @cos;
>>>>>
>>>>>     $maxcount ||= 1;
>>>>>     $skip ||= 0;
>>>>>
>>>>>     local $/ = "\0";
>>>>>
>>>>>     open my $fd, "-|", git_cmd(), "rev-list",
>>>>>         "--header",
>>>>>         @args,
>>>>>         ("--max-count=" . $maxcount),
>>>>>         ("--skip=" . $skip),
>>>>>         @extra_options,
>>>>>         $commit_id,
>>>>>         "--",
>>>>>         ($filename ? ($filename) : ())
>>>>>         or die_error(500, "Open git-rev-list failed");

But I was not able to fix this, at least not currently.  I wrote a failing
test case for "commit" and similar views on unborn HEAD... but they fail
_without_ error message like the one quoted.

I'd have to go slower route of examining gitweb code in how it deals with
"invalid" HEAD (i.e. HEAD not pointing to commit, being on unborn branch).

>>> For my git projects on gerrit, our main branch name is "base".
>>> We don't have any code on "master" branch.
>>> May be the $HEAD is looking for master branch(or checked out branch in git
>>> project).--> In our case, "master" is an empty branch.
>>> Also, In the git projects, the HEAD file is pointing to "ref:
>>> refs/heads/master".
>>> So, I think that's the reason for errors.
>>>
>>> How can I make $HEAD to point to a branch other than "master"?.
>>>   a) I can do this by pointing HEAD file in git projects to other branch
>> [...]
>>>   b) Is there any way, other than doing above step (a) ?.
>>>      I mean I don't want to have a code on "master" branch and also I
>>>      don't want to point HEAD file in git projects to some other branch.
>>>      Do I need to make any modifications to "gitweb.cgi" for this?
>>
>> Now that I know the source of this error, I can write test case
>> for it, and fix it.  I'll try to do it soon.
>>
>> So finally what you would need for (b) is just upgrade gitweb.

And here is the patch:
-- >8 ------------ >8 ---
From: Jakub Narebski <[email-masked]>
Subject: [PATCH] gitweb: Deal with HEAD pointing to unborn branch in "heads"
 view

Gitweb has problems if HEAD points to an unborn branch, with no
commits on it yet, but there are other branches present (so it is not
newly initialized repository).

This can happen if non-bare repository (with default 'master' branch)
is updated not via committing but by other means like push to it, or
Gerrit.  It can happen also just after running "git checkout --orphan
<new branch>" but before creating any new commit on this branch.

This commit adds test and fixes the issue of being on unborn branch
(of HEAD not pointing to a commit) in "heads" view, and also in
"summary" view -- which includes "heads" excerpt as subview.

While at it rename local variable $head to $head_at, as it points to
current commit rather than current branch name (HEAD contents).

Reported-by: rajesh boyapati <[email-masked]>
Signed-off-by: Jakub Narebski <[email-masked]>
---
 gitweb/gitweb.perl                     |    4 ++--
 t/t9500-gitweb-standalone-no-errors.sh |    9 +++++++++
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 9cf7e71..1f0ec12 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -5570,7 +5570,7 @@ sub git_tags_body {
 
 sub git_heads_body {
 	# uses global variable $project
-	my ($headlist, $head, $from, $to, $extra) = @_;
+	my ($headlist, $head_at, $from, $to, $extra) = @_;
 	$from = 0 unless defined $from;
 	$to = $#{$headlist} if (!defined $to || $#{$headlist} < $to);
 
@@ -5579,7 +5579,7 @@ sub git_heads_body {
 	for (my $i = $from; $i <= $to; $i++) {
 		my $entry = $headlist->[$i];
 		my %ref = %$entry;
-		my $curr = $ref{'id'} eq $head;
+		my $curr = defined $head_at && $ref{'id'} eq $head_at;
 		if ($alternate) {
 			print "<tr class=\"dark\">\n";
 		} else {
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 0f771c6..81246a6 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -739,4 +739,13 @@ test_expect_success \
 	'echo "\$projects_list_group_categories = 1;" >>gitweb_config.perl &&
 	 gitweb_run'
 
+# ----------------------------------------------------------------------
+# unborn branches
+
+test_expect_success \
+	'unborn HEAD: "summary" page (with "heads" subview)' \
+	'git checkout orphan_branch || git checkout --orphan orphan_branch &&
+	 test_when_finished "git checkout master" &&
+	 gitweb_run "p=.git;a=summary"'
+
 test_done
-- 
1.7.9