Merge branch 'master' of git://repo.or.cz/alt-git

This commit is contained in:
Johannes Sixt
2009-07-16 09:31:45 +02:00
23 changed files with 323 additions and 220 deletions

View File

@@ -14,6 +14,7 @@ SYNOPSIS
[ \--max-age=timestamp ]
[ \--min-age=timestamp ]
[ \--sparse ]
[ \--merges ]
[ \--no-merges ]
[ \--first-parent ]
[ \--remove-empty ]

View File

@@ -201,6 +201,10 @@ endif::git-rev-list[]
Stop when a given path disappears from the tree.
--merges::
Print only merge commits.
--no-merges::
Do not print commits with more than one parent.

View File

@@ -61,6 +61,8 @@ all::
#
# Define NO_LIBGEN_H if you don't have libgen.h.
#
# Define NEEDS_LIBGEN if your libgen needs -lgen when linking
#
# Define NO_SYS_SELECT_H if you don't have sys/select.h.
#
# Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.
@@ -828,18 +830,31 @@ ifeq ($(uname_S),GNU)
NO_STRLCPY=YesPlease
NO_MKSTEMPS = YesPlease
endif
ifeq ($(uname_S),IRIX)
NO_SETENV = YesPlease
NO_UNSETENV = YesPlease
NO_STRCASESTR = YesPlease
NO_MEMMEM = YesPlease
NO_MKSTEMPS = YesPlease
NO_MKDTEMP = YesPlease
NO_MMAP = YesPlease
NO_EXTERNAL_GREP = UnfortunatelyYes
SNPRINTF_RETURNS_BOGUS = YesPlease
SHELL_PATH = /usr/gnu/bin/bash
NEEDS_LIBGEN = YesPlease
endif
ifeq ($(uname_S),IRIX64)
NO_IPV6=YesPlease
NO_SETENV=YesPlease
NO_UNSETENV = YesPlease
NO_STRCASESTR=YesPlease
NO_MEMMEM = YesPlease
NO_MKSTEMPS = YesPlease
NO_STRLCPY = YesPlease
NO_SOCKADDR_STORAGE=YesPlease
NO_MKDTEMP = YesPlease
NO_MMAP = YesPlease
NO_EXTERNAL_GREP = UnfortunatelyYes
SNPRINTF_RETURNS_BOGUS = YesPlease
SHELL_PATH=/usr/gnu/bin/bash
BASIC_CFLAGS += -DPATH_MAX=1024
# for now, build 32-bit version
BASIC_LDFLAGS += -L/usr/lib32
NEEDS_LIBGEN = YesPlease
endif
ifeq ($(uname_S),HP-UX)
NO_IPV6=YesPlease
@@ -1019,6 +1034,9 @@ ifdef NEEDS_LIBICONV
endif
EXTLIBS += $(ICONV_LINK) -liconv
endif
ifdef NEEDS_LIBGEN
EXTLIBS += -lgen
endif
ifdef NEEDS_SOCKET
EXTLIBS += -lsocket
endif
@@ -1641,10 +1659,11 @@ ifneq (,$X)
endif
bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
{ $(RM) "$$execdir/git$X" && \
{ test "$$bindir/" = "$$execdir/" || \
{ $(RM) "$$execdir/git$X" && \
test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
ln "$$bindir/git$X" "$$execdir/git$X" 2>/dev/null || \
cp "$$bindir/git$X" "$$execdir/git$X"; } && \
cp "$$bindir/git$X" "$$execdir/git$X"; } ; } && \
{ for p in $(BUILT_INS); do \
$(RM) "$$execdir/$$p" && \
ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \

View File

@@ -97,35 +97,6 @@ static void treat_gitlinks(const char **pathspec)
}
}
static void fill_directory(struct dir_struct *dir, const char **pathspec,
int ignored_too)
{
const char *path, *base;
int baselen;
/* Set up the default git porcelain excludes */
memset(dir, 0, sizeof(*dir));
if (!ignored_too) {
dir->flags |= DIR_COLLECT_IGNORED;
setup_standard_excludes(dir);
}
/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
*/
baselen = common_prefix(pathspec);
path = ".";
base = "";
if (baselen)
path = base = xmemdupz(*pathspec, baselen);
/* Read the directory and prune it */
read_directory(dir, path, base, baselen, pathspec);
if (pathspec)
prune_directory(dir, pathspec, baselen);
}
static void refresh(int verbose, const char **pathspec)
{
char *seen;
@@ -343,9 +314,21 @@ int cmd_add(int argc, const char **argv, const char *prefix)
die("index file corrupt");
treat_gitlinks(pathspec);
if (add_new_files)
if (add_new_files) {
int baselen;
/* Set up the default git porcelain excludes */
memset(&dir, 0, sizeof(dir));
if (!ignored_too) {
dir.flags |= DIR_COLLECT_IGNORED;
setup_standard_excludes(&dir);
}
/* This picks up the paths that are not tracked */
fill_directory(&dir, pathspec, ignored_too);
baselen = fill_directory(&dir, pathspec);
if (pathspec)
prune_directory(&dir, pathspec, baselen);
}
if (refresh_only) {
refresh(verbose, pathspec);

View File

@@ -33,7 +33,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
struct strbuf directory = STRBUF_INIT;
struct dir_struct dir;
const char *path, *base;
static const char **pathspec;
struct strbuf buf = STRBUF_INIT;
const char *qname;
@@ -78,16 +77,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
pathspec = get_pathspec(prefix, argv);
read_cache();
/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
*/
baselen = common_prefix(pathspec);
path = ".";
base = "";
if (baselen)
path = base = xmemdupz(*pathspec, baselen);
read_directory(&dir, path, base, baselen, pathspec);
fill_directory(&dir, pathspec);
if (pathspec)
seen = xmalloc(argc > 0 ? argc : 1);

View File

@@ -400,14 +400,14 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
/*
* We would want to bypass the object transfer altogether if
* everything we are going to fetch already exists and connected
* everything we are going to fetch already exists and is connected
* locally.
*
* The refs we are going to fetch are in to_fetch (nr_heads in
* total). If running
* The refs we are going to fetch are in ref_map. If running
*
* $ git rev-list --objects to_fetch[0] to_fetch[1] ... --not --all
* $ git rev-list --objects --stdin --not --all
*
* (feeding all the refs in ref_map on its standard input)
* does not error out, that means everything reachable from the
* refs we are going to fetch exists and is connected to some of
* our existing refs.
@@ -416,8 +416,9 @@ static int quickfetch(struct ref *ref_map)
{
struct child_process revlist;
struct ref *ref;
char **argv;
int i, err;
int err;
const char *argv[] = {"rev-list",
"--quiet", "--objects", "--stdin", "--not", "--all", NULL};
/*
* If we are deepening a shallow clone we already have these
@@ -429,34 +430,46 @@ static int quickfetch(struct ref *ref_map)
if (depth)
return -1;
for (i = 0, ref = ref_map; ref; ref = ref->next)
i++;
if (!i)
if (!ref_map)
return 0;
argv = xmalloc(sizeof(*argv) * (i + 6));
i = 0;
argv[i++] = xstrdup("rev-list");
argv[i++] = xstrdup("--quiet");
argv[i++] = xstrdup("--objects");
for (ref = ref_map; ref; ref = ref->next)
argv[i++] = xstrdup(sha1_to_hex(ref->old_sha1));
argv[i++] = xstrdup("--not");
argv[i++] = xstrdup("--all");
argv[i++] = NULL;
memset(&revlist, 0, sizeof(revlist));
revlist.argv = (const char**)argv;
revlist.argv = argv;
revlist.git_cmd = 1;
revlist.no_stdin = 1;
revlist.no_stdout = 1;
revlist.no_stderr = 1;
err = run_command(&revlist);
revlist.in = -1;
for (i = 0; argv[i]; i++)
free(argv[i]);
free(argv);
return err;
err = start_command(&revlist);
if (err) {
error("could not run rev-list");
return err;
}
/*
* If rev-list --stdin encounters an unknown commit, it terminates,
* which will cause SIGPIPE in the write loop below.
*/
sigchain_push(SIGPIPE, SIG_IGN);
for (ref = ref_map; ref; ref = ref->next) {
if (write_in_full(revlist.in, sha1_to_hex(ref->old_sha1), 40) < 0 ||
write_in_full(revlist.in, "\n", 1) < 0) {
if (errno != EPIPE && errno != EINVAL)
error("failed write to rev-list: %s", strerror(errno));
err = -1;
break;
}
}
if (close(revlist.in)) {
error("failed to close rev-list's stdin: %s", strerror(errno));
err = -1;
}
sigchain_pop(SIGPIPE);
return finish_command(&revlist) || err;
}
static int fetch_refs(struct transport *transport, struct ref *ref_map)

View File

@@ -161,12 +161,7 @@ static void show_files(struct dir_struct *dir, const char *prefix)
/* For cached/deleted files we don't need to even do the readdir */
if (show_others || show_killed) {
const char *path = ".", *base = "";
int baselen = prefix_len;
if (baselen)
path = base = prefix;
read_directory(dir, path, base, baselen, pathspec);
fill_directory(dir, pathspec);
if (show_others)
show_other_files(dir);
if (show_killed)

View File

@@ -329,7 +329,8 @@ static int update_one(struct cache_tree *it,
entlen = pathlen - baselen;
}
if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1))
return error("invalid object %s", sha1_to_hex(sha1));
return error("invalid object %06o %s for '%.*s'",
mode, sha1_to_hex(sha1), entlen+baselen, path);
if (ce->ce_flags & CE_REMOVE)
continue; /* entry being removed */

