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
### --- 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 \
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)
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 \
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 \
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
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
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
$(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
$(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
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:
$(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
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
/* 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 */
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];
{ "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;
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?
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)) {
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;
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;
#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;
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)
{
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);
continue;
}
if (!strcmp(path, "-q")) {
- quiet = 1;
+ refresh_flags |= REFRESH_QUIET;
continue;
}
if (!strcmp(path, "--add")) {
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")) {
goto finish;
}
if (!strcmp(path, "--ignore-missing")) {
- not_new = 1;
+ refresh_flags |= REFRESH_IGNORE_MISSING;
continue;
}
if (!strcmp(path, "--verbose")) {