From: Junio C Hamano Date: Wed, 24 May 2006 18:04:16 +0000 (-0700) Subject: Merge branch 'lt/dirwalk' X-Git-Tag: v1.4.0-rc1~79 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/376bb3a352d6512a318706c2fba5737ffd7cc92b?hp=-c Merge branch 'lt/dirwalk' This makes 'git add' and 'git rm' built-ins. * 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 --- 376bb3a352d6512a318706c2fba5737ffd7cc92b diff --combined Makefile index 5423b7a79b,d4a91135c3..46c83cb4c6 --- a/Makefile +++ b/Makefile @@@ -113,19 -113,19 +113,19 @@@ 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 \ git-merge-resolve.sh git-merge-ours.sh \ - git-lost-found.sh + git-lost-found.sh git-quiltimport.sh SCRIPT_PERL = \ git-archimport.perl git-cvsimport.perl git-relink.perl \ @@@ -154,24 -154,24 +154,25 @@@ 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 \ - git-receive-pack$X git-rev-list$X git-rev-parse$X \ + git-receive-pack$X git-rev-parse$X \ git-send-pack$X git-show-branch$X git-shell$X \ git-show-index$X git-ssh-fetch$X \ git-ssh-upload$X git-tar-tree$X git-unpack-file$X \ git-unpack-objects$X git-update-index$X git-update-server-info$X \ git-upload-pack$X git-verify-pack$X git-write-tree$X \ - git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \ + git-update-ref$X git-symbolic-ref$X \ git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \ git-describe$X git-merge-tree$X git-blame$X git-imap-send$X 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 \ @@@ -211,7 -211,7 +212,7 @@@ LIB_OBJS = blob.o commit.o connect.o csum-file.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 @@@ -420,9 -420,6 +421,9 @@@ els ALL_CFLAGS += -Dsockaddr_storage=sockaddr_in6 endif endif +ifdef NO_INET_NTOP + LIB_OBJS += compat/inet_ntop.o +endif ifdef NO_ICONV ALL_CFLAGS += -DNO_ICONV @@@ -464,7 -461,6 +465,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 @@@ -571,6 -567,10 +572,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 @@@ -627,14 -627,7 +628,14 @@@ install: al $(MAKE) -C templates install $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)' $(INSTALL) $(PYMODULES) '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)' - $(foreach p,$(BUILT_INS), rm -f '$(DESTDIR_SQ)$(bindir_SQ)/$p' && ln '$(DESTDIR_SQ)$(bindir_SQ)/git$X' '$(DESTDIR_SQ)$(bindir_SQ)/$p' ;) + if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \ + then \ + ln -f '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \ + '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' || \ + cp '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \ + '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \ + fi + $(foreach p,$(BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) install-doc: $(MAKE) -C Documentation install @@@ -661,25 -654,6 +662,25 @@@ dist: git.spec git-tar-tre rpm: dist $(RPMBUILD) -ta $(GIT_TARNAME).tar.gz +htmldocs = git-htmldocs-$(GIT_VERSION) +manpages = git-manpages-$(GIT_VERSION) +dist-doc: + rm -fr .doc-tmp-dir + mkdir .doc-tmp-dir + $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc + cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar . + gzip -n -9 -f $(htmldocs).tar + : + rm -fr .doc-tmp-dir + mkdir .doc-tmp-dir .doc-tmp-dir/man1 .doc-tmp-dir/man7 + $(MAKE) -C Documentation DESTDIR=. \ + man1=../.doc-tmp-dir/man1 \ + man7=../.doc-tmp-dir/man7 \ + install + cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar . + gzip -n -9 -f $(manpages).tar + rm -fr .doc-tmp-dir + ### Cleaning rules clean: @@@ -687,9 -661,8 +688,9 @@@ $(LIB_FILE) $(XDIFF_LIB) rm -f $(ALL_PROGRAMS) $(BUILT_INS) git$X rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags - rm -rf $(GIT_TARNAME) + rm -rf $(GIT_TARNAME) .doc-tmp-dir rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz + rm -f $(htmldocs).tar $(manpages).tar $(MAKE) -C Documentation/ clean $(MAKE) -C templates clean $(MAKE) -C t/ clean diff --combined builtin.h index 60541262c4,c1cb765dea..1a41d4753f --- a/builtin.h +++ b/builtin.h @@@ -24,8 -24,7 +24,10 @@@ extern int cmd_count_objects(int argc, 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 afa8e4f0ac,89aa4f6c7e..d8aa9e6047 --- a/cache.h +++ b/cache.h @@@ -142,6 -142,7 +142,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 */ @@@ -158,12 -159,6 +159,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]; diff --combined git.c index 3216d311b2,20c0f197a3..4a2c4bab7a --- a/git.c +++ b/git.c @@@ -50,9 -50,8 +50,11 @@@ static void handle_internal_command(in { "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 b95edcc14c,e8fa6d0812..32ba917923 --- a/read-cache.c +++ b/read-cache.c @@@ -331,6 -331,70 +331,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? @@@ -472,6 -536,8 +536,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)) { @@@ -496,123 -562,6 +562,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; diff --combined update-index.c index 7d6de821e2,859efc7916..5854d11fd9 --- a/update-index.c +++ b/update-index.c @@@ -18,6 -18,9 +18,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; @@@ -25,6 -28,23 +25,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; @@@ -120,70 -140,103 +120,6 @@@ static int add_file_to_cache(const cha 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. - * "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. -- * - * Also, we don't want double slashes or slashes at the - * end that can make pathnames ambiguous. - * 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 int verify_dotfile(const char *rest) -static struct cache_entry *refresh_entry(struct cache_entry *ce, int really) --{ - /* - * 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; - struct stat st; - struct cache_entry *updated; - int changed, size; -- - /* - * ".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; - 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; -- } - return 1; - - 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; --} -- - static int verify_path(const char *path) -static int refresh_cache(int really) --{ - char c; - int i; - int has_errors = 0; -- - goto inside; - for (;;) { - if (!c) - return 1; - if (c == '/') { - inside: - c = *path++; - switch (c) { - default: - 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; - case '/': case '\0': - break; - case '.': - if (verify_dotfile(path)) - 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; -- } - return 0; - if (quiet) - continue; - printf("%s: needs update\n", ce->name); - has_errors = 1; - continue; -- } - c = *path++; - 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 add_cacheinfo(unsigned int mode, const unsigned char *sha1, const char *path, int stage) { @@@ -536,7 -589,6 +472,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); @@@ -557,7 -609,7 +493,7 @@@ continue; } if (!strcmp(path, "-q")) { - quiet = 1; + refresh_flags |= REFRESH_QUIET; continue; } if (!strcmp(path, "--add")) { @@@ -573,15 -625,15 +509,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")) { @@@ -654,7 -706,7 +590,7 @@@ goto finish; } if (!strcmp(path, "--ignore-missing")) { - not_new = 1; + refresh_flags |= REFRESH_IGNORE_MISSING; continue; } if (!strcmp(path, "--verbose")) {