git-commit-vandalism/builtin-prune.c
Johannes Schindelin f01913e419 Add "--expire <time>" option to 'git prune'
Earlier, 'git prune' would prune all loose unreachable objects.
This could be quite dangerous, as the objects could be used in
an ongoing operation.

This patch adds a mode to expire only loose, unreachable objects
which are older than a certain time.  For example, by

	git prune --expire 14.days

you can prune only those objects which are loose, unreachable
and older than 14 days (and thus probably outdated).

The implementation uses st.st_mtime rather than st.st_ctime,
because it can be tested better, using 'touch -d <time>' (and
omitting the test when the platform does not support that
command line switch).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-30 15:47:01 -08:00

120 lines
2.3 KiB
C

#include "cache.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"
#include "builtin.h"
#include "reachable.h"
static const char prune_usage[] = "git-prune [-n]";
static int show_only;
static unsigned long expire;
static int prune_object(char *path, const char *filename, const unsigned char *sha1)
{
const char *fullpath = mkpath("%s/%s", path, filename);
if (expire) {
struct stat st;
if (lstat(fullpath, &st))
return error("Could not stat '%s'", fullpath);
if (st.st_mtime > expire)
return 0;
}
if (show_only) {
enum object_type type = sha1_object_info(sha1, NULL);
printf("%s %s\n", sha1_to_hex(sha1),
(type > 0) ? typename(type) : "unknown");
} else
unlink(fullpath);
return 0;
}
static int prune_dir(int i, char *path)
{
DIR *dir = opendir(path);
struct dirent *de;
if (!dir)
return 0;
while ((de = readdir(dir)) != NULL) {
char name[100];
unsigned char sha1[20];
int len = strlen(de->d_name);
switch (len) {
case 2:
if (de->d_name[1] != '.')
break;
case 1:
if (de->d_name[0] != '.')
break;
continue;
case 38:
sprintf(name, "%02x", i);
memcpy(name+2, de->d_name, len+1);
if (get_sha1_hex(name, sha1) < 0)
break;
/*
* Do we know about this object?
* It must have been reachable
*/
if (lookup_object(sha1))
continue;
prune_object(path, de->d_name, sha1);
continue;
}
fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
}
if (!show_only)
rmdir(path);
closedir(dir);
return 0;
}
static void prune_object_dir(const char *path)
{
int i;
for (i = 0; i < 256; i++) {
static char dir[4096];
sprintf(dir, "%s/%02x", path, i);
prune_dir(i, dir);
}
}
int cmd_prune(int argc, const char **argv, const char *prefix)
{
int i;
struct rev_info revs;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "-n")) {
show_only = 1;
continue;
}
if (!strcmp(arg, "--expire")) {
if (++i < argc) {
expire = approxidate(argv[i]);
continue;
}
}
else if (!prefixcmp(arg, "--expire=")) {
expire = approxidate(arg + 9);
continue;
}
usage(prune_usage);
}
save_commit_buffer = 0;
init_revisions(&revs, prefix);
mark_reachable_objects(&revs, 1);
prune_object_dir(get_object_directory());
sync();
prune_packed_objects(show_only);
return 0;
}