Merge branch 'lt/gitweb' into next

* lt/gitweb:
  gitweb: Declare global variables with "our"
  gitweb: Enable tree (directory) history display
  gitweb: optimize per-file history generation
  git object hash cleanups
  revision.c: --full-history fix.
  Fix errno usage in connect.c
  Minor documentation fixup.
  git-svn: allow a local target directory to be specified for init
  don't load objects needlessly when repacking
This commit is contained in:
Junio C Hamano
2006-07-01 18:29:59 -07:00
7 changed files with 162 additions and 120 deletions

View File

@@ -15,9 +15,9 @@ SYNOPSIS
DESCRIPTION
-----------
Updates the index file for given paths, or all modified files if
'-a' is specified, and makes a commit object. The command
VISUAL and EDITOR environment variables to edit the commit log
message.
'-a' is specified, and makes a commit object. The command specified
by either the VISUAL or EDITOR environment variables are used to edit
the commit log message.
Several environment variable are used during commits. They are
documented in gitlink:git-commit-tree[1].

View File

@@ -328,7 +328,7 @@ static enum protocol get_protocol(const char *name)
*/
static int git_tcp_connect_sock(char *host)
{
int sockfd = -1;
int sockfd = -1, saved_errno = 0;
char *colon, *end;
const char *port = STR(DEFAULT_GIT_PORT);
struct addrinfo hints, *ai0, *ai;
@@ -362,9 +362,12 @@ static int git_tcp_connect_sock(char *host)
for (ai0 = ai; ai; ai = ai->ai_next) {
sockfd = socket(ai->ai_family,
ai->ai_socktype, ai->ai_protocol);
if (sockfd < 0)
if (sockfd < 0) {
saved_errno = errno;
continue;
}
if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
saved_errno = errno;
close(sockfd);
sockfd = -1;
continue;
@@ -375,7 +378,7 @@ static int git_tcp_connect_sock(char *host)
freeaddrinfo(ai0);
if (sockfd < 0)
die("unable to connect a socket (%s)", strerror(errno));
die("unable to connect a socket (%s)", strerror(saved_errno));
return sockfd;
}
@@ -387,7 +390,7 @@ static int git_tcp_connect_sock(char *host)
*/
static int git_tcp_connect_sock(char *host)
{
int sockfd = -1;
int sockfd = -1, saved_errno = 0;
char *colon, *end;
char *port = STR(DEFAULT_GIT_PORT), *ep;
struct hostent *he;
@@ -426,8 +429,10 @@ static int git_tcp_connect_sock(char *host)
for (ap = he->h_addr_list; *ap; ap++) {
sockfd = socket(he->h_addrtype, SOCK_STREAM, 0);
if (sockfd < 0)
if (sockfd < 0) {
saved_errno = errno;
continue;
}
memset(&sa, 0, sizeof sa);
sa.sin_family = he->h_addrtype;
@@ -435,6 +440,7 @@ static int git_tcp_connect_sock(char *host)
memcpy(&sa.sin_addr, *ap, he->h_length);
if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
saved_errno = errno;
close(sockfd);
sockfd = -1;
continue;
@@ -443,7 +449,7 @@ static int git_tcp_connect_sock(char *host)
}
if (sockfd < 0)
die("unable to connect a socket (%s)", strerror(errno));
die("unable to connect a socket (%s)", strerror(saved_errno));
return sockfd;
}

View File

@@ -264,9 +264,19 @@ when you have upgraded your tools and habits to use refs/remotes/$GIT_SVN
}
sub init {
$SVN_URL = shift or die "SVN repository location required " .
my $url = shift or die "SVN repository location required " .
"as a command-line argument\n";
$SVN_URL =~ s!/+$!!; # strip trailing slash
$url =~ s!/+$!!; # strip trailing slash
if (my $repo_path = shift) {
unless (-d $repo_path) {
mkpath([$repo_path]);
}
$GIT_DIR = $ENV{GIT_DIR} = $repo_path . "/.git";
init_vars();
}
$SVN_URL = $url;
unless (-d $GIT_DIR) {
my @init_db = ('git-init-db');
push @init_db, "--template=$_template" if defined $_template;

View File

@@ -16,21 +16,21 @@ use Encode;
use Fcntl ':mode';
binmode STDOUT, ':utf8';
my $cgi = new CGI;
my $version = "267";
my $my_url = $cgi->url();
my $my_uri = $cgi->url(-absolute => 1);
my $rss_link = "";
our $cgi = new CGI;
our $version = "267";
our $my_url = $cgi->url();
our $my_uri = $cgi->url(-absolute => 1);
our $rss_link = "";
# location of the git-core binaries
my $gitbin = "/usr/bin";
our $gitbin = "/usr/bin";
# absolute fs-path which will be prepended to the project path
#my $projectroot = "/pub/scm";
my $projectroot = "/home/kay/public_html/pub/scm";
#our $projectroot = "/pub/scm";
our $projectroot = "/home/kay/public_html/pub/scm";
# version of the git-core binaries
my $git_version = qx($gitbin/git --version);
our $git_version = qx($gitbin/git --version);
if ($git_version =~ m/git version (.*)$/) {
$git_version = $1;
} else {
@@ -38,32 +38,31 @@ if ($git_version =~ m/git version (.*)$/) {
}
# location for temporary files needed for diffs
my $git_temp = "/tmp/gitweb";
our $git_temp = "/tmp/gitweb";
# target of the home link on top of all pages
my $home_link = $my_uri;
our $home_link = $my_uri;
# html text to include at home page
my $home_text = "indextext.html";
our $home_text = "indextext.html";
# URI of default stylesheet
my $stylesheet = "gitweb.css";
our $stylesheet = "gitweb.css";
# source of projects list
#my $projects_list = $projectroot;
my $projects_list = "index/index.aux";
#our $projects_list = $projectroot;
our $projects_list = "index/index.aux";
# default blob_plain mimetype and default charset for text/plain blob
my $default_blob_plain_mimetype = 'text/plain';
my $default_text_plain_charset = undef;
our $default_blob_plain_mimetype = 'text/plain';
our $default_text_plain_charset = undef;
# file to use for guessing MIME types before trying /etc/mime.types
# (relative to the current git repository)
my $mimetypes_file = undef;
our $mimetypes_file = undef;
# input validation and dispatch
my $action = $cgi->param('a');
our $action = $cgi->param('a');
if (defined $action) {
if ($action =~ m/[^0-9a-zA-Z\.\-_]/) {
undef $action;
@@ -78,7 +77,7 @@ if (defined $action) {
}
}
my $order = $cgi->param('o');
our $order = $cgi->param('o');
if (defined $order) {
if ($order =~ m/[^0-9a-zA-Z_]/) {
undef $order;
@@ -86,7 +85,7 @@ if (defined $order) {
}
}
my $project = ($cgi->param('p') || $ENV{'PATH_INFO'});
our $project = ($cgi->param('p') || $ENV{'PATH_INFO'});
if (defined $project) {
$project =~ s|^/||; $project =~ s|/$||;
$project = validate_input($project);
@@ -109,7 +108,7 @@ if (defined $project) {
exit;
}
my $file_name = $cgi->param('f');
our $file_name = $cgi->param('f');
if (defined $file_name) {
$file_name = validate_input($file_name);
if (!defined($file_name)) {
@@ -117,7 +116,7 @@ if (defined $file_name) {
}
}
my $hash = $cgi->param('h');
our $hash = $cgi->param('h');
if (defined $hash) {
$hash = validate_input($hash);
if (!defined($hash)) {
@@ -125,7 +124,7 @@ if (defined $hash) {
}
}
my $hash_parent = $cgi->param('hp');
our $hash_parent = $cgi->param('hp');
if (defined $hash_parent) {
$hash_parent = validate_input($hash_parent);
if (!defined($hash_parent)) {
@@ -133,7 +132,7 @@ if (defined $hash_parent) {
}
}
my $hash_base = $cgi->param('hb');
our $hash_base = $cgi->param('hb');
if (defined $hash_base) {
$hash_base = validate_input($hash_base);
if (!defined($hash_base)) {
@@ -141,7 +140,7 @@ if (defined $hash_base) {
}
}
my $page = $cgi->param('pg');
our $page = $cgi->param('pg');
if (defined $page) {
if ($page =~ m/[^0-9]$/) {
undef $page;
@@ -149,7 +148,7 @@ if (defined $page) {
}
}
my $searchtext = $cgi->param('s');
our $searchtext = $cgi->param('s');
if (defined $searchtext) {
if ($searchtext =~ m/[^a-zA-Z0-9_\.\/\-\+\:\@ ]/) {
undef $searchtext;
@@ -1676,6 +1675,7 @@ sub git_tree {
"</td>\n" .
"<td class=\"link\">" .
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$t_hash$base_key;f=$base$t_name")}, "tree") .
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=history;h=$hash_base;f=$base$t_name")}, "history") .
"</td>\n";
}
print "</tr>\n";
@@ -2295,16 +2295,13 @@ sub git_history {
"</div>\n";
print "<div class=\"page_path\"><b>/" . esc_html($file_name) . "</b><br/></div>\n";
open my $fd, "-|", "$gitbin/git-rev-list $hash | $gitbin/git-diff-tree -r --stdin -- \'$file_name\'";
my $commit;
open my $fd, "-|",
"$gitbin/git-rev-list --full-history $hash -- \'$file_name\'";
print "<table cellspacing=\"0\">\n";
my $alternate = 0;
while (my $line = <$fd>) {
if ($line =~ m/^([0-9a-fA-F]{40})/){
$commit = $1;
next;
}
if ($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)\t(.*)$/ && (defined $commit)) {
my $commit = $1;
my %co = git_read_commit($commit);
if (!%co) {
next;
@@ -2336,7 +2333,6 @@ sub git_history {
}
print "</td>\n" .
"</tr>\n";
undef $commit;
}
}
print "</table>\n";

115
object.c
View File

@@ -5,88 +5,97 @@
#include "commit.h"
#include "tag.h"
static struct object **objs;
static int nr_objs, obj_allocs;
static struct object **obj_hash;
static int nr_objs, obj_hash_size;
unsigned int get_max_object_index(void)
{
return obj_allocs;
return obj_hash_size;
}
struct object *get_indexed_object(unsigned int idx)
{
return objs[idx];
return obj_hash[idx];
}
const char *type_names[] = {
"none", "blob", "tree", "commit", "bad"
};
static unsigned int hash_obj(struct object *obj, unsigned int n)
{
unsigned int hash = *(unsigned int *)obj->sha1;
return hash % n;
}
static void insert_obj_hash(struct object *obj, struct object **hash, unsigned int size)
{
int j = hash_obj(obj, size);
while (hash[j]) {
j++;
if (j >= size)
j = 0;
}
hash[j] = obj;
}
static int hashtable_index(const unsigned char *sha1)
{
unsigned int i;
memcpy(&i, sha1, sizeof(unsigned int));
return (int)(i % obj_allocs);
}
static int find_object(const unsigned char *sha1)
{
int i;
if (!objs)
return -1;
i = hashtable_index(sha1);
while (objs[i]) {
if (memcmp(sha1, objs[i]->sha1, 20) == 0)
return i;
i++;
if (i == obj_allocs)
i = 0;
}
return -1 - i;
return (int)(i % obj_hash_size);
}
struct object *lookup_object(const unsigned char *sha1)
{
int pos = find_object(sha1);
if (pos >= 0)
return objs[pos];
return NULL;
int i;
struct object *obj;
if (!obj_hash)
return NULL;
i = hashtable_index(sha1);
while ((obj = obj_hash[i]) != NULL) {
if (!memcmp(sha1, obj->sha1, 20))
break;
i++;
if (i == obj_hash_size)
i = 0;
}
return obj;
}
static void grow_object_hash(void)
{
int i;
int new_hash_size = obj_hash_size < 32 ? 32 : 2 * obj_hash_size;
struct object **new_hash;
new_hash = calloc(new_hash_size, sizeof(struct object *));
for (i = 0; i < obj_hash_size; i++) {
struct object *obj = obj_hash[i];
if (!obj)
continue;
insert_obj_hash(obj, new_hash, new_hash_size);
}
free(obj_hash);
obj_hash = new_hash;
obj_hash_size = new_hash_size;
}
void created_object(const unsigned char *sha1, struct object *obj)
{
int pos;
obj->parsed = 0;
memcpy(obj->sha1, sha1, 20);
obj->type = TYPE_NONE;
obj->used = 0;
obj->type = TYPE_NONE;
obj->flags = 0;
memcpy(obj->sha1, sha1, 20);
if (obj_allocs - 1 <= nr_objs * 2) {
int i, count = obj_allocs;
obj_allocs = (obj_allocs < 32 ? 32 : 2 * obj_allocs);
objs = xrealloc(objs, obj_allocs * sizeof(struct object *));
memset(objs + count, 0, (obj_allocs - count)
* sizeof(struct object *));
for (i = 0; i < obj_allocs; i++)
if (objs[i]) {
int j = find_object(objs[i]->sha1);
if (j != i) {
j = -1 - j;
objs[j] = objs[i];
objs[i] = NULL;
}
}
}
if (obj_hash_size - 1 <= nr_objs * 2)
grow_object_hash();
pos = find_object(sha1);
if (pos >= 0)
die("Inserting %s twice\n", sha1_to_hex(sha1));
pos = -pos-1;
objs[pos] = obj;
insert_obj_hash(obj, obj_hash, obj_hash_size);
nr_objs++;
}

View File

@@ -970,11 +970,12 @@ struct unpacked {
* one.
*/
static int try_delta(struct unpacked *trg, struct unpacked *src,
struct delta_index *src_index, unsigned max_depth)
unsigned max_depth)
{
struct object_entry *trg_entry = trg->entry;
struct object_entry *src_entry = src->entry;
unsigned long size, src_size, delta_size, sizediff, max_size;
unsigned long trg_size, src_size, delta_size, sizediff, max_size, sz;
char type[10];
void *delta_buf;
/* Don't bother doing diffs between different types */
@@ -1009,19 +1010,38 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
return 0;
/* Now some size filtering heuristics. */
size = trg_entry->size;
max_size = size/2 - 20;
trg_size = trg_entry->size;
max_size = trg_size/2 - 20;
max_size = max_size * (max_depth - src_entry->depth) / max_depth;
if (max_size == 0)
return 0;
if (trg_entry->delta && trg_entry->delta_size <= max_size)
max_size = trg_entry->delta_size-1;
src_size = src_entry->size;
sizediff = src_size < size ? size - src_size : 0;
sizediff = src_size < trg_size ? trg_size - src_size : 0;
if (sizediff >= max_size)
return 0;
delta_buf = create_delta(src_index, trg->data, size, &delta_size, max_size);
/* Load data if not already done */
if (!trg->data) {
trg->data = read_sha1_file(trg_entry->sha1, type, &sz);
if (sz != trg_size)
die("object %s inconsistent object length (%lu vs %lu)",
sha1_to_hex(trg_entry->sha1), sz, trg_size);
}
if (!src->data) {
src->data = read_sha1_file(src_entry->sha1, type, &sz);
if (sz != src_size)
die("object %s inconsistent object length (%lu vs %lu)",
sha1_to_hex(src_entry->sha1), sz, src_size);
}
if (!src->index) {
src->index = create_delta_index(src->data, src_size);
if (!src->index)
die("out of memory");
}
delta_buf = create_delta(src->index, trg->data, trg_size, &delta_size, max_size);
if (!delta_buf)
return 0;
@@ -1054,8 +1074,6 @@ static void find_deltas(struct object_entry **list, int window, int depth)
while (--i >= 0) {
struct object_entry *entry = list[i];
struct unpacked *n = array + idx;
unsigned long size;
char type[10];
int j;
if (!entry->preferred_base)
@@ -1082,11 +1100,8 @@ static void find_deltas(struct object_entry **list, int window, int depth)
free_delta_index(n->index);
n->index = NULL;
free(n->data);
n->data = NULL;
n->entry = entry;
n->data = read_sha1_file(entry->sha1, type, &size);
if (size != entry->size)
die("object %s inconsistent object length (%lu vs %lu)",
sha1_to_hex(entry->sha1), size, entry->size);
j = window;
while (--j > 0) {
@@ -1097,7 +1112,7 @@ static void find_deltas(struct object_entry **list, int window, int depth)
m = array + other_idx;
if (!m->entry)
break;
if (try_delta(n, m, m->index, depth) < 0)
if (try_delta(n, m, depth) < 0)
break;
}
/* if we made n a delta, and if n is already at max
@@ -1107,10 +1122,6 @@ static void find_deltas(struct object_entry **list, int window, int depth)
if (entry->delta && depth <= entry->depth)
continue;
n->index = create_delta_index(n->data, size);
if (!n->index)
die("out of memory");
idx++;
if (idx >= window)
idx = 0;

View File

@@ -280,7 +280,7 @@ int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1)
static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
{
struct commit_list **pp, *parent;
int tree_changed = 0;
int tree_changed = 0, tree_same = 0;
if (!commit->tree)
return;
@@ -298,6 +298,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
parse_commit(p);
switch (rev_compare_tree(revs, p->tree, commit->tree)) {
case REV_TREE_SAME:
tree_same = 1;
if (!revs->simplify_history || (p->object.flags & UNINTERESTING)) {
/* Even if a merge with an uninteresting
* side branch brought the entire change
@@ -334,7 +335,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
}
die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1));
}
if (tree_changed)
if (tree_changed && !tree_same)
commit->object.flags |= TREECHANGE;
}
@@ -895,6 +896,8 @@ static int rewrite_one(struct rev_info *revs, struct commit **pp)
struct commit *p = *pp;
if (!revs->limited)
add_parents_to_list(revs, p, &revs->commits);
if (p->parents && p->parents->next)
return 0;
if (p->object.flags & (TREECHANGE | UNINTERESTING))
return 0;
if (!p->parents)
@@ -987,8 +990,15 @@ struct commit *get_revision(struct rev_info *revs)
commit->parents && commit->parents->next)
continue;
if (revs->prune_fn && revs->dense) {
if (!(commit->object.flags & TREECHANGE))
continue;
/* Commit without changes? */
if (!(commit->object.flags & TREECHANGE)) {
/* drop merges unless we want parenthood */
if (!revs->parents)
continue;
/* non-merge - always ignore it */
if (commit->parents && !commit->parents->next)
continue;
}
if (revs->parents)
rewrite_parents(revs, commit);
}