git-svnimport: support for incremental import
[gitweb.git] / builtin-reflog.c
index d4f73535c4e627b060df52a4c3cd01749cd6fb9c..d3f2f50d2bc7b4ef0f0e4801c70c5a15ff869f1f 100644 (file)
@@ -3,7 +3,10 @@
 #include "commit.h"
 #include "refs.h"
 #include "dir.h"
-#include <time.h>
+#include "tree-walk.h"
+
+static unsigned long default_reflog_expire;
+static unsigned long default_reflog_expire_unreachable;
 
 struct expire_reflog_cb {
        FILE *newlog;
@@ -13,13 +16,50 @@ struct expire_reflog_cb {
        unsigned long expire_unreachable;
 };
 
+static int tree_is_complete(const unsigned char *sha1)
+{
+       struct tree_desc desc;
+       void *buf;
+       char type[20];
+
+       buf = read_sha1_file(sha1, type, &desc.size);
+       if (!buf)
+               return 0;
+       desc.buf = buf;
+       while (desc.size) {
+               const unsigned char *elem;
+               const char *name;
+               unsigned mode;
+
+               elem = tree_entry_extract(&desc, &name, &mode);
+               if (!has_sha1_file(elem) ||
+                   (S_ISDIR(mode) && !tree_is_complete(elem))) {
+                       free(buf);
+                       return 0;
+               }
+               update_tree_entry(&desc);
+       }
+       free(buf);
+       return 1;
+}
+
 static int keep_entry(struct commit **it, unsigned char *sha1)
 {
+       struct commit *commit;
+
        *it = NULL;
        if (is_null_sha1(sha1))
                return 1;
-       *it = lookup_commit_reference_gently(sha1, 1);
-       return (*it != NULL);
+       commit = lookup_commit_reference_gently(sha1, 1);
+       if (!commit)
+               return 0;
+
+       /* Make sure everything in this commit exists. */
+       parse_object(commit->object.sha1);
+       if (!tree_is_complete(commit->tree->object.sha1))
+               return 0;
+       *it = commit;
+       return 1;
 }
 
 static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
@@ -43,7 +83,8 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
                goto prune;
 
        if ((timestamp < cb->expire_unreachable) &&
-           ((old && !in_merge_bases(old, cb->ref_commit)) ||
+           (!cb->ref_commit ||
+            (old && !in_merge_bases(old, cb->ref_commit)) ||
             (new && !in_merge_bases(new, cb->ref_commit))))
                goto prune;
 
@@ -89,10 +130,9 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
        }
 
        cb.ref_commit = lookup_commit_reference_gently(sha1, 1);
-       if (!cb.ref_commit) {
-               status = error("ref '%s' does not point at a commit", ref);
-               goto finish;
-       }
+       if (!cb.ref_commit)
+               fprintf(stderr,
+                       "warning: ref '%s' does not point at a commit\n", ref);
        cb.ref = ref;
        cb.expire_total = cmd->expire_total;
        cb.expire_unreachable = cmd->expire_unreachable;
@@ -113,6 +153,17 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
        return status;
 }
 
+static int reflog_expire_config(const char *var, const char *value)
+{
+       if (!strcmp(var, "gc.reflogexpire"))
+               default_reflog_expire = approxidate(value);
+       else if (!strcmp(var, "gc.reflogexpireunreachable"))
+               default_reflog_expire_unreachable = approxidate(value);
+       else
+               return git_default_config(var, value);
+       return 0;
+}
+
 static const char reflog_expire_usage[] =
 "git-reflog expire [--dry-run] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
 
@@ -122,11 +173,18 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
        unsigned long now = time(NULL);
        int i, status, do_all;
 
+       git_config(reflog_expire_config);
+
        save_commit_buffer = 0;
        do_all = status = 0;
        memset(&cb, 0, sizeof(cb));
-       cb.expire_total = now - 90 * 24 * 3600;
-       cb.expire_unreachable = now - 30 * 24 * 3600;
+
+       if (!default_reflog_expire_unreachable)
+               default_reflog_expire_unreachable = now - 30 * 24 * 3600;
+       if (!default_reflog_expire)
+               default_reflog_expire = now - 90 * 24 * 3600;
+       cb.expire_total = default_reflog_expire;
+       cb.expire_unreachable = default_reflog_expire_unreachable;
 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];