Merge branch 'jk/ref-cache-non-repository-optim' into maint
The underlying machinery used by "ls-files -o" and other commands have been taught not to create empty submodule ref cache for a directory that is not a submodule. This removes a ton of wasted CPU cycles. * jk/ref-cache-non-repository-optim: resolve_gitlink_ref: ignore non-repository paths clean: make is_git_repository a public function
This commit is contained in:
commit
e2d7739051
@ -147,30 +147,6 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Return 1 if the given path is the root of a git repository or
|
|
||||||
* submodule else 0. Will not return 1 for bare repositories with the
|
|
||||||
* exception of creating a bare repository in "foo/.git" and calling
|
|
||||||
* is_git_repository("foo").
|
|
||||||
*/
|
|
||||||
static int is_git_repository(struct strbuf *path)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
int gitfile_error;
|
|
||||||
size_t orig_path_len = path->len;
|
|
||||||
assert(orig_path_len != 0);
|
|
||||||
strbuf_complete(path, '/');
|
|
||||||
strbuf_addstr(path, ".git");
|
|
||||||
if (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf))
|
|
||||||
ret = 1;
|
|
||||||
if (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED ||
|
|
||||||
gitfile_error == READ_GITFILE_ERR_READ_FAILED)
|
|
||||||
ret = 1; /* This could be a real .git file, take the
|
|
||||||
* safe option and avoid cleaning */
|
|
||||||
strbuf_setlen(path, orig_path_len);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
|
static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
|
||||||
int dry_run, int quiet, int *dir_gone)
|
int dry_run, int quiet, int *dir_gone)
|
||||||
{
|
{
|
||||||
@ -182,7 +158,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
|
|||||||
|
|
||||||
*dir_gone = 1;
|
*dir_gone = 1;
|
||||||
|
|
||||||
if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_git_repository(path)) {
|
if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_nonbare_repository_dir(path)) {
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
quote_path_relative(path->buf, prefix, "ed);
|
quote_path_relative(path->buf, prefix, "ed);
|
||||||
printf(dry_run ? _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
|
printf(dry_run ? _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
|
||||||
|
20
cache.h
20
cache.h
@ -456,7 +456,6 @@ extern char *git_work_tree_cfg;
|
|||||||
extern int is_inside_work_tree(void);
|
extern int is_inside_work_tree(void);
|
||||||
extern const char *get_git_dir(void);
|
extern const char *get_git_dir(void);
|
||||||
extern const char *get_git_common_dir(void);
|
extern const char *get_git_common_dir(void);
|
||||||
extern int is_git_directory(const char *path);
|
|
||||||
extern char *get_object_directory(void);
|
extern char *get_object_directory(void);
|
||||||
extern char *get_index_file(void);
|
extern char *get_index_file(void);
|
||||||
extern char *get_graft_file(void);
|
extern char *get_graft_file(void);
|
||||||
@ -467,6 +466,25 @@ extern const char *get_git_namespace(void);
|
|||||||
extern const char *strip_namespace(const char *namespaced_ref);
|
extern const char *strip_namespace(const char *namespaced_ref);
|
||||||
extern const char *get_git_work_tree(void);
|
extern const char *get_git_work_tree(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true if the given path is a git directory; note that this _just_
|
||||||
|
* looks at the directory itself. If you want to know whether "foo/.git"
|
||||||
|
* is a repository, you must feed that path, not just "foo".
|
||||||
|
*/
|
||||||
|
extern int is_git_directory(const char *path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return 1 if the given path is the root of a git repository or
|
||||||
|
* submodule, else 0. Will not return 1 for bare repositories with the
|
||||||
|
* exception of creating a bare repository in "foo/.git" and calling
|
||||||
|
* is_git_repository("foo").
|
||||||
|
*
|
||||||
|
* If we run into read errors, we err on the side of saying "yes, it is",
|
||||||
|
* as we usually consider sub-repos precious, and would prefer to err on the
|
||||||
|
* side of not disrupting or deleting them.
|
||||||
|
*/
|
||||||
|
extern int is_nonbare_repository_dir(struct strbuf *path);
|
||||||
|
|
||||||
#define READ_GITFILE_ERR_STAT_FAILED 1
|
#define READ_GITFILE_ERR_STAT_FAILED 1
|
||||||
#define READ_GITFILE_ERR_NOT_A_FILE 2
|
#define READ_GITFILE_ERR_NOT_A_FILE 2
|
||||||
#define READ_GITFILE_ERR_OPEN_FAILED 3
|
#define READ_GITFILE_ERR_OPEN_FAILED 3
|
||||||
|
@ -933,6 +933,10 @@ static void clear_loose_ref_cache(struct ref_cache *refs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new submodule ref cache and add it to the internal
|
||||||
|
* set of caches.
|
||||||
|
*/
|
||||||
static struct ref_cache *create_ref_cache(const char *submodule)
|
static struct ref_cache *create_ref_cache(const char *submodule)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
@ -942,9 +946,24 @@ static struct ref_cache *create_ref_cache(const char *submodule)
|
|||||||
len = strlen(submodule) + 1;
|
len = strlen(submodule) + 1;
|
||||||
refs = xcalloc(1, sizeof(struct ref_cache) + len);
|
refs = xcalloc(1, sizeof(struct ref_cache) + len);
|
||||||
memcpy(refs->name, submodule, len);
|
memcpy(refs->name, submodule, len);
|
||||||
|
refs->next = submodule_ref_caches;
|
||||||
|
submodule_ref_caches = refs;
|
||||||
return refs;
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct ref_cache *lookup_ref_cache(const char *submodule)
|
||||||
|
{
|
||||||
|
struct ref_cache *refs;
|
||||||
|
|
||||||
|
if (!submodule || !*submodule)
|
||||||
|
return &ref_cache;
|
||||||
|
|
||||||
|
for (refs = submodule_ref_caches; refs; refs = refs->next)
|
||||||
|
if (!strcmp(submodule, refs->name))
|
||||||
|
return refs;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return a pointer to a ref_cache for the specified submodule. For
|
* Return a pointer to a ref_cache for the specified submodule. For
|
||||||
* the main repository, use submodule==NULL. The returned structure
|
* the main repository, use submodule==NULL. The returned structure
|
||||||
@ -953,18 +972,9 @@ static struct ref_cache *create_ref_cache(const char *submodule)
|
|||||||
*/
|
*/
|
||||||
static struct ref_cache *get_ref_cache(const char *submodule)
|
static struct ref_cache *get_ref_cache(const char *submodule)
|
||||||
{
|
{
|
||||||
struct ref_cache *refs;
|
struct ref_cache *refs = lookup_ref_cache(submodule);
|
||||||
|
if (!refs)
|
||||||
if (!submodule || !*submodule)
|
refs = create_ref_cache(submodule);
|
||||||
return &ref_cache;
|
|
||||||
|
|
||||||
for (refs = submodule_ref_caches; refs; refs = refs->next)
|
|
||||||
if (!strcmp(submodule, refs->name))
|
|
||||||
return refs;
|
|
||||||
|
|
||||||
refs = create_ref_cache(submodule);
|
|
||||||
refs->next = submodule_ref_caches;
|
|
||||||
submodule_ref_caches = refs;
|
|
||||||
return refs;
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1336,16 +1346,24 @@ static int resolve_gitlink_ref_recursive(struct ref_cache *refs,
|
|||||||
int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)
|
int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)
|
||||||
{
|
{
|
||||||
int len = strlen(path), retval;
|
int len = strlen(path), retval;
|
||||||
char *submodule;
|
struct strbuf submodule = STRBUF_INIT;
|
||||||
struct ref_cache *refs;
|
struct ref_cache *refs;
|
||||||
|
|
||||||
while (len && path[len-1] == '/')
|
while (len && path[len-1] == '/')
|
||||||
len--;
|
len--;
|
||||||
if (!len)
|
if (!len)
|
||||||
return -1;
|
return -1;
|
||||||
submodule = xstrndup(path, len);
|
|
||||||
refs = get_ref_cache(submodule);
|
strbuf_add(&submodule, path, len);
|
||||||
free(submodule);
|
refs = lookup_ref_cache(submodule.buf);
|
||||||
|
if (!refs) {
|
||||||
|
if (!is_nonbare_repository_dir(&submodule)) {
|
||||||
|
strbuf_release(&submodule);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
refs = create_ref_cache(submodule.buf);
|
||||||
|
}
|
||||||
|
strbuf_release(&submodule);
|
||||||
|
|
||||||
retval = resolve_gitlink_ref_recursive(refs, refname, sha1, 0);
|
retval = resolve_gitlink_ref_recursive(refs, refname, sha1, 0);
|
||||||
return retval;
|
return retval;
|
||||||
|
17
setup.c
17
setup.c
@ -312,6 +312,23 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int is_nonbare_repository_dir(struct strbuf *path)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int gitfile_error;
|
||||||
|
size_t orig_path_len = path->len;
|
||||||
|
assert(orig_path_len != 0);
|
||||||
|
strbuf_complete(path, '/');
|
||||||
|
strbuf_addstr(path, ".git");
|
||||||
|
if (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf))
|
||||||
|
ret = 1;
|
||||||
|
if (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED ||
|
||||||
|
gitfile_error == READ_GITFILE_ERR_READ_FAILED)
|
||||||
|
ret = 1;
|
||||||
|
strbuf_setlen(path, orig_path_len);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int is_inside_git_dir(void)
|
int is_inside_git_dir(void)
|
||||||
{
|
{
|
||||||
if (inside_git_dir < 0)
|
if (inside_git_dir < 0)
|
||||||
|
@ -28,4 +28,8 @@ test_perf 'clean many untracked sub dirs, ignore nested git' '
|
|||||||
git clean -n -q -f -f -d 100000_sub_dirs/
|
git clean -n -q -f -f -d 100000_sub_dirs/
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_perf 'ls-files -o' '
|
||||||
|
git ls-files -o
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
@ -65,6 +65,13 @@ test_expect_success '--no-empty-directory hides empty directory' '
|
|||||||
test_cmp expected3 output
|
test_cmp expected3 output
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ls-files --others handles non-submodule .git' '
|
||||||
|
mkdir not-a-submodule &&
|
||||||
|
echo foo >not-a-submodule/.git &&
|
||||||
|
git ls-files -o >output &&
|
||||||
|
test_cmp expected1 output
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success SYMLINKS 'ls-files --others with symlinked submodule' '
|
test_expect_success SYMLINKS 'ls-files --others with symlinked submodule' '
|
||||||
git init super &&
|
git init super &&
|
||||||
git init sub &&
|
git init sub &&
|
||||||
|
Loading…
Reference in New Issue
Block a user