3

Calling URL http://<gitweburl>/gitweb.cgi?p=<repo>;a=tree;f=<subdir>;hb=HEAD will show the tree of <repo> starting at <subdir>.

Calling URL http://<gitweburl>/gitweb.cgi?p=<repo>;a=snapshot;f=<subdir>;hb=HEAD will produce a 404.

Calling URL http://<gitweburl>/gitweb.cgi?p=<repo>.git;a=snapshot;h=HEAD will provide a snapshot of <repo> at HEAD revision.

I can't find the right syntax to make Gitweb give a snapshot starting at a sub-directory. I mean something leading to: $ git archive --format=tar --remote=<gituser>@<gitserver>:<repo> HEAD:<subdir>

I naively tried calling URL http://<gitweburl>/gitweb.cgi?p=<repo>;a=snapshot;h=HEAD;f=<subdir> but that results in an snapshot archive containing the whole repository.

After clicking around in the Gitweb web interface I found out that, changing to "tree" view and moving to <subdir> and then clicking "snapshot" uses an URL similar to this:

http://<gitweburl>?p=<repo>;a=snapshot;h=42a6503da6aaedc92bb3543e0b0de9b2de0aaae9;sf=tgz

Which delivers exactly what I want but I have no idea what this hash parameter h=... is. It's no commit id - I've checked. It must somehow identify <subdir>. But even if it does - this still doesn't help me because somebody just wanting a snapshot starting at/containing only <subdir> usually doesn't know this hash.

Any idea about how to get a sub-directory snapshot via Gitweb? Thanks in advance!


Addition:

Just found out: h=42a6503da6aaedc92bb3543e0b0de9b2de0aaae9 is the hash value associated to <subdir> visible by e.g. $ git ls-tree -r -t HEAD

So these 2 commands:

$ git archive --format=tar --remote=<gituser>@<gitserver>:<repo> HEAD:<subdir>

$ git archive --format=tar --remote=<gituser>@<gitserver>:<repo> 42a6503da6aaedc92bb3543e0b0de9b2de0aaae9

do the same which let's me think that HEAD:<subdir> and 42a6503da6aaedc92bb3543e0b0de9b2de0aaae9 are equivalent. Still I can't just substitute the hash in http://<gitweburl>?p=<repo>;a=snapshot;h=42a6503da6aaedc92bb3543e0b0de9b2de0aaae9;sf=tgz with HEAD:<subdir>. Calling this URL results in "400 - Invalid hash parameter"... so no real progress here.


As suggested by poke, a quick'n dirty hack to use URL http://<gitweburl>/gitweb.cgi?p=<repo>;a=snapshot;h=HEAD;f=<subdir>

$ diff -Naur gitweb.cgi.original gitweb.cgi.new 
--- gitweb.cgi.original 2012-09-28 00:50:47.000000000 +0200
+++ gitweb.cgi.new  2013-01-22 11:04:29.870532502 +0100
@@ -7029,6 +7029,9 @@

    my ($name, $prefix) = snapshot_name($project, $hash);
    my $filename = "$name$known_snapshot_formats{$format}{'suffix'}";
+   if ($file_name) {
+       $hash="$hash:$file_name"
+   }
    my $cmd = quote_command(
        git_cmd(), 'archive',
        "--format=$known_snapshot_formats{$format}{'format'}",
user1649119
  • 111
  • 4

2 Answers2

2

The h value in question is the id of the tree object you are currently looking at. A commit has a single root tree object, which you can see on Gitweb’s commit page. And each tree is a list of directory entries pointing to blobs (in case of files) or other tree objects.

So when you are navigating deeper into the tree, the h always represents the tree id. The hb value on the other hand is the commit id.

Unfortunately, Gitweb does not contain a nicer way to get the snapshot of a subdirectory, i.e. without knowing the tree hash but just the path. But it is probably possible to add some functionality to it that takes the f parameter into account and automatically gets the tree hash for you.

I just checked the source for this, and you might be able to have luck when modifying this part. I don’t know perl too well to tell you what exactly to do, but you could basically check if the $file_name variable is set and if that’s the case, just get the hash for $hash:$file_name. Then you set that to the new hash and everything could work.

poke
  • 369,085
  • 72
  • 557
  • 602
0

I was recently faced with a similar quest - to have gitweb produce an archive with listed object names (only one f= URL argument allowed, but we can pass %20 space-characters to list several objects). Here is my overall patch against gitweb.cgi as in OpenSuse 13.2 "git-web-2.1.4-13.1.x86_64" version.

Feel free to use and enjoy:

--- gitweb.cgi.orig     2015-03-13 13:42:29.000000000 +0100
+++ gitweb.cgi.snapshot-filenames-withoutDebug  2015-07-02 14:50:46.196000000 +0200
@@ -20,6 +20,11 @@
 use Time::HiRes qw(gettimeofday tv_interval);
 binmode STDOUT, ':utf8';

+# http://www.spinics.net/lists/git/msg241958.html
+if (!defined($CGI::VERSION) || $CGI::VERSION < 4.08) {
+       eval 'sub CGI::multi_param { CGI::param(@_) }'
+}
+
 our $t0 = [ gettimeofday() ];
 our $number_of_git_cmds = 0;

@@ -871,7 +876,7 @@

        while (my ($name, $symbol) = each %cgi_param_mapping) {
                if ($symbol eq 'opt') {
-                       $input_params{$name} = [ map { decode_utf8($_) } $cgi->param($symbol) ];
+                       $input_params{$name} = [ map { decode_utf8($_) } $cgi->multi_param($symbol) ];
                } else {
                        $input_params{$name} = decode_utf8($cgi->param($symbol));
                }
@@ -7324,6 +7329,15 @@
                die_error(403, "Unsupported snapshot format");
        }

+       if (!defined($hash)) {
+               $hash = "";
+               if ( $file_name && $file_name =~ /^([^:]*):(.*)$/ ) {
+                       $hash = "$1";
+                       $file_name = "$2";
+               }
+               if ( $hash eq "") { $hash = "HEAD"; }
+               printf STDERR "Defaulted hash to '$hash' ('h=' URL argument was missing)\n";
+       }
        my $type = git_get_type("$hash^{}");
        if (!$type) {
                die_error(404, 'Object does not exist');
@@ -7341,6 +7354,14 @@
                git_cmd(), 'archive',
                "--format=$known_snapshot_formats{$format}{'format'}",
                "--prefix=$prefix/", $hash);
+       if ($file_name) {
+               # To fetch several pathnames use space-separation, e.g.
+               # "...git-web?p=proj.git;a=snapshot;f=file1%20file2
+               # To fetch pathnames with spaces, escape them, e.g.
+               # "...git-web?p=proj.git;a=snapshot;f=file\%20name
+               $cmd .= " " . $file_name;
+       }
+
        if (exists $known_snapshot_formats{$format}{'compressor'}) {
                $cmd .= ' | ' . quote_command(@{$known_snapshot_formats{$format}{'compressor'}});
        }

UPDATE: This code drop was revised and extended with unit-testing etc. and PR'ed against the upstream gitweb... let's see how it goes ;) See more here : https://github.com/git/git/pull/206

Hope this helps, Jim Klimov

Jim Klimov
  • 187
  • 6