-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'lt/dirwalk' into jc/dirwalk-n-cache-tree
This commit is what this branch is all about. It records the evil merge needed to adjust built-in git-add and git-rm for the cache-tree extension. * lt/dirwalk: Add builtin "git rm" command Move pathspec matching from builtin-add.c into dir.c Prevent bogus paths from being added to the index. builtin-add: fix unmatched pathspec warnings. Remove old "git-add.sh" remnants builtin-add: warn on unmatched pathspecs Do "git add" as a builtin Clean up git-ls-file directory walking library interface libify git-ls-files directory traversal Conflicts: Makefile builtin.h git.c update-index.c
- Loading branch information
Showing
13 changed files
with
899 additions
and
550 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
/* | ||
* "git add" builtin command | ||
* | ||
* Copyright (C) 2006 Linus Torvalds | ||
*/ | ||
#include <fnmatch.h> | ||
|
||
#include "cache.h" | ||
#include "builtin.h" | ||
#include "dir.h" | ||
#include "cache-tree.h" | ||
|
||
static const char builtin_add_usage[] = | ||
"git-add [-n] [-v] <filepattern>..."; | ||
|
||
static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix) | ||
{ | ||
char *seen; | ||
int i, specs; | ||
struct dir_entry **src, **dst; | ||
|
||
for (specs = 0; pathspec[specs]; specs++) | ||
/* nothing */; | ||
seen = xmalloc(specs); | ||
memset(seen, 0, specs); | ||
|
||
src = dst = dir->entries; | ||
i = dir->nr; | ||
while (--i >= 0) { | ||
struct dir_entry *entry = *src++; | ||
if (!match_pathspec(pathspec, entry->name, entry->len, prefix, seen)) { | ||
free(entry); | ||
continue; | ||
} | ||
*dst++ = entry; | ||
} | ||
dir->nr = dst - dir->entries; | ||
|
||
for (i = 0; i < specs; i++) { | ||
struct stat st; | ||
const char *match; | ||
if (seen[i]) | ||
continue; | ||
|
||
/* Existing file? We must have ignored it */ | ||
match = pathspec[i]; | ||
if (!match[0] || !lstat(match, &st)) | ||
continue; | ||
die("pathspec '%s' did not match any files", match); | ||
} | ||
} | ||
|
||
static void fill_directory(struct dir_struct *dir, const char **pathspec) | ||
{ | ||
const char *path, *base; | ||
int baselen; | ||
|
||
/* Set up the default git porcelain excludes */ | ||
memset(dir, 0, sizeof(*dir)); | ||
dir->exclude_per_dir = ".gitignore"; | ||
path = git_path("info/exclude"); | ||
if (!access(path, R_OK)) | ||
add_excludes_from_file(dir, path); | ||
|
||
/* | ||
* Calculate common prefix for the pathspec, and | ||
* use that to optimize the directory walk | ||
*/ | ||
baselen = common_prefix(pathspec); | ||
path = "."; | ||
base = ""; | ||
if (baselen) { | ||
char *common = xmalloc(baselen + 1); | ||
common = xmalloc(baselen + 1); | ||
memcpy(common, *pathspec, baselen); | ||
common[baselen] = 0; | ||
path = base = common; | ||
} | ||
|
||
/* Read the directory and prune it */ | ||
read_directory(dir, path, base, baselen); | ||
if (pathspec) | ||
prune_directory(dir, pathspec, baselen); | ||
} | ||
|
||
static int add_file_to_index(const char *path, int verbose) | ||
{ | ||
int size, namelen; | ||
struct stat st; | ||
struct cache_entry *ce; | ||
|
||
if (lstat(path, &st)) | ||
die("%s: unable to stat (%s)", path, strerror(errno)); | ||
|
||
if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) | ||
die("%s: can only add regular files or symbolic links", path); | ||
|
||
namelen = strlen(path); | ||
size = cache_entry_size(namelen); | ||
ce = xcalloc(1, size); | ||
memcpy(ce->name, path, namelen); | ||
ce->ce_flags = htons(namelen); | ||
fill_stat_cache_info(ce, &st); | ||
|
||
ce->ce_mode = create_ce_mode(st.st_mode); | ||
if (!trust_executable_bit) { | ||
/* If there is an existing entry, pick the mode bits | ||
* from it. | ||
*/ | ||
int pos = cache_name_pos(path, namelen); | ||
if (pos >= 0) | ||
ce->ce_mode = active_cache[pos]->ce_mode; | ||
} | ||
|
||
if (index_path(ce->sha1, path, &st, 1)) | ||
die("unable to index file %s", path); | ||
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD)) | ||
die("unable to add %s to index",path); | ||
if (verbose) | ||
printf("add '%s'\n", path); | ||
cache_tree_invalidate_path(active_cache_tree, path); | ||
return 0; | ||
} | ||
|
||
static struct cache_file cache_file; | ||
|
||
int cmd_add(int argc, const char **argv, char **envp) | ||
{ | ||
int i, newfd; | ||
int verbose = 0, show_only = 0; | ||
const char *prefix = setup_git_directory(); | ||
const char **pathspec; | ||
struct dir_struct dir; | ||
|
||
git_config(git_default_config); | ||
|
||
newfd = hold_index_file_for_update(&cache_file, get_index_file()); | ||
if (newfd < 0) | ||
die("unable to create new cachefile"); | ||
|
||
if (read_cache() < 0) | ||
die("index file corrupt"); | ||
|
||
for (i = 1; i < argc; i++) { | ||
const char *arg = argv[i]; | ||
|
||
if (arg[0] != '-') | ||
break; | ||
if (!strcmp(arg, "--")) { | ||
i++; | ||
break; | ||
} | ||
if (!strcmp(arg, "-n")) { | ||
show_only = 1; | ||
continue; | ||
} | ||
if (!strcmp(arg, "-v")) { | ||
verbose = 1; | ||
continue; | ||
} | ||
die(builtin_add_usage); | ||
} | ||
git_config(git_default_config); | ||
pathspec = get_pathspec(prefix, argv + i); | ||
|
||
fill_directory(&dir, pathspec); | ||
|
||
if (show_only) { | ||
const char *sep = "", *eof = ""; | ||
for (i = 0; i < dir.nr; i++) { | ||
printf("%s%s", sep, dir.entries[i]->name); | ||
sep = " "; | ||
eof = "\n"; | ||
} | ||
fputs(eof, stdout); | ||
return 0; | ||
} | ||
|
||
for (i = 0; i < dir.nr; i++) | ||
add_file_to_index(dir.entries[i]->name, verbose); | ||
|
||
if (active_cache_changed) { | ||
if (write_cache(newfd, active_cache, active_nr) || | ||
commit_index_file(&cache_file)) | ||
die("Unable to write new index file"); | ||
} | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/* | ||
* "git rm" builtin command | ||
* | ||
* Copyright (C) Linus Torvalds 2006 | ||
*/ | ||
#include "cache.h" | ||
#include "builtin.h" | ||
#include "dir.h" | ||
|
||
static const char builtin_rm_usage[] = | ||
"git-rm [-n] [-v] [-f] <filepattern>..."; | ||
|
||
static struct { | ||
int nr, alloc; | ||
const char **name; | ||
} list; | ||
|
||
static void add_list(const char *name) | ||
{ | ||
if (list.nr >= list.alloc) { | ||
list.alloc = alloc_nr(list.alloc); | ||
list.name = xrealloc(list.name, list.alloc * sizeof(const char *)); | ||
} | ||
list.name[list.nr++] = name; | ||
} | ||
|
||
static int remove_file(const char *name) | ||
{ | ||
int ret; | ||
char *slash; | ||
|
||
ret = unlink(name); | ||
if (!ret && (slash = strrchr(name, '/'))) { | ||
char *n = strdup(name); | ||
do { | ||
n[slash - name] = 0; | ||
name = n; | ||
} while (!rmdir(name) && (slash = strrchr(name, '/'))); | ||
} | ||
return ret; | ||
} | ||
|
||
static struct cache_file cache_file; | ||
|
||
int cmd_rm(int argc, const char **argv, char **envp) | ||
{ | ||
int i, newfd; | ||
int verbose = 0, show_only = 0, force = 0; | ||
const char *prefix = setup_git_directory(); | ||
const char **pathspec; | ||
char *seen; | ||
|
||
git_config(git_default_config); | ||
|
||
newfd = hold_index_file_for_update(&cache_file, get_index_file()); | ||
if (newfd < 0) | ||
die("unable to create new index file"); | ||
|
||
if (read_cache() < 0) | ||
die("index file corrupt"); | ||
|
||
for (i = 1 ; i < argc ; i++) { | ||
const char *arg = argv[i]; | ||
|
||
if (*arg != '-') | ||
break; | ||
if (!strcmp(arg, "--")) { | ||
i++; | ||
break; | ||
} | ||
if (!strcmp(arg, "-n")) { | ||
show_only = 1; | ||
continue; | ||
} | ||
if (!strcmp(arg, "-v")) { | ||
verbose = 1; | ||
continue; | ||
} | ||
if (!strcmp(arg, "-f")) { | ||
force = 1; | ||
continue; | ||
} | ||
die(builtin_rm_usage); | ||
} | ||
pathspec = get_pathspec(prefix, argv + i); | ||
|
||
seen = NULL; | ||
if (pathspec) { | ||
for (i = 0; pathspec[i] ; i++) | ||
/* nothing */; | ||
seen = xmalloc(i); | ||
memset(seen, 0, i); | ||
} | ||
|
||
for (i = 0; i < active_nr; i++) { | ||
struct cache_entry *ce = active_cache[i]; | ||
if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen)) | ||
continue; | ||
add_list(ce->name); | ||
} | ||
|
||
if (pathspec) { | ||
const char *match; | ||
for (i = 0; (match = pathspec[i]) != NULL ; i++) { | ||
if (*match && !seen[i]) | ||
die("pathspec '%s' did not match any files", match); | ||
} | ||
} | ||
|
||
/* | ||
* First remove the names from the index: we won't commit | ||
* the index unless all of them succeed | ||
*/ | ||
for (i = 0; i < list.nr; i++) { | ||
const char *path = list.name[i]; | ||
printf("rm '%s'\n", path); | ||
|
||
if (remove_file_from_cache(path)) | ||
die("git rm: unable to remove %s", path); | ||
cache_tree_invalidate_path(active_cache_tree, path); | ||
} | ||
|
||
/* | ||
* Then, if we used "-f", remove the filenames from the | ||
* workspace. If we fail to remove the first one, we | ||
* abort the "git rm" (but once we've successfully removed | ||
* any file at all, we'll go ahead and commit to it all: | ||
* by then we've already committed ourself and can't fail | ||
* in the middle) | ||
*/ | ||
if (force) { | ||
int removed = 0; | ||
for (i = 0; i < list.nr; i++) { | ||
const char *path = list.name[i]; | ||
if (!remove_file(path)) { | ||
removed = 1; | ||
continue; | ||
} | ||
if (!removed) | ||
die("git rm: %s: %s", path, strerror(errno)); | ||
} | ||
} | ||
|
||
if (active_cache_changed) { | ||
if (write_cache(newfd, active_cache, active_nr) || | ||
commit_index_file(&cache_file)) | ||
die("Unable to write new index file"); | ||
} | ||
|
||
return 0; | ||
} |
Oops, something went wrong.