Gitweb snapshot of subdirectory
The calling URL will http://<gitweburl>/gitweb.cgi?p=<repo>;a=tree;f=<subdir>;hb=HEAD
display a tree <repo>
starting at <subdir>
.
The calling url http://<gitweburl>/gitweb.cgi?p=<repo>;a=snapshot;f=<subdir>;hb=HEAD
will produce a 404.
The calling URL http://<gitweburl>/gitweb.cgi?p=<repo>.git;a=snapshot;h=HEAD
will provide a snapshot <repo>
in the HEAD revision.
I can't seem to find the correct syntax to get Gitweb to give a snapshot starting from a subdirectory. I mean something leading to:$ git archive --format=tar --remote=<gituser>@<gitserver>:<repo> HEAD:<subdir>
I was naively trying to call the url http://<gitweburl>/gitweb.cgi?p=<repo>;a=snapshot;h=HEAD;f=<subdir>
but that results in a snapshot archive containing the entire repository .
After clicking on the Gitweb web interface, I found out that by going to the "tree" view and navigating to <subdir>
, and then clicking "snapshot", use a URL similar to this one:
http://<gitweburl>?p=<repo>;a=snapshot;h=42a6503da6aaedc92bb3543e0b0de9b2de0aaae9;sf=tgz
Which provides exactly what I want, but I have no idea what this hash parameter is h=...
. This is not a commit id - I checked. He has to define in some way <subdir>
. But even if it does - it still doesn't help me because someone just wants a snapshot starting with / containing only <subdir>
usually doesn't know this hash.
Any idea on how to get a snapshot of a subdirectory via Gitweb? Thanks in advance!
Addition:
Just figured out: h=42a6503da6aaedc92bb3543e0b0de9b2de0aaae9
is the hash value associated with <subdir>
, visible for example.$ git ls-tree -r -t HEAD
So these two commands:
$ git archive --format=tar --remote=<gituser>@<gitserver>:<repo> HEAD:<subdir>
$ git archive --format=tar --remote=<gituser>@<gitserver>:<repo> 42a6503da6aaedc92bb3543e0b0de9b2de0aaae9
doing the same thing, which makes me think that HEAD:<subdir>
and are 42a6503da6aaedc92bb3543e0b0de9b2de0aaae9
equivalent. However, I cannot simply replace the hash in http://<gitweburl>?p=<repo>;a=snapshot;h=42a6503da6aaedc92bb3543e0b0de9b2de0aaae9;sf=tgz
with HEAD:<subdir>
. Calling that url results in "400 - Invalid hash parameter" ... so no real progress here.
As suggested by poke, a quick 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'}",
source to share
The value h
is the identifier of the tree object you are currently looking at. The end has one root tree object, which you can see on the Gitwebs commit page. And each tree is a list of directory entries pointing to blobs (in the case of files) or other tree objects.
So when you move deeper into the tree, it h
always represents the tree ID. On the other hand, the value hb
is the commit ID.
Unfortunately, Gitweb does not provide a better way to get a snapshot of a subdirectory, i.e. without knowing the tree hash, just for the path. But it is probably possible to add some functions to it that take the parameter into account f
and automatically get the hash of the head for you.
I just checked the source for this and you might be happy to change this part . I don't know perl very well to tell you exactly what to do, but you can basically check if a variable is set $file_name
, and if so, just get a hash for $hash:$file_name
. Then you set this to a new hash and everything can work.
source to share
I recently ran into a similar task - to have gitweb create an archive with object names (only one f = URL argument is allowed, but we can pass% 20 spaces to list multiple objects). Here is my general patch against gitweb.cgi as in OpenSuse 13.2 "git-web-2.1.4-13.1.x86_64".
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 drop in code has been revisited and extended with unit testing, etc. and PR'ed against upstream gitweb ... let's see how it goes;) More details here: https://github.com/git/git/pull/206
Hope this helps, Jim Klimov
source to share