From: Junio C Hamano Date: Sat, 20 May 2006 01:06:08 +0000 (-0700) Subject: Merge branch 'master' into next X-Git-Tag: v1.4.1-rc1~81 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/ae514b4c5b51e9b4ee1071898481c01b4d90f67b?hp=-c Merge branch 'master' into next * master: Fix build procedure for builtin-init-db Allow pickaxe and diff-filter options to be used by git log. Libify the index refresh logic Builtin git-init-db --- ae514b4c5b51e9b4ee1071898481c01b4d90f67b diff --combined Makefile index 06b31d8a25,4fd6520b7e..abfc073582 --- a/Makefile +++ b/Makefile @@@ -113,14 -113,14 +113,14 @@@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__pow ### --- END CONFIGURATION SECTION --- SCRIPT_SH = \ - git-add.sh git-bisect.sh git-branch.sh git-checkout.sh \ + git-bisect.sh git-branch.sh git-checkout.sh \ git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \ git-fetch.sh \ git-format-patch.sh git-ls-remote.sh \ git-merge-one-file.sh git-parse-remote.sh \ git-prune.sh git-pull.sh git-rebase.sh \ git-repack.sh git-request-pull.sh git-reset.sh \ - git-resolve.sh git-revert.sh git-rm.sh git-sh-setup.sh \ + git-resolve.sh git-revert.sh git-sh-setup.sh \ git-tag.sh git-verify-tag.sh \ git-applymbox.sh git-applypatch.sh git-am.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ @@@ -154,7 -154,7 +154,7 @@@ PROGRAMS = git-convert-objects$X git-diff-files$X \ git-diff-index$X git-diff-stages$X \ git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \ - git-hash-object$X git-index-pack$X git-init-db$X git-local-fetch$X \ + git-hash-object$X git-index-pack$X git-local-fetch$X \ git-ls-files$X git-ls-tree$X git-mailinfo$X git-merge-base$X \ git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \ git-peek-remote$X git-prune-packed$X git-read-tree$X \ @@@ -170,8 -170,8 +170,9 @@@ BUILT_INS = git-log$X git-whatchanged$X git-show$X \ git-count-objects$X git-diff$X git-push$X \ - git-grep$X git-rev-list$X git-check-ref-format$X \ + git-grep$X git-add$X git-rm$X git-rev-list$X \ - git-check-ref-format$X ++ git-check-ref-format$X \ + git-init-db$X # what 'all' will build and 'install' will install, in gitexecdir ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) @@@ -200,7 -200,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 \ @@@ -208,10 -208,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 \ @@@ -219,8 -219,8 +220,8 @@@ BUILTIN_OBJS = \ builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \ - builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \ - builtin-init-db.o + builtin-grep.o builtin-add.o builtin-rev-list.o builtin-check-ref-format.o \ - builtin-rm.o ++ builtin-rm.o builtin-init-db.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) LIBS = $(GITLIBS) -lz @@@ -461,6 -461,7 +462,7 @@@ PYTHON_PATH_SQ = $(subst ','\'',$(PYTHO GIT_PYTHON_DIR_SQ = $(subst ','\'',$(GIT_PYTHON_DIR)) ALL_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' $(COMPAT_CFLAGS) + ALL_CFLAGS += -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' LIB_OBJS += $(COMPAT_OBJS) export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir ### Build rules @@@ -567,10 -568,6 +569,6 @@@ git-http-push$X: revision.o http.o http $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) - init-db.o: init-db.c - $(CC) -c $(ALL_CFLAGS) \ - -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c - $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst git-%$X,%.o,$(PROGRAMS)): $(GITLIBS) $(DIFF_OBJS): diffcore.h @@@ -612,9 -609,6 +610,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-log.c index d5bbc1cc06,c4ceee0f98..12a6d19203 --- a/builtin-log.c +++ b/builtin-log.c @@@ -9,10 -9,6 +9,10 @@@ #include "diff.h" #include "revision.h" #include "log-tree.h" +#include "builtin.h" + +/* this is in builtin-diff.c */ +void add_head(struct rev_info *revs); static int cmd_log_wc(int argc, const char **argv, char **envp, struct rev_info *rev) @@@ -23,6 -19,13 +23,13 @@@ rev->commit_format = CMIT_FMT_DEFAULT; rev->verbose_header = 1; argc = setup_revisions(argc, argv, rev, "HEAD"); + if (rev->always_show_header) { + if (rev->diffopt.pickaxe || rev->diffopt.filter) { + rev->always_show_header = 0; + if (rev->diffopt.output_format == DIFF_FORMAT_RAW) + rev->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT; + } + } if (argc > 1) die("unrecognized argument: %s", argv[1]); @@@ -71,160 -74,3 +78,160 @@@ int cmd_log(int argc, const char **argv rev.diffopt.recursive = 1; return cmd_log_wc(argc, argv, envp, &rev); } + +static int istitlechar(char c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || c == '.' || c == '_'; +} + +static FILE *realstdout = NULL; +static char *output_directory = NULL; + +static void reopen_stdout(struct commit *commit, int nr, int keep_subject) +{ + char filename[1024]; + char *sol; + int len = 0; + + if (output_directory) { + strncpy(filename, output_directory, 1010); + len = strlen(filename); + if (filename[len - 1] != '/') + filename[len++] = '/'; + } + + sprintf(filename + len, "%04d", nr); + len = strlen(filename); + + sol = strstr(commit->buffer, "\n\n"); + if (sol) { + int j, space = 1; + + sol += 2; + /* strip [PATCH] or [PATCH blabla] */ + if (!keep_subject && !strncmp(sol, "[PATCH", 6)) { + char *eos = strchr(sol + 6, ']'); + if (eos) { + while (isspace(*eos)) + eos++; + sol = eos; + } + } + + for (j = 0; len < 1024 - 6 && sol[j] && sol[j] != '\n'; j++) { + if (istitlechar(sol[j])) { + if (space) { + filename[len++] = '-'; + space = 0; + } + filename[len++] = sol[j]; + if (sol[j] == '.') + while (sol[j + 1] == '.') + j++; + } else + space = 1; + } + while (filename[len - 1] == '.' || filename[len - 1] == '-') + len--; + } + strcpy(filename + len, ".txt"); + fprintf(realstdout, "%s\n", filename); + freopen(filename, "w", stdout); +} + +int cmd_format_patch(int argc, const char **argv, char **envp) +{ + struct commit *commit; + struct commit **list = NULL; + struct rev_info rev; + int nr = 0, total, i, j; + int use_stdout = 0; + int numbered = 0; + int keep_subject = 0; + + init_revisions(&rev); + rev.commit_format = CMIT_FMT_EMAIL; + rev.verbose_header = 1; + rev.diff = 1; + rev.diffopt.with_raw = 0; + rev.diffopt.with_stat = 1; + rev.combine_merges = 0; + rev.ignore_merges = 1; + rev.diffopt.output_format = DIFF_FORMAT_PATCH; + + /* + * Parse the arguments before setup_revisions(), or something + * like "git fmt-patch -o a123 HEAD^.." may fail; a123 is + * possibly a valid SHA1. + */ + for (i = 1, j = 1; i < argc; i++) { + if (!strcmp(argv[i], "--stdout")) + use_stdout = 1; + else if (!strcmp(argv[i], "-n") || + !strcmp(argv[i], "--numbered")) + numbered = 1; + else if (!strcmp(argv[i], "-k") || + !strcmp(argv[i], "--keep-subject")) { + keep_subject = 1; + rev.total = -1; + } else if (!strcmp(argv[i], "-o")) { + if (argc < 3) + die ("Which directory?"); + if (mkdir(argv[i + 1], 0777) < 0 && errno != EEXIST) + die("Could not create directory %s", + argv[i + 1]); + output_directory = strdup(argv[i + 1]); + i++; + } else + argv[j++] = argv[i]; + } + argc = j; + + if (numbered && keep_subject < 0) + die ("-n and -k are mutually exclusive."); + + argc = setup_revisions(argc, argv, &rev, "HEAD"); + if (argc > 1) + die ("unrecognized argument: %s", argv[1]); + + if (rev.pending_objects && rev.pending_objects->next == NULL) { + rev.pending_objects->item->flags |= UNINTERESTING; + add_head(&rev); + } + + if (!use_stdout) + realstdout = fdopen(dup(1), "w"); + + prepare_revision_walk(&rev); + while ((commit = get_revision(&rev)) != NULL) { + /* ignore merges */ + if (commit->parents && commit->parents->next) + continue; + nr++; + list = realloc(list, nr * sizeof(list[0])); + list[nr - 1] = commit; + } + total = nr; + if (numbered) + rev.total = total; + while (0 <= --nr) { + int shown; + commit = list[nr]; + rev.nr = total - nr; + if (!use_stdout) + reopen_stdout(commit, rev.nr, keep_subject); + shown = log_tree_commit(&rev, commit); + free(commit->buffer); + commit->buffer = NULL; + if (shown) + printf("-- \n%s\n\n", git_version_string); + if (!use_stdout) + fclose(stdout); + } + if (output_directory) + free(output_directory); + free(list); + return 0; +} + diff --combined builtin.h index d150c7ce56,60541262c4..34d5e6a7a9 --- a/builtin.h +++ b/builtin.h @@@ -20,14 -20,12 +20,15 @@@ 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_rm(int argc, const char **argv, char **envp); +extern int cmd_add(int argc, const char **argv, char **envp); extern int cmd_rev_list(int argc, const char **argv, char **envp); extern int cmd_check_ref_format(int argc, const char **argv, char **envp); + extern int cmd_init_db(int argc, const char **argv, char **envp); #endif diff --combined cache.h index f9b704916d,afa8e4f0ac..31755c85a0 --- a/cache.h +++ b/cache.h @@@ -114,7 -114,6 +114,7 @@@ static inline unsigned int create_ce_mo extern struct cache_entry **active_cache; extern unsigned int active_nr, active_alloc, active_cache_changed; +extern struct cache_tree *active_cache_tree; #define GIT_DIR_ENVIRONMENT "GIT_DIR" #define DEFAULT_GIT_DIR_ENVIRONMENT ".git" @@@ -143,7 -142,6 +143,7 @@@ extern void verify_non_filename(const c /* Initialize and use the cache information */ extern int read_cache(void); extern int write_cache(int newfd, struct cache_entry **cache, int entries); +extern int verify_path(const char *path); extern int cache_name_pos(const char *name, int namelen); #define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */ #define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */ @@@ -160,6 -158,12 +160,12 @@@ extern int index_pipe(unsigned char *sh extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object); extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); + #define REFRESH_REALLY 0x0001 /* ignore_valid */ + #define REFRESH_UNMERGED 0x0002 /* allow unmerged */ + #define REFRESH_QUIET 0x0004 /* be quiet about it */ + #define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */ + extern int refresh_cache(unsigned int flags); + struct cache_file { struct cache_file *next; char lockfile[PATH_MAX]; @@@ -253,7 -257,6 +259,7 @@@ extern void *read_object_with_reference unsigned char *sha1_ret); const char *show_date(unsigned long time, int timezone); +const char *show_rfc2822_date(unsigned long time, int timezone); int parse_date(const char *date, char *buf, int bufsize); void datestamp(char *buf, int bufsize); unsigned long approxidate(const char *); diff --combined git.c index 63aa311435,3216d311b2..eab8c1f452 --- a/git.c +++ b/git.c @@@ -47,13 -47,11 +47,14 @@@ 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 }, + { "rm", cmd_rm }, + { "add", cmd_add }, { "rev-list", cmd_rev_list }, + { "init-db", cmd_init_db }, { "check-ref-format", cmd_check_ref_format } }; int i; diff --combined read-cache.c index 9a272f89fc,b95edcc14c..36bd4ea0be --- a/read-cache.c +++ b/read-cache.c @@@ -4,26 -4,11 +4,26 @@@ * Copyright (C) Linus Torvalds, 2005 */ #include "cache.h" +#include "cache-tree.h" + +/* Index extensions. + * + * The first letter should be 'A'..'Z' for extensions that are not + * necessary for a correct operation (i.e. optimization data). + * When new extensions are added that _needs_ to be understood in + * order to correctly interpret the index file, pick character that + * is outside the range, to cause the reader to abort. + */ + +#define CACHE_EXT(s) ( (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]) ) +#define CACHE_EXT_TREE 0x54524545 /* "TREE" */ struct cache_entry **active_cache = NULL; static time_t index_file_timestamp; unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0; +struct cache_tree *active_cache_tree = NULL; + /* * This only updates the "non-critical" parts of the directory * cache, ie the parts that aren't tracked by GIT, and only used @@@ -346,70 -331,6 +346,70 @@@ int ce_path_match(const struct cache_en return 0; } +/* + * We fundamentally don't like some paths: we don't want + * dot or dot-dot anywhere, and for obvious reasons don't + * want to recurse into ".git" either. + * + * Also, we don't want double slashes or slashes at the + * end that can make pathnames ambiguous. + */ +static int verify_dotfile(const char *rest) +{ + /* + * The first character was '.', but that + * has already been discarded, we now test + * the rest. + */ + switch (*rest) { + /* "." is not allowed */ + case '\0': case '/': + return 0; + + /* + * ".git" followed by NUL or slash is bad. This + * shares the path end test with the ".." case. + */ + case 'g': + if (rest[1] != 'i') + break; + if (rest[2] != 't') + break; + rest += 2; + /* fallthrough */ + case '.': + if (rest[1] == '\0' || rest[1] == '/') + return 0; + } + return 1; +} + +int verify_path(const char *path) +{ + char c; + + goto inside; + for (;;) { + if (!c) + return 1; + if (c == '/') { +inside: + c = *path++; + switch (c) { + default: + continue; + case '/': case '\0': + break; + case '.': + if (verify_dotfile(path)) + continue; + } + return 0; + } + c = *path++; + } +} + /* * Do we have another file that has the beginning components being a * proper superset of the name we're trying to add? @@@ -551,8 -472,6 +551,8 @@@ int add_cache_entry(struct cache_entry if (!ok_to_add) return -1; + if (!verify_path(ce->name)) + return -1; if (!skip_df_check && check_file_directory_conflict(ce, pos, ok_to_replace)) { @@@ -577,6 -496,123 +577,123 @@@ return 0; } + /* Three functions to allow overloaded pointer return; see linux/err.h */ + static inline void *ERR_PTR(long error) + { + return (void *) error; + } + + static inline long PTR_ERR(const void *ptr) + { + return (long) ptr; + } + + static inline long IS_ERR(const void *ptr) + { + return (unsigned long)ptr > (unsigned long)-1000L; + } + + /* + * "refresh" does not calculate a new sha1 file or bring the + * cache up-to-date for mode/content changes. But what it + * _does_ do is to "re-match" the stat information of a file + * with the cache, so that you can refresh the cache for a + * file that hasn't been changed but where the stat entry is + * out of date. + * + * For example, you'd want to do this after doing a "git-read-tree", + * to link up the stat cache details with the proper files. + */ + static struct cache_entry *refresh_entry(struct cache_entry *ce, int really) + { + struct stat st; + struct cache_entry *updated; + int changed, size; + + if (lstat(ce->name, &st) < 0) + return ERR_PTR(-errno); + + changed = ce_match_stat(ce, &st, really); + if (!changed) { + if (really && assume_unchanged && + !(ce->ce_flags & htons(CE_VALID))) + ; /* mark this one VALID again */ + else + return NULL; + } + + if (ce_modified(ce, &st, really)) + return ERR_PTR(-EINVAL); + + size = ce_size(ce); + updated = xmalloc(size); + memcpy(updated, ce, size); + fill_stat_cache_info(updated, &st); + + /* In this case, if really is not set, we should leave + * CE_VALID bit alone. Otherwise, paths marked with + * --no-assume-unchanged (i.e. things to be edited) will + * reacquire CE_VALID bit automatically, which is not + * really what we want. + */ + if (!really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID))) + updated->ce_flags &= ~htons(CE_VALID); + + return updated; + } + + int refresh_cache(unsigned int flags) + { + int i; + int has_errors = 0; + int really = (flags & REFRESH_REALLY) != 0; + int allow_unmerged = (flags & REFRESH_UNMERGED) != 0; + int quiet = (flags & REFRESH_QUIET) != 0; + int not_new = (flags & REFRESH_IGNORE_MISSING) != 0; + + for (i = 0; i < active_nr; i++) { + struct cache_entry *ce, *new; + ce = active_cache[i]; + if (ce_stage(ce)) { + while ((i < active_nr) && + ! strcmp(active_cache[i]->name, ce->name)) + i++; + i--; + if (allow_unmerged) + continue; + printf("%s: needs merge\n", ce->name); + has_errors = 1; + continue; + } + + new = refresh_entry(ce, really); + if (!new) + continue; + if (IS_ERR(new)) { + if (not_new && PTR_ERR(new) == -ENOENT) + continue; + if (really && PTR_ERR(new) == -EINVAL) { + /* If we are doing --really-refresh that + * means the index is not valid anymore. + */ + ce->ce_flags &= ~htons(CE_VALID); + active_cache_changed = 1; + } + if (quiet) + continue; + printf("%s: needs update\n", ce->name); + has_errors = 1; + continue; + } + active_cache_changed = 1; + /* You can NOT just free active_cache[i] here, since it + * might not be necessarily malloc()ed but can also come + * from mmap(). */ + active_cache[i] = new; + } + return has_errors; + } + static int verify_hdr(struct cache_header *hdr, unsigned long size) { SHA_CTX c; @@@ -594,22 -630,6 +711,22 @@@ return 0; } +static int read_index_extension(const char *ext, void *data, unsigned long sz) +{ + switch (CACHE_EXT(ext)) { + case CACHE_EXT_TREE: + active_cache_tree = cache_tree_read(data, sz); + break; + default: + if (*ext < 'A' || 'Z' < *ext) + return error("index uses %.4s extension, which we do not understand", + ext); + fprintf(stderr, "ignoring %.4s extension\n", ext); + break; + } + return 0; +} + int read_cache(void) { int fd, i; @@@ -658,22 -678,6 +775,22 @@@ active_cache[i] = ce; } index_file_timestamp = st.st_mtime; + while (offset <= size - 20 - 8) { + /* After an array of active_nr index entries, + * there can be arbitrary number of extended + * sections, each of which is prefixed with + * extension name (4-byte) and section length + * in 4-byte network byte order. + */ + unsigned long extsize; + memcpy(&extsize, map + offset + 4, 4); + extsize = ntohl(extsize); + if (read_index_extension(map + offset, + map + offset + 8, extsize) < 0) + goto unmap; + offset += 8; + offset += extsize; + } return active_nr; unmap: @@@ -708,17 -712,6 +825,17 @@@ static int ce_write(SHA_CTX *context, i return 0; } +static int write_index_ext_header(SHA_CTX *context, int fd, + unsigned long ext, unsigned long sz) +{ + ext = htonl(ext); + sz = htonl(sz); + if ((ce_write(context, fd, &ext, 4) < 0) || + (ce_write(context, fd, &sz, 4) < 0)) + return -1; + return 0; +} + static int ce_flush(SHA_CTX *context, int fd) { unsigned int left = write_buffer_len; @@@ -815,19 -808,5 +932,19 @@@ int write_cache(int newfd, struct cache if (ce_write(&c, newfd, ce, ce_size(ce)) < 0) return -1; } + + /* Write extension data here */ + if (active_cache_tree) { + unsigned long sz; + void *data = cache_tree_write(active_cache_tree, &sz); + if (data && + !write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sz) && + !ce_write(&c, newfd, data, sz)) + ; + else { + free(data); + return -1; + } + } return ce_flush(&c, newfd); } diff --combined update-index.c index 21448cc5cc,7d6de821e2..956b6b34f9 --- a/update-index.c +++ b/update-index.c @@@ -6,7 -6,6 +6,7 @@@ #include "cache.h" #include "strbuf.h" #include "quote.h" +#include "cache-tree.h" #include "tree-walk.h" /* @@@ -19,9 -18,6 +19,6 @@@ static int allow_add; static int allow_remove; static int allow_replace; - static int allow_unmerged; /* --refresh needing merge is not error */ - static int not_new; /* --refresh not having working tree files is not error */ - static int quiet; /* --refresh needing update is not error */ static int info_only; static int force_remove; static int verbose; @@@ -29,23 -25,6 +26,6 @@@ static int mark_valid_only = 0 #define MARK_VALID 1 #define UNMARK_VALID 2 - - /* Three functions to allow overloaded pointer return; see linux/err.h */ - static inline void *ERR_PTR(long error) - { - return (void *) error; - } - - static inline long PTR_ERR(const void *ptr) - { - return (long) ptr; - } - - static inline long IS_ERR(const void *ptr) - { - return (unsigned long)ptr > (unsigned long)-1000L; - } - static void report(const char *fmt, ...) { va_list vp; @@@ -72,7 -51,6 +52,7 @@@ static int mark_valid(const char *path active_cache[pos]->ce_flags &= ~htons(CE_VALID); break; } + cache_tree_invalidate_path(active_cache_tree, path); active_cache_changed = 1; return 0; } @@@ -86,12 -64,6 +66,12 @@@ static int add_file_to_cache(const cha struct stat st; status = lstat(path, &st); + + /* We probably want to do this in remove_file_from_cache() and + * add_cache_entry() instead... + */ + cache_tree_invalidate_path(active_cache_tree, path); + if (status < 0 || S_ISDIR(st.st_mode)) { /* When we used to have "path" and now we want to add * "path/file", we need a way to remove "path" before @@@ -148,103 -120,70 +128,6 @@@ return 0; } --/* - * "refresh" does not calculate a new sha1 file or bring the - * cache up-to-date for mode/content changes. But what it - * _does_ do is to "re-match" the stat information of a file - * with the cache, so that you can refresh the cache for a - * file that hasn't been changed but where the stat entry is - * out of date. - * We fundamentally don't like some paths: we don't want - * dot or dot-dot anywhere, and for obvious reasons don't - * want to recurse into ".git" either. -- * - * For example, you'd want to do this after doing a "git-read-tree", - * to link up the stat cache details with the proper files. - * Also, we don't want double slashes or slashes at the - * end that can make pathnames ambiguous. -- */ - static struct cache_entry *refresh_entry(struct cache_entry *ce, int really) -static int verify_dotfile(const char *rest) --{ - struct stat st; - struct cache_entry *updated; - int changed, size; - - if (lstat(ce->name, &st) < 0) - return ERR_PTR(-errno); - - changed = ce_match_stat(ce, &st, really); - if (!changed) { - if (really && assume_unchanged && - !(ce->ce_flags & htons(CE_VALID))) - ; /* mark this one VALID again */ - else - return NULL; - } - - if (ce_modified(ce, &st, really)) - return ERR_PTR(-EINVAL); - - size = ce_size(ce); - updated = xmalloc(size); - memcpy(updated, ce, size); - fill_stat_cache_info(updated, &st); - - /* In this case, if really is not set, we should leave - * CE_VALID bit alone. Otherwise, paths marked with - * --no-assume-unchanged (i.e. things to be edited) will - * reacquire CE_VALID bit automatically, which is not - * really what we want. - /* - * The first character was '.', but that - * has already been discarded, we now test - * the rest. -- */ - if (!really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID))) - updated->ce_flags &= ~htons(CE_VALID); - switch (*rest) { - /* "." is not allowed */ - case '\0': case '/': - return 0; -- - return updated; - /* - * ".git" followed by NUL or slash is bad. This - * shares the path end test with the ".." case. - */ - case 'g': - if (rest[1] != 'i') - break; - if (rest[2] != 't') - break; - rest += 2; - /* fallthrough */ - case '.': - if (rest[1] == '\0' || rest[1] == '/') - return 0; - } - return 1; --} -- - static int refresh_cache(int really) -static int verify_path(const char *path) --{ - int i; - int has_errors = 0; - - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce, *new; - ce = active_cache[i]; - if (ce_stage(ce)) { - while ((i < active_nr) && - ! strcmp(active_cache[i]->name, ce->name)) - i++; - i--; - if (allow_unmerged) - continue; - printf("%s: needs merge\n", ce->name); - has_errors = 1; - continue; - } - char c; -- - new = refresh_entry(ce, really); - if (!new) - continue; - if (IS_ERR(new)) { - if (not_new && PTR_ERR(new) == -ENOENT) - goto inside; - for (;;) { - if (!c) - return 1; - if (c == '/') { -inside: - c = *path++; - switch (c) { - default: -- continue; - if (really && PTR_ERR(new) == -EINVAL) { - /* If we are doing --really-refresh that - * means the index is not valid anymore. - */ - ce->ce_flags &= ~htons(CE_VALID); - active_cache_changed = 1; - case '/': case '\0': - break; - case '.': - if (verify_dotfile(path)) - continue; -- } - if (quiet) - continue; - printf("%s: needs update\n", ce->name); - has_errors = 1; - continue; - return 0; -- } - active_cache_changed = 1; - /* You can NOT just free active_cache[i] here, since it - * might not be necessarily malloc()ed but can also come - * from mmap(). */ - active_cache[i] = new; - c = *path++; -- } - return has_errors; --} -- static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, const char *path, int stage) { @@@ -270,7 -209,6 +153,7 @@@ return error("%s: cannot add to the index - missing --add option?", path); report("add '%s'", path); + cache_tree_invalidate_path(active_cache_tree, path); return 0; } @@@ -295,7 -233,6 +178,7 @@@ static void chmod_path(int flip, const default: goto fail; } + cache_tree_invalidate_path(active_cache_tree, path); active_cache_changed = 1; report("chmod %cx '%s'", flip, path); return; @@@ -317,7 -254,6 +200,7 @@@ static void update_one(const char *path die("Unable to mark file %s", path); goto free_return; } + cache_tree_invalidate_path(active_cache_tree, path); if (force_remove) { if (remove_file_from_cache(p)) @@@ -396,7 -332,6 +279,7 @@@ static void read_index_info(int line_te free(path_name); continue; } + cache_tree_invalidate_path(active_cache_tree, path_name); if (!mode) { /* mode == 0 means there is no such path -- remove */ @@@ -503,7 -438,6 +386,7 @@@ static int unresolve_one(const char *pa goto free_return; } + cache_tree_invalidate_path(active_cache_tree, path); remove_file_from_cache(path); if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) { error("%s: cannot add our version to the index.", path); @@@ -602,6 -536,7 +485,7 @@@ int main(int argc, const char **argv const char *prefix = setup_git_directory(); int prefix_length = prefix ? strlen(prefix) : 0; char set_executable_bit = 0; + unsigned int refresh_flags = 0; git_config(git_default_config); @@@ -622,7 -557,7 +506,7 @@@ continue; } if (!strcmp(path, "-q")) { - quiet = 1; + refresh_flags |= REFRESH_QUIET; continue; } if (!strcmp(path, "--add")) { @@@ -638,15 -573,15 +522,15 @@@ continue; } if (!strcmp(path, "--unmerged")) { - allow_unmerged = 1; + refresh_flags |= REFRESH_UNMERGED; continue; } if (!strcmp(path, "--refresh")) { - has_errors |= refresh_cache(0); + has_errors |= refresh_cache(refresh_flags); continue; } if (!strcmp(path, "--really-refresh")) { - has_errors |= refresh_cache(1); + has_errors |= refresh_cache(REFRESH_REALLY | refresh_flags); continue; } if (!strcmp(path, "--cacheinfo")) { @@@ -719,7 -654,7 +603,7 @@@ goto finish; } if (!strcmp(path, "--ignore-missing")) { - not_new = 1; + refresh_flags |= REFRESH_IGNORE_MISSING; continue; } if (!strcmp(path, "--verbose")) {