From eb8381c88518b10d683a29deea1d43ed671f14ec Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 3 Feb 2007 13:25:43 -0500 Subject: [PATCH] scan reflogs independently from refs 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 Signed-off-by: Junio C Hamano --- builtin-reflog.c | 7 ++----- fsck-objects.c | 9 +++++++-- reachable.c | 4 ++-- refs.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ refs.h | 6 ++++++ 5 files changed, 67 insertions(+), 9 deletions(-) diff --git a/builtin-reflog.c b/builtin-reflog.c index b6612a90ed..bfb169ac04 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -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)); @@ -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]; diff --git a/fsck-objects.c b/fsck-objects.c index ecfb014fff..c9b4a39807 100644 --- a/fsck-objects.c +++ b/fsck-objects.c @@ -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; @@ -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 diff --git a/reachable.c b/reachable.c index a6a334822a..01760d7046 100644 --- a/reachable.c +++ b/reachable.c @@ -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 diff --git a/refs.c b/refs.c index 4a523086e3..da09e434c7 100644 --- a/refs.c +++ b/refs.c @@ -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); +} diff --git a/refs.h b/refs.h index 94a58b41fb..acedffc0e4 100644 --- a/refs.h +++ b/refs.h @@ -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);