Skip to content

Commit

Permalink
scan reflogs independently from refs
Browse files Browse the repository at this point in the history
Currently, the search for all reflogs depends on the existence of
corresponding refs under the .git/refs/ directory.  Let's scan the
.git/logs/ directory directly instead.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
  • Loading branch information
Nicolas Pitre authored and Junio C Hamano committed Feb 3, 2007
1 parent a7e4fbf commit eb8381c
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 9 deletions.
7 changes: 2 additions & 5 deletions builtin-reflog.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,14 +245,11 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
char *log_file, *newlog_path = NULL;
int status = 0;

if (strncmp(ref, "refs/", 5))
return error("not a ref '%s'", ref);

memset(&cb, 0, sizeof(cb));
/* we take the lock for the ref itself to prevent it from
* getting updated.
*/
lock = lock_ref_sha1(ref + 5, sha1);
lock = lock_any_ref_for_update(ref, sha1);
if (!lock)
return error("cannot lock ref '%s'", ref);
log_file = xstrdup(git_path("logs/%s", ref));
Expand Down Expand Up @@ -353,7 +350,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
}

if (do_all)
status |= for_each_ref(expire_reflog, &cb);
status |= for_each_reflog(expire_reflog, &cb);
while (i < argc) {
const char *ref = argv[i++];
unsigned char sha1[20];
Expand Down
9 changes: 7 additions & 2 deletions fsck-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,12 @@ static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
return 0;
}

static int fsck_handle_reflog(const char *logname, const unsigned char *sha1, int flag, void *cb_data)
{
for_each_reflog_ent(logname, fsck_handle_reflog_ent, NULL);
return 0;
}

static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
struct object *obj;
Expand All @@ -495,14 +501,13 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f
obj->used = 1;
mark_reachable(obj, REACHABLE);

for_each_reflog_ent(refname, fsck_handle_reflog_ent, NULL);

return 0;
}

static void get_default_heads(void)
{
for_each_ref(fsck_handle_ref, NULL);
for_each_reflog(fsck_handle_reflog, NULL);

/*
* Not having any default heads isn't really fatal, but
Expand Down
4 changes: 2 additions & 2 deletions reachable.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,9 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog)
/* Add all external refs */
for_each_ref(add_one_ref, revs);

/* Add all reflog info from refs */
/* Add all reflog info */
if (mark_reflog)
for_each_ref(add_one_reflog, revs);
for_each_reflog(add_one_reflog, revs);

/*
* Set up the revision walk - this will move all commits
Expand Down
50 changes: 50 additions & 0 deletions refs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1201,3 +1201,53 @@ int for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
return ret;
}

static int do_for_each_reflog(const char *base, each_ref_fn fn, void *cb_data)
{
DIR *dir = opendir(git_path("logs/%s", base));
int retval = errno;

if (dir) {
struct dirent *de;
int baselen = strlen(base);
char *log = xmalloc(baselen + 257);

memcpy(log, base, baselen);
if (baselen && base[baselen-1] != '/')
log[baselen++] = '/';

while ((de = readdir(dir)) != NULL) {
struct stat st;
int namelen;

if (de->d_name[0] == '.')
continue;
namelen = strlen(de->d_name);
if (namelen > 255)
continue;
if (has_extension(de->d_name, ".lock"))
continue;
memcpy(log + baselen, de->d_name, namelen+1);
if (stat(git_path("logs/%s", log), &st) < 0)
continue;
if (S_ISDIR(st.st_mode)) {
retval = do_for_each_reflog(log, fn, cb_data);
} else {
unsigned char sha1[20];
if (!resolve_ref(log, sha1, 0, NULL))
retval = error("bad ref for %s", log);
else
retval = fn(log, sha1, 0, cb_data);
}
if (retval)
break;
}
free(log);
closedir(dir);
}
return retval;
}

int for_each_reflog(each_ref_fn fn, void *cb_data)
{
return do_for_each_reflog("", fn, cb_data);
}
6 changes: 6 additions & 0 deletions refs.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ extern int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned
typedef int each_reflog_ent_fn(unsigned char *osha1, unsigned char *nsha1, const char *, unsigned long, int, const char *, void *);
int for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data);

/*
* Calls the specified function for each reflog file until it returns nonzero,
* and returns the value
*/
extern int for_each_reflog(each_ref_fn, void *);

/** Returns 0 if target has the right format for a ref. **/
extern int check_ref_format(const char *target);

Expand Down

0 comments on commit eb8381c

Please sign in to comment.