Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tag: v1.5.6.5
Fetching contributors…

Cannot retrieve contributors at this time

file 175 lines (154 sloc) 4.32 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
/*
* "git clean" builtin command
*
* Copyright (C) 2007 Shawn Bohrer
*
* Based on git-clean.sh by Pavel Roskin
*/

#include "builtin.h"
#include "cache.h"
#include "dir.h"
#include "parse-options.h"
#include "quote.h"

static int force = -1; /* unset */

static const char *const builtin_clean_usage[] = {
"git-clean [-d] [-f] [-n] [-q] [-x | -X] [--] <paths>...",
NULL
};

static int git_clean_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "clean.requireforce"))
force = !git_config_bool(var, value);
return git_default_config(var, value, cb);
}

int cmd_clean(int argc, const char **argv, const char *prefix)
{
int i;
int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
struct strbuf directory;
struct dir_struct dir;
const char *path, *base;
static const char **pathspec;
struct strbuf buf;
const char *qname;
char *seen = NULL;
struct option options[] = {
OPT__QUIET(&quiet),
OPT__DRY_RUN(&show_only),
OPT_BOOLEAN('f', NULL, &force, "force"),
OPT_BOOLEAN('d', NULL, &remove_directories,
"remove whole directories"),
OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"),
OPT_BOOLEAN('X', NULL, &ignored_only,
"remove only ignored files"),
OPT_END()
};

git_config(git_clean_config, NULL);
if (force < 0)
force = 0;
else
config_set = 1;

argc = parse_options(argc, argv, options, builtin_clean_usage, 0);

strbuf_init(&buf, 0);
memset(&dir, 0, sizeof(dir));
if (ignored_only)
dir.show_ignored = 1;

if (ignored && ignored_only)
die("-x and -X cannot be used together");

if (!show_only && !force)
die("clean.requireForce%s set and -n or -f not given; "
"refusing to clean", config_set ? "" : " not");

dir.show_other_directories = 1;

if (!ignored)
setup_standard_excludes(&dir);

pathspec = get_pathspec(prefix, argv);
read_cache();

/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
*/
baselen = common_prefix(pathspec);
path = ".";
base = "";
if (baselen)
path = base = xmemdupz(*pathspec, baselen);
read_directory(&dir, path, base, baselen, pathspec);
strbuf_init(&directory, 0);

if (pathspec)
seen = xmalloc(argc > 0 ? argc : 1);

for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
int len, pos;
int matches = 0;
struct cache_entry *ce;
struct stat st;

/*
* Remove the '/' at the end that directory
* walking adds for directory entries.
*/
len = ent->len;
if (len && ent->name[len-1] == '/')
len--;
pos = cache_name_pos(ent->name, len);
if (0 <= pos)
continue; /* exact match */
pos = -pos - 1;
if (pos < active_nr) {
ce = active_cache[pos];
if (ce_namelen(ce) == len &&
!memcmp(ce->name, ent->name, len))
continue; /* Yup, this one exists unmerged */
}

/*
* we might have removed this as part of earlier
* recursive directory removal, so lstat() here could
* fail with ENOENT.
*/
if (lstat(ent->name, &st))
continue;

if (pathspec) {
memset(seen, 0, argc > 0 ? argc : 1);
matches = match_pathspec(pathspec, ent->name, len,
baselen, seen);
}

if (S_ISDIR(st.st_mode)) {
strbuf_addstr(&directory, ent->name);
qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
if (show_only && (remove_directories ||
(matches == MATCHED_EXACTLY))) {
printf("Would remove %s\n", qname);
} else if (remove_directories ||
(matches == MATCHED_EXACTLY)) {
if (!quiet)
printf("Removing %s\n", qname);
if (remove_dir_recursively(&directory, 0) != 0) {
warning("failed to remove '%s'", qname);
errors++;
}
} else if (show_only) {
printf("Would not remove %s\n", qname);
} else {
printf("Not removing %s\n", qname);
}
strbuf_reset(&directory);
} else {
if (pathspec && !matches)
continue;
qname = quote_path_relative(ent->name, -1, &buf, prefix);
if (show_only) {
printf("Would remove %s\n", qname);
continue;
} else if (!quiet) {
printf("Removing %s\n", qname);
}
if (unlink(ent->name) != 0) {
warning("failed to remove '%s'", qname);
errors++;
}
}
}
free(seen);

strbuf_release(&directory);
return (errors != 0);
}
Something went wrong with that request. Please try again.