From: Junio C Hamano Date: Wed, 17 May 2006 22:32:45 +0000 (-0700) Subject: Merge branch 'lt/dirwalk' into next X-Git-Tag: v1.4.1-rc1~94 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/ae12e59a8c895e48d4ef52ac6936674ac7be6370?hp=-c Merge branch 'lt/dirwalk' into next * lt/dirwalk: 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 Not a conflict, but builtin-add needed to be adjusted to properly invalidate the cache_tree entry. --- ae12e59a8c895e48d4ef52ac6936674ac7be6370 diff --combined Makefile index 0aeb94c55d,e6f7794ad0..2c87886c44 --- a/Makefile +++ b/Makefile @@@ -46,8 -46,6 +46,8 @@@ all # # Define NO_MMAP if you want to avoid mmap. # +# Define NO_H_OPTION_IN_GREP if your grep does not understand -H. +# # Define WITH_OWN_SUBPROCESS_PY if you want to use with python 2.3. # # Define NO_IPV6 if you lack IPv6 support and getaddrinfo(). @@@ -201,7 -199,7 +201,7 @@@ LIB_H = blob.h cache.h commit.h csum-file.h delta.h \ diff.h object.h pack.h pkt-line.h quote.h refs.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ - tree-walk.h log-tree.h + tree-walk.h log-tree.h dir.h DIFF_OBJS = \ diff.o diff-lib.o diffcore-break.o diffcore-order.o \ @@@ -209,10 -207,10 +209,10 @@@ diffcore-delta.o log-tree.o LIB_OBJS = \ - blob.o commit.o connect.o csum-file.o base85.o \ + blob.o commit.o connect.o csum-file.o cache-tree.o base85.o \ date.o diff-delta.o entry.o exec_cmd.o ident.o index.o \ object.o pack-check.o patch-delta.o path.o pkt-line.o \ - quote.o read-cache.o refs.o run-command.o \ + quote.o read-cache.o refs.o run-command.o dir.o \ server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \ tag.o tree.o usage.o config.o environment.o ctype.o copy.o \ fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \ @@@ -220,7 -218,7 +220,7 @@@ BUILTIN_OBJS = \ builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \ - builtin-grep.o + builtin-grep.o builtin-add.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) LIBS = $(GITLIBS) -lz @@@ -446,12 -444,6 +446,12 @@@ ifdef NO_ACCURATE_DIF ALL_CFLAGS += -DNO_ACCURATE_DIFF endif +ifdef NO_H_OPTION_IN_GREP + NO_H_OPTION_IN_GREP=1 +else + NO_H_OPTION_IN_GREP=0 +endif + # Shell quote (do not use $(call) to accomodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) @@@ -534,9 -526,6 +534,9 @@@ git$X git.spec %.o: %.S $(CC) -o $*.o -c $(ALL_CFLAGS) $< +builtin-grep.o: builtin-grep.c + $(CC) -o $*.o -c $(ALL_CFLAGS) -DNO_H_OPTION_IN_GREP=$(NO_H_OPTION_IN_GREP) $< + exec_cmd.o: exec_cmd.c $(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' $< @@@ -621,9 -610,6 +621,9 @@@ test-date$X: test-date.c date.o ctype. test-delta$X: test-delta.c diff-delta.o patch-delta.o $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^ +test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS) + $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) + check: for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done diff --combined builtin-add.c index 0000000000,089c7a89b3..7083820f7b mode 000000,100644..100644 --- a/builtin-add.c +++ b/builtin-add.c @@@ -1,0 -1,267 +1,269 @@@ + /* + * "git add" builtin command + * + * Copyright (C) 2006 Linus Torvalds + */ + #include + + #include "cache.h" + #include "builtin.h" + #include "dir.h" ++#include "cache-tree.h" + + static const char builtin_add_usage[] = + "git-add [-n] [-v] ..."; + + static int common_prefix(const char **pathspec) + { + const char *path, *slash, *next; + int prefix; + + if (!pathspec) + return 0; + + path = *pathspec; + slash = strrchr(path, '/'); + if (!slash) + return 0; + + prefix = slash - path + 1; + while ((next = *++pathspec) != NULL) { + int len = strlen(next); + if (len >= prefix && !memcmp(path, next, len)) + continue; + for (;;) { + if (!len) + return 0; + if (next[--len] != '/') + continue; + if (memcmp(path, next, len+1)) + continue; + prefix = len + 1; + break; + } + } + return prefix; + } + + static int match_one(const char *match, const char *name, int namelen) + { + int matchlen; + + /* If the match was just the prefix, we matched */ + matchlen = strlen(match); + if (!matchlen) + return 1; + + /* + * If we don't match the matchstring exactly, + * we need to match by fnmatch + */ + if (strncmp(match, name, matchlen)) + return !fnmatch(match, name, 0); + + /* + * If we did match the string exactly, we still + * need to make sure that it happened on a path + * component boundary (ie either the last character + * of the match was '/', or the next character of + * the name was '/' or the terminating NUL. + */ + return match[matchlen-1] == '/' || + name[matchlen] == '/' || + !name[matchlen]; + } + + static int match(const char **pathspec, const char *name, int namelen, int prefix, char *seen) + { + int retval; + const char *match; + + name += prefix; + namelen -= prefix; + + for (retval = 0; (match = *pathspec++) != NULL; seen++) { + if (retval & *seen) + continue; + match += prefix; + if (match_one(match, name, namelen)) { + retval = 1; + *seen = 1; + } + } + return retval; + } + + 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, 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 (!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; + } diff --combined builtin.h index 97e2464468,1b77f4b0ca..ccd0e31b2c --- a/builtin.h +++ b/builtin.h @@@ -20,10 -20,10 +20,11 @@@ extern int cmd_whatchanged(int argc, co extern int cmd_show(int argc, const char **argv, char **envp); extern int cmd_log(int argc, const char **argv, char **envp); extern int cmd_diff(int argc, const char **argv, char **envp); +extern int cmd_format_patch(int argc, const char **argv, char **envp); extern int cmd_count_objects(int argc, const char **argv, char **envp); extern int cmd_push(int argc, const char **argv, char **envp); extern int cmd_grep(int argc, const char **argv, char **envp); + extern int cmd_add(int argc, const char **argv, char **envp); #endif diff --combined git.c index 84803a62e6,fac46af057..6a470cf140 --- a/git.c +++ b/git.c @@@ -47,10 -47,10 +47,11 @@@ static void handle_internal_command(in { "whatchanged", cmd_whatchanged }, { "show", cmd_show }, { "push", cmd_push }, + { "fmt-patch", cmd_format_patch }, { "count-objects", cmd_count_objects }, { "diff", cmd_diff }, { "grep", cmd_grep }, + { "add", cmd_add }, }; int i;