1
0
mirror of https://github.com/git/git.git synced 2025-03-28 21:34:03 +00:00

refs.c: remove extra git_path calls from read_loose_refs

In iterating over the loose refs in "refs/foo/", we keep a
running strbuf with "refs/foo/one", "refs/foo/two", etc. But
we also need to access these files in the filesystem, as
".git/refs/foo/one", etc. For this latter purpose, we make a
series of independent calls to git_path(). These are safe
(we only use the result to call stat()), but assigning the
result of git_path is a suspicious pattern that we'd rather
avoid.

This patch keeps a running buffer with ".git/refs/foo/", and
we can just append/reset each directory element as we loop.
This matches how we handle the refnames. It should also be
more efficient, as we do not keep formatting the same
".git/refs/foo" prefix (which can be arbitrarily deep).

Technically we are dropping a call to strbuf_cleanup() on
each generated filename, but that's OK; it wasn't doing
anything, as we are putting in single-level names we read
from the filesystem (so it could not possibly be cleaning up
cruft like "./" in this instance).

A clever reader may also note that the running refname
buffer ("refs/foo/") is actually a subset of the filesystem
path buffer (".git/refs/foo/"). We could get by with one
buffer, indexing the length of $GIT_DIR when we want the
refname. However, having tried this, the resulting code
actually ends up a little more confusing, and the efficiency
improvement is tiny (and almost certainly dwarfed by the
system calls we are making).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jeff King 2015-08-10 05:36:19 -04:00 committed by Junio C Hamano
parent b21a5d6605
commit f5b2dec165

23
refs.c
View File

@ -1352,19 +1352,23 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
{ {
struct ref_cache *refs = dir->ref_cache; struct ref_cache *refs = dir->ref_cache;
DIR *d; DIR *d;
const char *path;
struct dirent *de; struct dirent *de;
int dirnamelen = strlen(dirname); int dirnamelen = strlen(dirname);
struct strbuf refname; struct strbuf refname;
struct strbuf path = STRBUF_INIT;
size_t path_baselen;
if (*refs->name) if (*refs->name)
path = git_path_submodule(refs->name, "%s", dirname); strbuf_git_path_submodule(&path, refs->name, "%s", dirname);
else else
path = git_path("%s", dirname); strbuf_git_path(&path, "%s", dirname);
path_baselen = path.len;
d = opendir(path); d = opendir(path.buf);
if (!d) if (!d) {
strbuf_release(&path);
return; return;
}
strbuf_init(&refname, dirnamelen + 257); strbuf_init(&refname, dirnamelen + 257);
strbuf_add(&refname, dirname, dirnamelen); strbuf_add(&refname, dirname, dirnamelen);
@ -1373,17 +1377,14 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
unsigned char sha1[20]; unsigned char sha1[20];
struct stat st; struct stat st;
int flag; int flag;
const char *refdir;
if (de->d_name[0] == '.') if (de->d_name[0] == '.')
continue; continue;
if (ends_with(de->d_name, ".lock")) if (ends_with(de->d_name, ".lock"))
continue; continue;
strbuf_addstr(&refname, de->d_name); strbuf_addstr(&refname, de->d_name);
refdir = *refs->name strbuf_addstr(&path, de->d_name);
? git_path_submodule(refs->name, "%s", refname.buf) if (stat(path.buf, &st) < 0) {
: git_path("%s", refname.buf);
if (stat(refdir, &st) < 0) {
; /* silently ignore */ ; /* silently ignore */
} else if (S_ISDIR(st.st_mode)) { } else if (S_ISDIR(st.st_mode)) {
strbuf_addch(&refname, '/'); strbuf_addch(&refname, '/');
@ -1430,8 +1431,10 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
create_ref_entry(refname.buf, sha1, flag, 0)); create_ref_entry(refname.buf, sha1, flag, 0));
} }
strbuf_setlen(&refname, dirnamelen); strbuf_setlen(&refname, dirnamelen);
strbuf_setlen(&path, path_baselen);
} }
strbuf_release(&refname); strbuf_release(&refname);
strbuf_release(&path);
closedir(d); closedir(d);
} }