10
cache.h
View File

@@ -744,7 +744,17 @@ struct checkout {
};
extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
struct cache_def {
char path[PATH_MAX + 1];
int len;
int flags;
int track_flags;
int prefix_len_stat_func;
};
extern int has_symlink_leading_path(const char *name, int len);
extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
extern int has_symlink_or_noent_leading_path(const char *name, int len);
extern int has_dirs_only_path(const char *name, int len, int prefix_len);
extern void invalidate_lstat_cache(const char *name, int len);

View File

@@ -485,6 +485,12 @@ AC_CHECK_LIB([resolv], [hstrerror],
AC_SUBST(NEEDS_RESOLV)
test -n "$NEEDS_RESOLV" && LIBS="$LIBS -lresolv"
AC_CHECK_LIB([gen], [basename],
[NEEDS_LIBGEN=],
[NEEDS_LIBGEN=YesPlease])
AC_SUBST(NEEDS_LIBGEN)
test -n "$NEEDS_LIBGEN" && LIBS="$LIBS -lgen"
## Checks for header files.
AC_MSG_NOTICE([CHECKS for header files])
#

View File

@@ -1114,7 +1114,7 @@ _git_ls_tree ()
__git_log_common_options="
--not --all
--branches --tags --remotes
--first-parent --no-merges
--first-parent --merges --no-merges
--max-count=
--max-age= --since= --after=
--min-age= --until= --before=

111
dir.c
View File

@@ -14,12 +14,11 @@ struct path_simplify {
const char *path;
};
static int read_directory_recursive(struct dir_struct *dir,
const char *path, const char *base, int baselen,
static int read_directory_recursive(struct dir_struct *dir, const char *path, int len,
int check_only, const struct path_simplify *simplify);
static int get_dtype(struct dirent *de, const char *path);
static int get_dtype(struct dirent *de, const char *path, int len);
int common_prefix(const char **pathspec)
static int common_prefix(const char **pathspec)
{
const char *path, *slash, *next;
int prefix;
@@ -52,6 +51,26 @@ int common_prefix(const char **pathspec)
return prefix;
}
int fill_directory(struct dir_struct *dir, const char **pathspec)
{
const char *path;
int len;
/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
*/
len = common_prefix(pathspec);
path = "";
if (len)
path = xmemdupz(*pathspec, len);
/* Read the directory and prune it */
read_directory(dir, path, len, pathspec);
return len;
}
/*
* Does 'match' match the given name?
* A match is found if
@@ -307,7 +326,7 @@ static int excluded_1(const char *pathname,
if (x->flags & EXC_FLAG_MUSTBEDIR) {
if (*dtype == DT_UNKNOWN)
*dtype = get_dtype(NULL, pathname);
*dtype = get_dtype(NULL, pathname, pathlen);
if (*dtype != DT_DIR)
continue;
}
@@ -505,7 +524,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
/* This is the "show_other_directories" case */
if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
return show_directory;
if (!read_directory_recursive(dir, dirname, dirname, len, 1, simplify))
if (!read_directory_recursive(dir, dirname, len, 1, simplify))
return ignore_directory;
return show_directory;
}
@@ -547,11 +566,52 @@ static int in_pathspec(const char *path, int len, const struct path_simplify *si
return 0;
}
static int get_dtype(struct dirent *de, const char *path)
static int get_index_dtype(const char *path, int len)
{
int pos;
struct cache_entry *ce;
ce = cache_name_exists(path, len, 0);
if (ce) {
if (!ce_uptodate(ce))
return DT_UNKNOWN;
if (S_ISGITLINK(ce->ce_mode))
return DT_DIR;
/*
* Nobody actually cares about the
* difference between DT_LNK and DT_REG
*/
return DT_REG;
}
/* Try to look it up as a directory */
pos = cache_name_pos(path, len);
if (pos >= 0)
return DT_UNKNOWN;
pos = -pos-1;
while (pos < active_nr) {
ce = active_cache[pos++];
if (strncmp(ce->name, path, len))
break;
if (ce->name[len] > '/')
break;
if (ce->name[len] < '/')
continue;
if (!ce_uptodate(ce))
break; /* continue? */
return DT_DIR;
}
return DT_UNKNOWN;
}
static int get_dtype(struct dirent *de, const char *path, int len)
{
int dtype = de ? DTYPE(de) : DT_UNKNOWN;
struct stat st;
if (dtype != DT_UNKNOWN)
return dtype;
dtype = get_index_dtype(path, len);
if (dtype != DT_UNKNOWN)
return dtype;
if (lstat(path, &st))
@@ -574,15 +634,15 @@ static int get_dtype(struct dirent *de, const char *path)
* Also, we ignore the name ".git" (even if it is not a directory).
* That likely will not change.
*/
static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
static int read_directory_recursive(struct dir_struct *dir, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
{
DIR *fdir = opendir(*path ? path : ".");
DIR *fdir = opendir(*base ? base : ".");
int contents = 0;
if (fdir) {
struct dirent *de;
char fullname[PATH_MAX + 1];
memcpy(fullname, base, baselen);
char path[PATH_MAX + 1];
memcpy(path, base, baselen);
while ((de = readdir(fdir)) != NULL) {
int len, dtype;
@@ -593,17 +653,18 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
continue;
len = strlen(de->d_name);
/* Ignore overly long pathnames! */
if (len + baselen + 8 > sizeof(fullname))
if (len + baselen + 8 > sizeof(path))
continue;
memcpy(fullname + baselen, de->d_name, len+1);
if (simplify_away(fullname, baselen + len, simplify))
memcpy(path + baselen, de->d_name, len+1);
len = baselen + len;
if (simplify_away(path, len, simplify))
continue;
dtype = DTYPE(de);
exclude = excluded(dir, fullname, &dtype);
exclude = excluded(dir, path, &dtype);
if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
&& in_pathspec(fullname, baselen + len, simplify))
dir_add_ignored(dir, fullname, baselen + len);
&& in_pathspec(path, len, simplify))
dir_add_ignored(dir, path,len);
/*
* Excluded? If we don't explicitly want to show
@@ -613,7 +674,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
continue;
if (dtype == DT_UNKNOWN)
dtype = get_dtype(de, fullname);
dtype = get_dtype(de, path, len);
/*
* Do we want to see just the ignored files?
@@ -630,9 +691,9 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
default:
continue;
case DT_DIR:
memcpy(fullname + baselen + len, "/", 2);
memcpy(path + len, "/", 2);
len++;
switch (treat_directory(dir, fullname, baselen + len, simplify)) {
switch (treat_directory(dir, path, len, simplify)) {
case show_directory:
if (exclude != !!(dir->flags
& DIR_SHOW_IGNORED))
@@ -640,7 +701,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
break;
case recurse_into_directory:
contents += read_directory_recursive(dir,
fullname, fullname, baselen + len, 0, simplify);
path, len, 0, simplify);
continue;
case ignore_directory:
continue;
@@ -654,7 +715,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
if (check_only)
goto exit_early;
else
dir_add_name(dir, fullname, baselen + len);
dir_add_name(dir, path, len);
}
exit_early:
closedir(fdir);
@@ -717,15 +778,15 @@ static void free_simplify(struct path_simplify *simplify)
free(simplify);
}
int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen, const char **pathspec)
int read_directory(struct dir_struct *dir, const char *path, int len, const char **pathspec)
{
struct path_simplify *simplify;
if (has_symlink_leading_path(path, strlen(path)))
if (has_symlink_leading_path(path, len))
return dir->nr;
simplify = create_simplify(pathspec);
read_directory_recursive(dir, path, base, baselen, 0, simplify);
read_directory_recursive(dir, path, len, 0, simplify);
free_simplify(simplify);
qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name);

5
dir.h
View File

@@ -61,14 +61,13 @@ struct dir_struct {
char basebuf[PATH_MAX];
};
extern int common_prefix(const char **pathspec);
#define MATCHED_RECURSIVELY 1
#define MATCHED_FNMATCH 2
#define MATCHED_EXACTLY 3
extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen, const char **pathspec);
extern int fill_directory(struct dir_struct *dir, const char **pathspec);
extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);
extern int excluded(struct dir_struct *, const char *, int *);
extern void add_excludes_from_file(struct dir_struct *, const char *fname);

View File

@@ -52,7 +52,7 @@
# else
# define _XOPEN_SOURCE 500
# endif
#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && !defined(_M_UNIX)
#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && !defined(_M_UNIX) && !defined(sgi)
#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
#ifndef __sun__
#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
@@ -62,6 +62,7 @@
#define _GNU_SOURCE 1
#define _BSD_SOURCE 1
#define _NETBSD_SOURCE 1
#define _SGI_SOURCE 1
#include <unistd.h>
#include <stdio.h>

View File

@@ -876,10 +876,6 @@ sub cmd_multi_init {
usage(1);
}
# there are currently some bugs that prevent multi-init/multi-fetch
# setups from working well without this.
$Git::SVN::_minimize_url = 1;
$_prefix = '' unless defined $_prefix;
if (defined $url) {
$url = canonicalize_url($url);
@@ -1180,7 +1176,7 @@ sub complete_url_ls_init {
"wanted to set to: $gs->{url}\n";
}
command_oneline('config', $k, $gs->{url}) unless $orig_url;
my $remote_path = "$ra->{svn_path}/$repo_path";
my $remote_path = "$gs->{path}/$repo_path";
$remote_path =~ s#/+#/#g;
$remote_path =~ s#^/##g;
$remote_path .= "/*" if $remote_path !~ /\*/;
@@ -1363,11 +1359,11 @@ sub read_repo_config {
sub extract_metadata {
my $id = shift or return (undef, undef, undef);
my ($url, $rev, $uuid) = ($id =~ /^\s*git-svn-id:\s+(.*)\@(\d+)
\s([a-f\d\-]+)$/x);
\s([a-f\d\-]+)$/ix);
if (!defined $rev || !$uuid || !$url) {
# some of the original repositories I made had
# identifiers like this:
($rev, $uuid) = ($id =~/^\s*git-svn-id:\s(\d+)\@([a-f\d\-]+)/);
($rev, $uuid) = ($id =~/^\s*git-svn-id:\s(\d+)\@([a-f\d\-]+)/i);
}
return ($url, $rev, $uuid);
}
@@ -2014,7 +2010,7 @@ sub _set_svm_vars {
chomp($src, $uuid);
$uuid =~ m{^[0-9a-f\-]{30,}$}
$uuid =~ m{^[0-9a-f\-]{30,}$}i
or die "doesn't look right - svm:uuid is '$uuid'\n";
# the '!' is used to mark the repos_root!/relative/path
@@ -2100,7 +2096,7 @@ sub svnsync {
die "doesn't look right - svn:sync-from-url is '$url'\n";
my $uuid = tmp_config('--get', "$section.svnsync-uuid");
($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}) or
($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or
die "doesn't look right - svn:sync-from-uuid is '$uuid'\n";
$svnsync = { url => $url, uuid => $uuid }
@@ -2118,7 +2114,7 @@ sub svnsync {
die "doesn't look right - svn:sync-from-url is '$url'\n";
my $uuid = $rp->{'svn:sync-from-uuid'} or die $err . "uuid\n";
($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}) or
($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or
die "doesn't look right - svn:sync-from-uuid is '$uuid'\n";
my $section = "svn-remote.$self->{repo_id}";
@@ -2134,7 +2130,7 @@ sub ra_uuid {
unless ($self->{ra_uuid}) {
my $key = "svn-remote.$self->{repo_id}.uuid";
my $uuid = eval { tmp_config('--get', $key) };
if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/) {
if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) {
$self->{ra_uuid} = $uuid;
} else {
die "ra_uuid called without URL\n" unless $self->{url};
@@ -2177,16 +2173,6 @@ sub ra {
$ra;
}
sub rel_path {
my ($self) = @_;
my $repos_root = $self->ra->{repos_root};
return $self->{path} if ($self->{url} eq $repos_root);
my $url = $self->{url} .
(length $self->{path} ? "/$self->{path}" : $self->{path});
$url =~ s!^\Q$repos_root\E(?:/+|$)!!g;
$url;
}
# prop_walk(PATH, REV, SUB)
# -------------------------
# Recursively traverse PATH at revision REV and invoke SUB for each
@@ -2512,10 +2498,7 @@ sub match_paths {
if (my $path = $paths->{"/$self->{path}"}) {
return ($path->{action} eq 'D') ? 0 : 1;
}
my $repos_root = $self->ra->{repos_root};
my $extended_path = $self->{url} . '/' . $self->{path};
$extended_path =~ s#^\Q$repos_root\E(/|$)##;
$self->{path_regex} ||= qr/^\/\Q$extended_path\E\//;
$self->{path_regex} ||= qr/^\/\Q$self->{path}\E\//;
if (grep /$self->{path_regex}/, keys %$paths) {
return 1;
}
@@ -2538,15 +2521,14 @@ sub find_parent_branch {
unless (defined $paths) {
my $err_handler = $SVN::Error::handler;
$SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs;
$self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1, sub {
$paths =
Git::SVN::Ra::dup_changed_paths($_[0]) });
$self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1,
sub { $paths = $_[0] });
$SVN::Error::handler = $err_handler;
}
return undef unless defined $paths;
# look for a parent from another branch:
my @b_path_components = split m#/#, $self->rel_path;
my @b_path_components = split m#/#, $self->{path};
my @a_path_components;
my $i;
while (@b_path_components) {
@@ -2564,11 +2546,11 @@ sub find_parent_branch {
my $r = $i->{copyfrom_rev};
my $repos_root = $self->ra->{repos_root};
my $url = $self->ra->{url};
my $new_url = $repos_root . $branch_from;
my $new_url = $url . $branch_from;
print STDERR "Found possible branch point: ",
"$new_url => ", $self->full_url, ", $r\n";
$branch_from =~ s#^/##;
my $gs = $self->other_gs($new_url, $url, $repos_root,
my $gs = $self->other_gs($new_url, $url,
$branch_from, $r, $self->{ref_id});
my ($r0, $parent) = $gs->find_rev_before($r, 1);
{
@@ -2753,9 +2735,9 @@ sub parse_svn_date {
}
sub other_gs {
my ($self, $new_url, $url, $repos_root,
my ($self, $new_url, $url,
$branch_from, $r, $old_ref_id) = @_;
my $gs = Git::SVN->find_by_url($new_url, $repos_root, $branch_from);
my $gs = Git::SVN->find_by_url($new_url, $url, $branch_from);
unless ($gs) {
my $ref_id = $old_ref_id;
$ref_id =~ s/\@\d+$//;
@@ -2866,7 +2848,7 @@ sub make_log_entry {
die "Can't have both 'useSvmProps' and 'rewriteRoot' ",
"options set!\n";
}
my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$};
my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}i;
# we don't want "SVM: initializing mirror for junk" ...
return undef if $r == 0;
my $svm = $self->svm;
@@ -4431,6 +4413,34 @@ sub get_log {
my ($self, @args) = @_;
my $pool = SVN::Pool->new;
# svn_log_changed_path_t objects passed to get_log are likely to be
# overwritten even if only the refs are copied to an external variable,
# so we should dup the structures in their entirety. Using an
# externally passed pool (instead of our temporary and quickly cleared
# pool in Git::SVN::Ra) does not help matters at all...
my $receiver = pop @args;
my $prefix = "/".$self->{svn_path};
$prefix =~ s#/+($)##;
my $prefix_regex = qr#^\Q$prefix\E#;
push(@args, sub {
my ($paths) = $_[0];
return &$receiver(@_) unless $paths;
$_[0] = ();
foreach my $p (keys %$paths) {
my $i = $paths->{$p};
# Make path relative to our url, not repos_root
$p =~ s/$prefix_regex//;
my %s = map { $_ => $i->$_; }
qw/copyfrom_path copyfrom_rev action/;
if ($s{'copyfrom_path'}) {
$s{'copyfrom_path'} =~ s/$prefix_regex//;
}
$_[0]{$p} = \%s;
}
&$receiver(@_);
});
# the limit parameter was not supported in SVN 1.1.x, so we
# drop it. Therefore, the receiver callback passed to it
# is made aware of this limitation by being wrapped if
@@ -4600,7 +4610,7 @@ sub gs_fetch_loop_common {
};
sub _cb {
my ($paths, $r, $author, $date, $log) = @_;
[ dup_changed_paths($paths),
[ $paths,
{ author => $author, date => $date, log => $log } ];
}
$self->get_log([$longest_path], $min, $max, 0, 1, 1,
@@ -4823,24 +4833,6 @@ sub skip_unknown_revs {
die "Error from SVN, ($errno): ", $err->expanded_message,"\n";
}
# svn_log_changed_path_t objects passed to get_log are likely to be
# overwritten even if only the refs are copied to an external variable,
# so we should dup the structures in their entirety. Using an externally
# passed pool (instead of our temporary and quickly cleared pool in
# Git::SVN::Ra) does not help matters at all...
sub dup_changed_paths {
my ($paths) = @_;
return undef unless $paths;
my %ret;
foreach my $p (keys %$paths) {
my $i = $paths->{$p};
my %s = map { $_ => $i->$_ }
qw/copyfrom_path copyfrom_rev action/;
$ret{$p} = \%s;
}
\%ret;
}
package Git::SVN::Log;
use strict;
use warnings;

View File

@@ -94,7 +94,7 @@ our $favicon = "++GITWEB_FAVICON++";
# URI and label (title) of GIT logo link
#our $logo_url = "http://www.kernel.org/pub/software/scm/git/docs/";
#our $logo_label = "git documentation";
our $logo_url = "http://git.or.cz/";
our $logo_url = "http://git-scm.com/";
our $logo_label = "git homepage";
# source of projects list

View File

@@ -34,7 +34,9 @@ static void *preload_thread(void *_data)
struct thread_data *p = _data;
struct index_state *index = p->index;
struct cache_entry **cep = index->cache + p->offset;
struct cache_def cache;
memset(&cache, 0, sizeof(cache));
nr = p->nr;
if (nr + p->offset > index->cache_nr)
nr = index->cache_nr - p->offset;
@@ -49,6 +51,8 @@ static void *preload_thread(void *_data)
continue;
if (!ce_path_match(ce, p->pathspec))
continue;
if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))
continue;
if (lstat(ce->name, &st))
continue;
if (ie_match_stat(index, ce, &st, CE_MATCH_RACY_IS_DIRTY))

View File

@@ -133,7 +133,7 @@ void mark_parents_uninteresting(struct commit *commit)
static void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode)
{
if (revs->no_walk && (obj->flags & UNINTERESTING))
die("object ranges do not make sense when not walking revisions");
revs->no_walk = 0;
if (revs->reflog_info && obj->type == OBJ_COMMIT &&
add_reflog_for_walk(revs->reflog_info,
(struct commit *)obj, name))

View File

@@ -32,19 +32,13 @@ static int longest_path_match(const char *name_a, int len_a,
return match_len;
}
static struct cache_def {
char path[PATH_MAX + 1];
int len;
int flags;
int track_flags;
int prefix_len_stat_func;
} cache;
static struct cache_def default_cache;
static inline void reset_lstat_cache(void)
static inline void reset_lstat_cache(struct cache_def *cache)
{
cache.path[0] = '\0';
cache.len = 0;
cache.flags = 0;
cache->path[0] = '\0';
cache->len = 0;
cache->flags = 0;
/*
* The track_flags and prefix_len_stat_func members is only
* set by the safeguard rule inside lstat_cache()
@@ -70,23 +64,23 @@ static inline void reset_lstat_cache(void)
* of the prefix, where the cache should use the stat() function
* instead of the lstat() function to test each path component.
*/
static int lstat_cache(const char *name, int len,
static int lstat_cache(struct cache_def *cache, const char *name, int len,
int track_flags, int prefix_len_stat_func)
{
int match_len, last_slash, last_slash_dir, previous_slash;
int match_flags, ret_flags, save_flags, max_len, ret;
struct stat st;
if (cache.track_flags != track_flags ||
cache.prefix_len_stat_func != prefix_len_stat_func) {
if (cache->track_flags != track_flags ||
cache->prefix_len_stat_func != prefix_len_stat_func) {
/*
* As a safeguard rule we clear the cache if the
* values of track_flags and/or prefix_len_stat_func
* does not match with the last supplied values.
*/
reset_lstat_cache();
cache.track_flags = track_flags;
cache.prefix_len_stat_func = prefix_len_stat_func;
reset_lstat_cache(cache);
cache->track_flags = track_flags;
cache->prefix_len_stat_func = prefix_len_stat_func;
match_len = last_slash = 0;
} else {
/*
@@ -94,10 +88,10 @@ static int lstat_cache(const char *name, int len,
* the 2 "excluding" path types.
*/
match_len = last_slash =
longest_path_match(name, len, cache.path, cache.len,
longest_path_match(name, len, cache->path, cache->len,
&previous_slash);
match_flags = cache.flags & track_flags & (FL_NOENT|FL_SYMLINK);
if (match_flags && match_len == cache.len)
match_flags = cache->flags & track_flags & (FL_NOENT|FL_SYMLINK);
if (match_flags && match_len == cache->len)
return match_flags;
/*
* If we now have match_len > 0, we would know that
@@ -121,18 +115,18 @@ static int lstat_cache(const char *name, int len,
max_len = len < PATH_MAX ? len : PATH_MAX;
while (match_len < max_len) {
do {
cache.path[match_len] = name[match_len];
cache->path[match_len] = name[match_len];
match_len++;
} while (match_len < max_len && name[match_len] != '/');
if (match_len >= max_len && !(track_flags & FL_FULLPATH))
break;
last_slash = match_len;
cache.path[last_slash] = '\0';
cache->path[last_slash] = '\0';
if (last_slash <= prefix_len_stat_func)
ret = stat(cache.path, &st);
ret = stat(cache->path, &st);
else
ret = lstat(cache.path, &st);
ret = lstat(cache->path, &st);
if (ret) {
ret_flags = FL_LSTATERR;
@@ -156,9 +150,9 @@ static int lstat_cache(const char *name, int len,
*/
save_flags = ret_flags & track_flags & (FL_NOENT|FL_SYMLINK);
if (save_flags && last_slash > 0 && last_slash <= PATH_MAX) {
cache.path[last_slash] = '\0';
cache.len = last_slash;
cache.flags = save_flags;
cache->path[last_slash] = '\0';
cache->len = last_slash;
cache->flags = save_flags;
} else if ((track_flags & FL_DIR) &&
last_slash_dir > 0 && last_slash_dir <= PATH_MAX) {
/*
@@ -172,11 +166,11 @@ static int lstat_cache(const char *name, int len,
* can still cache the path components before the last
* one (the found symlink or non-existing component).
*/
cache.path[last_slash_dir] = '\0';
cache.len = last_slash_dir;
cache.flags = FL_DIR;
cache->path[last_slash_dir] = '\0';
cache->len = last_slash_dir;
cache->flags = FL_DIR;
} else {
reset_lstat_cache();
reset_lstat_cache(cache);
}
return ret_flags;
}
@@ -188,16 +182,17 @@ static int lstat_cache(const char *name, int len,
void invalidate_lstat_cache(const char *name, int len)
{
int match_len, previous_slash;
struct cache_def *cache = &default_cache; /* FIXME */
match_len = longest_path_match(name, len, cache.path, cache.len,
match_len = longest_path_match(name, len, cache->path, cache->len,
&previous_slash);
if (len == match_len) {
if ((cache.track_flags & FL_DIR) && previous_slash > 0) {
cache.path[previous_slash] = '\0';
cache.len = previous_slash;
cache.flags = FL_DIR;
if ((cache->track_flags & FL_DIR) && previous_slash > 0) {
cache->path[previous_slash] = '\0';
cache->len = previous_slash;
cache->flags = FL_DIR;
} else {
reset_lstat_cache();
reset_lstat_cache(cache);
}
}
}
@@ -207,19 +202,26 @@ void invalidate_lstat_cache(const char *name, int len)
*/
void clear_lstat_cache(void)
{
reset_lstat_cache();
struct cache_def *cache = &default_cache; /* FIXME */
reset_lstat_cache(cache);
}
#define USE_ONLY_LSTAT 0
/*
* Return non-zero if path 'name' has a leading symlink component
*/
int threaded_has_symlink_leading_path(struct cache_def *cache, const char *name, int len)
{
return lstat_cache(cache, name, len, FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) & FL_SYMLINK;
}
/*
* Return non-zero if path 'name' has a leading symlink component
*/
int has_symlink_leading_path(const char *name, int len)
{
return lstat_cache(name, len,
FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) &
FL_SYMLINK;
return threaded_has_symlink_leading_path(&default_cache, name, len);
}
/*
@@ -228,7 +230,8 @@ int has_symlink_leading_path(const char *name, int len)
*/
int has_symlink_or_noent_leading_path(const char *name, int len)
{
return lstat_cache(name, len,
struct cache_def *cache = &default_cache; /* FIXME */
return lstat_cache(cache, name, len,
FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT) &
(FL_SYMLINK|FL_NOENT);
}
@@ -242,7 +245,8 @@ int has_symlink_or_noent_leading_path(const char *name, int len)
*/
int has_dirs_only_path(const char *name, int len, int prefix_len)
{
return lstat_cache(name, len,
struct cache_def *cache = &default_cache; /* FIXME */
return lstat_cache(cache, name, len,
FL_DIR|FL_FULLPATH, prefix_len) &
FL_DIR;
}

View File

@@ -119,4 +119,24 @@ test_expect_success 'quickfetch should not copy from alternate' '
'
test_expect_success 'quickfetch should handle ~1000 refs (on Windows)' '
git gc &&
head=$(git rev-parse HEAD) &&
branchprefix="$head refs/heads/branch" &&
for i in 0 1 2 3 4 5 6 7 8 9; do
for j in 0 1 2 3 4 5 6 7 8 9; do
for k in 0 1 2 3 4 5 6 7 8 9; do
echo "$branchprefix$i$j$k" >> .git/packed-refs
done
done
done &&
(
cd cloned &&
git fetch &&
git fetch
)
'
test_done

View File

@@ -99,22 +99,22 @@ test_expect_success 'Multiple branch or tag paths require -d' '
test_expect_success 'create new branches and tags' '
( cd git_project &&
git svn branch -m "New branch 1" -d project/b_one New1 ) &&
git svn branch -m "New branch 1" -d b_one New1 ) &&
( cd svn_project &&
svn_cmd up && test -e b_one/New1/a.file ) &&
( cd git_project &&
git svn branch -m "New branch 2" -d project/b_two New2 ) &&
git svn branch -m "New branch 2" -d b_two New2 ) &&
( cd svn_project &&
svn_cmd up && test -e b_two/New2/a.file ) &&
( cd git_project &&
git svn branch -t -m "New tag 1" -d project/tags_A Tag1 ) &&
git svn branch -t -m "New tag 1" -d tags_A Tag1 ) &&
( cd svn_project &&
svn_cmd up && test -e tags_A/Tag1/a.file ) &&
( cd git_project &&
git svn tag -m "New tag 2" -d project/tags_B Tag2 ) &&
git svn tag -m "New tag 2" -d tags_B Tag2 ) &&
( cd svn_project &&
svn_cmd up && test -e tags_B/Tag2/a.file )
'

View File

@@ -128,7 +128,7 @@ static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_o
static int unpack_index_entry(struct cache_entry *ce, struct unpack_trees_options *o)
{
struct cache_entry *src[5] = { ce, };
struct cache_entry *src[5] = { ce, NULL, };
o->pos++;
if (ce_stage(ce)) {
@@ -551,7 +551,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
memset(&d, 0, sizeof(d));
if (o->dir)
d.exclude_per_dir = o->dir->exclude_per_dir;
i = read_directory(&d, ce->name, pathbuf, namelen+1, NULL);
i = read_directory(&d, pathbuf, namelen+1, NULL);
if (i)
return o->gently ? -1 :
error(ERRORMSG(o, not_uptodate_dir), ce->name);
@@ -1004,7 +1004,7 @@ int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o)
if (old && same(old, a)) {
int update = 0;
if (o->reset) {
if (o->reset && !ce_uptodate(old)) {
struct stat st;
if (lstat(old->name, &st) ||
ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID))

View File

@@ -255,7 +255,7 @@ static void wt_status_print_untracked(struct wt_status *s)
DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
setup_standard_excludes(&dir);
read_directory(&dir, ".", "", 0, NULL);
fill_directory(&dir, NULL);
for(i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
if (!cache_name_is_other(ent->name, ent->len))