7929af1aacd515bcc49bb79e9e3d8ee616397b4f
   1#include "cache.h"
   2#include "commit.h"
   3#include "diff.h"
   4#include "revision.h"
   5#include "builtin.h"
   6#include "reachable.h"
   7
   8static const char prune_usage[] = "git-prune [-n] [--grace=time]";
   9static int show_only;
  10static int prune_grace_period;
  11
  12static int prune_object(char *path, const char *filename, const unsigned char *sha1)
  13{
  14        char buf[20];
  15        const char *type;
  16
  17        if (show_only) {
  18                if (sha1_object_info(sha1, buf, NULL))
  19                        type = "unknown";
  20                else
  21                        type = buf;
  22                printf("%s %s\n", sha1_to_hex(sha1), type);
  23                return 0;
  24        }
  25        unlink(mkpath("%s/%s", path, filename));
  26        rmdir(path);
  27        return 0;
  28}
  29
  30static int prune_dir(int i, char *path)
  31{
  32        DIR *dir = opendir(path);
  33        struct dirent *de;
  34
  35        if (!dir)
  36                return 0;
  37
  38        while ((de = readdir(dir)) != NULL) {
  39                char name[100];
  40                unsigned char sha1[20];
  41                int len = strlen(de->d_name);
  42                struct stat st;
  43
  44                switch (len) {
  45                case 2:
  46                        if (de->d_name[1] != '.')
  47                                break;
  48                case 1:
  49                        if (de->d_name[0] != '.')
  50                                break;
  51                        continue;
  52                case 38:
  53                        sprintf(name, "%02x", i);
  54                        memcpy(name+2, de->d_name, len+1);
  55                        if (get_sha1_hex(name, sha1) < 0)
  56                                break;
  57
  58                        /*
  59                         * Do we know about this object?
  60                         * It must have been reachable
  61                         */
  62                        if (lookup_object(sha1))
  63                                continue;
  64
  65                        if (prune_grace_period > 0 &&
  66                            !stat(mkpath("%s/%s", path, de->d_name), &st) &&
  67                            st.st_mtime > prune_grace_period)
  68                                continue;
  69
  70                        prune_object(path, de->d_name, sha1);
  71                        continue;
  72                }
  73                fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
  74        }
  75        closedir(dir);
  76        return 0;
  77}
  78
  79static void prune_object_dir(const char *path)
  80{
  81        int i;
  82        for (i = 0; i < 256; i++) {
  83                static char dir[4096];
  84                sprintf(dir, "%s/%02x", path, i);
  85                prune_dir(i, dir);
  86        }
  87}
  88
  89static int git_prune_config(const char *var, const char *value)
  90{
  91        if (!strcmp(var, "gc.prunegrace")) {
  92                if (!strcmp(value, "off"))
  93                        prune_grace_period = 0;
  94                else
  95                        prune_grace_period = approxidate(value);
  96                return 0;
  97        }
  98        return git_default_config(var, value);
  99}
 100
 101int cmd_prune(int argc, const char **argv, const char *prefix)
 102{
 103        int i;
 104        struct rev_info revs;
 105        prune_grace_period = time(NULL)-24*60*60;
 106
 107        git_config(git_prune_config);
 108
 109        for (i = 1; i < argc; i++) {
 110                const char *arg = argv[i];
 111                if (!strcmp(arg, "-n")) {
 112                        show_only = 1;
 113                        continue;
 114                }
 115                if (!strncmp(arg, "--grace=", 8)) {
 116                        if (!strcmp(arg+8, "off"))
 117                                prune_grace_period = 0;
 118                        else
 119                                prune_grace_period = approxidate(arg+8);
 120                        continue;
 121                }
 122                usage(prune_usage);
 123        }
 124
 125        save_commit_buffer = 0;
 126        init_revisions(&revs, prefix);
 127        mark_reachable_objects(&revs, 1);
 128
 129        prune_object_dir(get_object_directory());
 130
 131        sync();
 132        prune_packed_objects(show_only);
 133        return 0;
 134}