scan reflogs independently from refs
authorNicolas Pitre <nico@cam.org>
Sat, 3 Feb 2007 18:25:43 +0000 (13:25 -0500)
committerJunio C Hamano <junkio@cox.net>
Sat, 3 Feb 2007 19:57:18 +0000 (11:57 -0800)
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>
builtin-reflog.c
fsck-objects.c
reachable.c
refs.c
refs.h

index b6612a90ed7a049290291f484609c0efa911c1a7..bfb169ac04a3bddbe7afe79efc25e5ef3de59319 100644 (file)
@@ -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];
index ecfb014fffe1c13dedcd6973b4328abeef02413d..c9b4a3980795c6e4df8f793dfd640b4bd2db36d5 100644 (file)
@@ -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
index a6a334822a91f7325399740b0aa05e95f6fb4a70..01760d70462927ad33c7976a50e31372863a45f9 100644 (file)
@@ -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 4a523086e37fa0bcdd647c826b9221165d630586..da09e434c7ac5dfceebc6a2ffd85e57eaeb75eef 100644 (file)
--- 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 94a58b41fbf3b3de81a7133c2db404338093758d..acedffc0e412e1de6137d665a7c6b32f58b1c20b 100644 (file)
--- 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);