From: Junio C Hamano Date: Wed, 26 Oct 2016 20:14:44 +0000 (-0700) Subject: Merge branch 'bw/ls-files-recurse-submodules' X-Git-Tag: v2.11.0-rc0~47 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/1c2b1f7018ba7d5f6a5d949e29e4eaeeef3261e2?hp=-c Merge branch 'bw/ls-files-recurse-submodules' "git ls-files" learned "--recurse-submodules" option that can be used to get a listing of tracked files across submodules (i.e. this only works with "--cached" option, not for listing untracked or ignored files). This would be a useful tool to sit on the upstream side of a pipe that is read with xargs to work on all working tree files from the top-level superproject. * bw/ls-files-recurse-submodules: ls-files: add pathspec matching for submodules ls-files: pass through safe options for --recurse-submodules ls-files: optionally recurse into submodules git: make super-prefix option --- 1c2b1f7018ba7d5f6a5d949e29e4eaeeef3261e2 diff --combined Documentation/git.txt index b8bec711f4,2188ae6056..2cf7e225f5 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@@ -13,6 -13,7 +13,7 @@@ SYNOPSI [--exec-path[=]] [--html-path] [--man-path] [--info-path] [-p|--paginate|--no-pager] [--no-replace-objects] [--bare] [--git-dir=] [--work-tree=] [--namespace=] + [--super-prefix=] [] DESCRIPTION @@@ -43,10 -44,9 +44,10 @@@ unreleased) version of Git, that is ava branch of the `git.git` repository. Documentation for older releases are available here: -* link:v2.10.0/git.html[documentation for release 2.10] +* link:v2.10.1/git.html[documentation for release 2.10.1] * release notes for + link:RelNotes/2.10.1.txt[2.10.1], link:RelNotes/2.10.0.txt[2.10]. * link:v2.9.3/git.html[documentation for release 2.9.3] @@@ -602,6 -602,11 +603,11 @@@ foo.bar= ...`) sets `foo.bar` to the em details. Equivalent to setting the `GIT_NAMESPACE` environment variable. + --super-prefix=:: + Currently for internal use only. Set a prefix which gives a path from + above a repository down to its root. One use is to give submodules + context about the superproject that invoked it. + --bare:: Treat the repository as a bare repository. If GIT_DIR environment is not set, it is set to the current working diff --combined builtin/ls-files.c index 197f153f50,0f25914348..1592290815 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@@ -14,6 -14,7 +14,7 @@@ #include "resolve-undo.h" #include "string-list.h" #include "pathspec.h" + #include "run-command.h" static int abbrev; static int show_deleted; @@@ -28,8 -29,11 +29,11 @@@ static int show_valid_bit static int line_terminator = '\n'; static int debug_mode; static int show_eol; + static int recurse_submodules; + static struct argv_array submodules_options = ARGV_ARRAY_INIT; static const char *prefix; + static const char *super_prefix; static int max_prefix_len; static int prefix_len; static struct pathspec pathspec; @@@ -67,12 -71,25 +71,25 @@@ static void write_eolinfo(const struct static void write_name(const char *name) { + /* + * Prepend the super_prefix to name to construct the full_name to be + * written. + */ + struct strbuf full_name = STRBUF_INIT; + if (super_prefix) { + strbuf_addstr(&full_name, super_prefix); + strbuf_addstr(&full_name, name); + name = full_name.buf; + } + /* * With "--full-name", prefix_len=0; this caller needs to pass * an empty string in that case (a NULL is good for ""). */ write_name_quoted_relative(name, prefix_len ? prefix : NULL, stdout, line_terminator); + + strbuf_release(&full_name); } static void show_dir_entry(const char *tag, struct dir_entry *ent) @@@ -152,55 -169,117 +169,117 @@@ static void show_killed_files(struct di } } + /* + * Compile an argv_array with all of the options supported by --recurse_submodules + */ + static void compile_submodule_options(const struct dir_struct *dir, int show_tag) + { + if (line_terminator == '\0') + argv_array_push(&submodules_options, "-z"); + if (show_tag) + argv_array_push(&submodules_options, "-t"); + if (show_valid_bit) + argv_array_push(&submodules_options, "-v"); + if (show_cached) + argv_array_push(&submodules_options, "--cached"); + if (show_eol) + argv_array_push(&submodules_options, "--eol"); + if (debug_mode) + argv_array_push(&submodules_options, "--debug"); + } + + /** + * Recursively call ls-files on a submodule + */ + static void show_gitlink(const struct cache_entry *ce) + { + struct child_process cp = CHILD_PROCESS_INIT; + int status; + int i; + + argv_array_pushf(&cp.args, "--super-prefix=%s%s/", + super_prefix ? super_prefix : "", + ce->name); + argv_array_push(&cp.args, "ls-files"); + argv_array_push(&cp.args, "--recurse-submodules"); + + /* add supported options */ + argv_array_pushv(&cp.args, submodules_options.argv); + + /* + * Pass in the original pathspec args. The submodule will be + * responsible for prepending the 'submodule_prefix' prior to comparing + * against the pathspec for matches. + */ + argv_array_push(&cp.args, "--"); + for (i = 0; i < pathspec.nr; i++) + argv_array_push(&cp.args, pathspec.items[i].original); + + cp.git_cmd = 1; + cp.dir = ce->name; + status = run_command(&cp); + if (status) + exit(status); + } + static void show_ce_entry(const char *tag, const struct cache_entry *ce) { + struct strbuf name = STRBUF_INIT; int len = max_prefix_len; + if (super_prefix) + strbuf_addstr(&name, super_prefix); + strbuf_addstr(&name, ce->name); if (len >= ce_namelen(ce)) die("git ls-files: internal error - cache entry not superset of prefix"); - if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce), - len, ps_matched, - S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode))) - return; + if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && + submodule_path_match(&pathspec, name.buf, ps_matched)) { + show_gitlink(ce); + } else if (match_pathspec(&pathspec, name.buf, name.len, + len, ps_matched, + S_ISDIR(ce->ce_mode) || + S_ISGITLINK(ce->ce_mode))) { + if (tag && *tag && show_valid_bit && + (ce->ce_flags & CE_VALID)) { + static char alttag[4]; + memcpy(alttag, tag, 3); + if (isalpha(tag[0])) + alttag[0] = tolower(tag[0]); + else if (tag[0] == '?') + alttag[0] = '!'; + else { + alttag[0] = 'v'; + alttag[1] = tag[0]; + alttag[2] = ' '; + alttag[3] = 0; + } + tag = alttag; + } - if (tag && *tag && show_valid_bit && - (ce->ce_flags & CE_VALID)) { - static char alttag[4]; - memcpy(alttag, tag, 3); - if (isalpha(tag[0])) - alttag[0] = tolower(tag[0]); - else if (tag[0] == '?') - alttag[0] = '!'; - else { - alttag[0] = 'v'; - alttag[1] = tag[0]; - alttag[2] = ' '; - alttag[3] = 0; + if (!show_stage) { + fputs(tag, stdout); + } else { + printf("%s%06o %s %d\t", + tag, + ce->ce_mode, - find_unique_abbrev(ce->sha1,abbrev), ++ find_unique_abbrev(ce->oid.hash, abbrev), + ce_stage(ce)); + } + write_eolinfo(ce, ce->name); + write_name(ce->name); + if (debug_mode) { + const struct stat_data *sd = &ce->ce_stat_data; + + printf(" ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec); + printf(" mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec); + printf(" dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino); + printf(" uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid); + printf(" size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags); } - tag = alttag; } - if (!show_stage) { - fputs(tag, stdout); - } else { - printf("%s%06o %s %d\t", - tag, - ce->ce_mode, - find_unique_abbrev(ce->oid.hash,abbrev), - ce_stage(ce)); - } - write_eolinfo(ce, ce->name); - write_name(ce->name); - if (debug_mode) { - const struct stat_data *sd = &ce->ce_stat_data; - - printf(" ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec); - printf(" mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec); - printf(" dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino); - printf(" uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid); - printf(" size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags); - } + strbuf_release(&name); } static void show_ru_info(void) @@@ -468,6 -547,8 +547,8 @@@ int cmd_ls_files(int argc, const char * { OPTION_SET_INT, 0, "full-name", &prefix_len, NULL, N_("make the output relative to the project top directory"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL }, + OPT_BOOL(0, "recurse-submodules", &recurse_submodules, + N_("recurse through submodules")), OPT_BOOL(0, "error-unmatch", &error_unmatch, N_("if any is not in the index, treat this as an error")), OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"), @@@ -484,6 -565,7 +565,7 @@@ prefix = cmd_prefix; if (prefix) prefix_len = strlen(prefix); + super_prefix = get_super_prefix(); git_config(git_default_config, NULL); if (read_cache() < 0) @@@ -519,13 -601,32 +601,32 @@@ if (require_work_tree && !is_inside_work_tree()) setup_work_tree(); + if (recurse_submodules) + compile_submodule_options(&dir, show_tag); + + if (recurse_submodules && + (show_stage || show_deleted || show_others || show_unmerged || + show_killed || show_modified || show_resolve_undo || with_tree)) + die("ls-files --recurse-submodules unsupported mode"); + + if (recurse_submodules && error_unmatch) + die("ls-files --recurse-submodules does not support " + "--error-unmatch"); + parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD | PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP, prefix, argv); - /* Find common prefix for all pathspec's */ - max_prefix = common_prefix(&pathspec); + /* + * Find common prefix for all pathspec's + * This is used as a performance optimization which unfortunately cannot + * be done when recursing into submodules + */ + if (recurse_submodules) + max_prefix = NULL; + else + max_prefix = common_prefix(&pathspec); max_prefix_len = max_prefix ? strlen(max_prefix) : 0; /* Treat unmatching pathspec elements as errors */ diff --combined cache.h index 05ecb889eb,8cf495db75..5f2f03090f --- a/cache.h +++ b/cache.h @@@ -173,7 -173,7 +173,7 @@@ struct cache_entry unsigned int ce_flags; unsigned int ce_namelen; unsigned int index; /* for link extension */ - unsigned char sha1[20]; + struct object_id oid; char name[FLEX_ARRAY]; /* more */ }; @@@ -367,9 -367,8 +367,9 @@@ extern void free_name_hash(struct index #define rename_cache_entry_at(pos, new_name) rename_index_entry_at(&the_index, (pos), (new_name)) #define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos)) #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path)) -#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags), 0) -#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags), 0) +#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags)) +#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags)) +#define chmod_cache_entry(ce, flip) chmod_index_entry(&the_index, (ce), (flip)) #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL) #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options)) #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options)) @@@ -409,6 -408,7 +409,7 @@@ static inline enum object_type object_t #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE" #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE" #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX" + #define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX" #define DEFAULT_GIT_DIR_ENVIRONMENT ".git" #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY" #define INDEX_ENVIRONMENT "GIT_INDEX_FILE" @@@ -433,7 -433,6 +434,7 @@@ #define GIT_GLOB_PATHSPECS_ENVIRONMENT "GIT_GLOB_PATHSPECS" #define GIT_NOGLOB_PATHSPECS_ENVIRONMENT "GIT_NOGLOB_PATHSPECS" #define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS" +#define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH" /* * This environment variable is expected to contain a boolean indicating @@@ -455,12 -454,6 +456,12 @@@ */ extern const char * const local_repo_env[]; +/* + * Returns true iff we have a configured git repository (either via + * setup_git_directory, or in the environment via $GIT_DIR). + */ +int have_git_dir(void); + extern int is_bare_repository_cfg; extern int is_bare_repository(void); extern int is_inside_git_dir(void); @@@ -476,6 -469,7 +477,7 @@@ extern int get_common_dir_noenv(struct extern int get_common_dir(struct strbuf *sb, const char *gitdir); extern const char *get_git_namespace(void); extern const char *strip_namespace(const char *namespaced_ref); + extern const char *get_super_prefix(void); extern const char *get_git_work_tree(void); /* @@@ -527,10 -521,9 +529,10 @@@ extern void verify_non_filename(const c extern int path_inside_repo(const char *prefix, const char *path); #define INIT_DB_QUIET 0x0001 +#define INIT_DB_EXIST_OK 0x0002 -extern int set_git_dir_init(const char *git_dir, const char *real_git_dir, int); -extern int init_db(const char *template_dir, unsigned int flags); +extern int init_db(const char *git_dir, const char *real_git_dir, + const char *template_dir, unsigned int flags); extern void sanitize_stdfds(void); extern int daemonize(void); @@@ -590,10 -583,9 +592,10 @@@ extern int remove_file_from_index(struc #define ADD_CACHE_IGNORE_ERRORS 4 #define ADD_CACHE_IGNORE_REMOVAL 8 #define ADD_CACHE_INTENT 16 -extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags, int force_mode); -extern int add_file_to_index(struct index_state *, const char *path, int flags, int force_mode); +extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags); +extern int add_file_to_index(struct index_state *, const char *path, int flags); extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options); +extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip); extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b); extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce); extern int index_name_is_other(const struct index_state *, const char *, int); @@@ -675,15 -667,8 +677,15 @@@ extern size_t delta_base_cache_limit extern unsigned long big_file_threshold; extern unsigned long pack_size_limit_cfg; +/* + * Accessors for the core.sharedrepository config which lazy-load the value + * from the config (if not already set). The "reset" function can be + * used to unset "set" or cached value, meaning that the value will be loaded + * fresh from the config file on the next call to get_shared_repository(). + */ void set_shared_repository(int value); int get_shared_repository(void); +void reset_shared_repository(void); /* * Do replace refs need to be checked this run? This variable is @@@ -1207,11 -1192,6 +1209,11 @@@ struct object_context #define GET_SHA1_FOLLOW_SYMLINKS 0100 #define GET_SHA1_ONLY_TO_DIE 04000 +#define GET_SHA1_DISAMBIGUATORS \ + (GET_SHA1_COMMIT | GET_SHA1_COMMITTISH | \ + GET_SHA1_TREE | GET_SHA1_TREEISH | \ + GET_SHA1_BLOB) + extern int get_sha1(const char *str, unsigned char *sha1); extern int get_sha1_commit(const char *str, unsigned char *sha1); extern int get_sha1_committish(const char *str, unsigned char *sha1); @@@ -1226,8 -1206,6 +1228,8 @@@ extern int get_oid(const char *str, str typedef int each_abbrev_fn(const unsigned char *sha1, void *); extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *); +extern int set_disambiguate_hint_config(const char *var, const char *value); + /* * Try to read a SHA1 in hexadecimal format from the 40 characters * starting at hex. Write the 20-byte result to sha1 in binary form. @@@ -1255,7 -1233,7 +1257,7 @@@ extern char *sha1_to_hex(const unsigne extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */ extern int interpret_branch_name(const char *str, int len, struct strbuf *); -extern int get_sha1_mb(const char *str, unsigned char *sha1); +extern int get_oid_mb(const char *str, struct object_id *oid); extern int validate_headref(const char *ref); @@@ -1365,7 -1343,6 +1367,7 @@@ struct checkout not_new:1, refresh_cache:1; }; +#define CHECKOUT_INIT { NULL, "" } #define TEMPORARY_FILENAME_LENGTH 25 extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath); @@@ -1391,46 -1368,16 +1393,46 @@@ extern void remove_scheduled_dirs(void) extern struct alternate_object_database { struct alternate_object_database *next; - char *name; - char base[FLEX_ARRAY]; /* more */ + + /* see alt_scratch_buf() */ + struct strbuf scratch; + size_t base_len; + + char path[FLEX_ARRAY]; } *alt_odb_list; extern void prepare_alt_odb(void); extern void read_info_alternates(const char * relative_base, int depth); extern char *compute_alternate_path(const char *path, struct strbuf *err); -extern void add_to_alternates_file(const char *reference); typedef int alt_odb_fn(struct alternate_object_database *, void *); extern int foreach_alt_odb(alt_odb_fn, void*); +/* + * Allocate a "struct alternate_object_database" but do _not_ actually + * add it to the list of alternates. + */ +struct alternate_object_database *alloc_alt_odb(const char *dir); + +/* + * Add the directory to the on-disk alternates file; the new entry will also + * take effect in the current process. + */ +extern void add_to_alternates_file(const char *dir); + +/* + * Add the directory to the in-memory list of alternates (along with any + * recursive alternates it points to), but do not modify the on-disk alternates + * file. + */ +extern void add_to_alternates_memory(const char *dir); + +/* + * Returns a scratch strbuf pre-filled with the alternate object directory, + * including a trailing slash, which can be used to access paths in the + * alternate. Always use this over direct access to alt->scratch, as it + * cleans up any previous use of the scratch buffer. + */ +extern struct strbuf *alt_scratch_buf(struct alternate_object_database *alt); + struct pack_window { struct pack_window *next; unsigned char *base; @@@ -1633,15 -1580,7 +1635,15 @@@ struct object_info } packed; } u; }; + +/* + * Initializer for a "struct object_info" that wants no items. You may + * also memset() the memory to all-zeroes. + */ +#define OBJECT_INFO_INIT {NULL} + extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags); +extern int packed_object_info(struct packed_git *pack, off_t offset, struct object_info *); /* Dumb servers support */ extern int update_server_info(int); @@@ -1876,6 -1815,7 +1878,6 @@@ extern void write_file(const char *path /* pager.c */ extern void setup_pager(void); -extern const char *pager_program; extern int pager_in_use(void); extern int pager_use_color; extern int term_columns(void); @@@ -1908,7 -1848,7 +1910,7 @@@ void packet_trace_identity(const char * * return 0 if success, 1 - if addition of a file failed and * ADD_FILES_IGNORE_ERRORS was specified in flags */ -int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags, int force_mode); +int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags); /* diff.c */ extern int diff_auto_refresh_index; diff --combined dir.c index 3bad1ade8d,28e97367d9..f9412e0213 --- a/dir.c +++ b/dir.c @@@ -207,8 -207,9 +207,9 @@@ int within_depth(const char *name, int return 1; } - #define DO_MATCH_EXCLUDE 1 - #define DO_MATCH_DIRECTORY 2 + #define DO_MATCH_EXCLUDE (1<<0) + #define DO_MATCH_DIRECTORY (1<<1) + #define DO_MATCH_SUBMODULE (1<<2) /* * Does 'match' match the given name? @@@ -283,6 -284,32 +284,32 @@@ static int match_pathspec_item(const st item->nowildcard_len - prefix)) return MATCHED_FNMATCH; + /* Perform checks to see if "name" is a super set of the pathspec */ + if (flags & DO_MATCH_SUBMODULE) { + /* name is a literal prefix of the pathspec */ + if ((namelen < matchlen) && + (match[namelen] == '/') && + !ps_strncmp(item, match, name, namelen)) + return MATCHED_RECURSIVELY; + + /* name" doesn't match up to the first wild character */ + if (item->nowildcard_len < item->len && + ps_strncmp(item, match, name, + item->nowildcard_len - prefix)) + return 0; + + /* + * Here is where we would perform a wildmatch to check if + * "name" can be matched as a directory (or a prefix) against + * the pathspec. Since wildmatch doesn't have this capability + * at the present we have to punt and say that it is a match, + * potentially returning a false positive + * The submodules themselves will be able to perform more + * accurate matching to determine if the pathspec matches. + */ + return MATCHED_RECURSIVELY; + } + return 0; } @@@ -386,6 -413,21 +413,21 @@@ int match_pathspec(const struct pathspe return negative ? 0 : positive; } + /** + * Check if a submodule is a superset of the pathspec + */ + int submodule_path_match(const struct pathspec *ps, + const char *submodule_name, + char *seen) + { + int matched = do_match_pathspec(ps, submodule_name, + strlen(submodule_name), + 0, seen, + DO_MATCH_DIRECTORY | + DO_MATCH_SUBMODULE); + return matched; + } + int report_path_error(const char *ps_matched, const struct pathspec *pathspec, const char *prefix) @@@ -525,7 -567,7 +567,7 @@@ static void *read_skip_worktree_file_fr return NULL; if (!ce_skip_worktree(active_cache[pos])) return NULL; - data = read_sha1_file(active_cache[pos]->sha1, &type, &sz); + data = read_sha1_file(active_cache[pos]->oid.hash, &type, &sz); if (!data || type != OBJ_BLOB) { free(data); return NULL; @@@ -533,7 -575,7 +575,7 @@@ *size = xsize_t(sz); if (sha1_stat) { memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat)); - hashcpy(sha1_stat->sha1, active_cache[pos]->sha1); + hashcpy(sha1_stat->sha1, active_cache[pos]->oid.hash); } return data; } @@@ -713,8 -755,7 +755,8 @@@ static int add_excludes(const char *fna !ce_stage(active_cache[pos]) && ce_uptodate(active_cache[pos]) && !would_convert_to_git(fname)) - hashcpy(sha1_stat->sha1, active_cache[pos]->sha1); + hashcpy(sha1_stat->sha1, + active_cache[pos]->oid.hash); else hash_sha1_file(buf, size, "blob", sha1_stat->sha1); fill_stat_data(&sha1_stat->stat, &st); @@@ -2005,8 -2046,8 +2047,8 @@@ int read_directory(struct dir_struct *d if (!len || treat_leading_path(dir, path, len, simplify)) read_directory_recursive(dir, path, len, untracked, 0, simplify); free_simplify(simplify); - qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name); - qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name); + QSORT(dir->entries, dir->nr, cmp_name); + QSORT(dir->ignored, dir->ignored_nr, cmp_name); if (dir->untracked) { static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS); trace_printf_key(&trace_untracked_stats, diff --combined environment.c index cd5aa57179,d12d7db20a..cdc097f80c --- a/environment.c +++ b/environment.c @@@ -40,6 -40,7 +40,6 @@@ size_t packed_git_window_size = DEFAULT size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT; size_t delta_base_cache_limit = 96 * 1024 * 1024; unsigned long big_file_threshold = 512 * 1024 * 1024; -const char *pager_program; int pager_use_color = 1; const char *editor_program; const char *askpass_program; @@@ -99,6 -100,8 +99,8 @@@ static char *work_tree static const char *namespace; static size_t namespace_len; + static const char *super_prefix; + static const char *git_dir, *git_common_dir; static char *git_object_dir, *git_index_file, *git_graft_file; int git_db_env, git_index_env, git_graft_env, git_common_dir_env; @@@ -119,6 -122,7 +121,7 @@@ const char * const local_repo_env[] = NO_REPLACE_OBJECTS_ENVIRONMENT, GIT_REPLACE_REF_BASE_ENVIRONMENT, GIT_PREFIX_ENVIRONMENT, + GIT_SUPER_PREFIX_ENVIRONMENT, GIT_SHALLOW_FILE_ENVIRONMENT, GIT_COMMON_DIR_ENVIRONMENT, NULL @@@ -195,13 -199,6 +198,13 @@@ int is_bare_repository(void return is_bare_repository_cfg && !get_git_work_tree(); } +int have_git_dir(void) +{ + return startup_info->have_repository + || git_dir + || getenv(GIT_DIR_ENVIRONMENT); +} + const char *get_git_dir(void) { if (!git_dir) @@@ -228,6 -225,16 +231,16 @@@ const char *strip_namespace(const char return namespaced_ref + namespace_len; } + const char *get_super_prefix(void) + { + static int initialized; + if (!initialized) { + super_prefix = getenv(GIT_SUPER_PREFIX_ENVIRONMENT); + initialized = 1; + } + return super_prefix; + } + static int git_work_tree_initialized; /* @@@ -351,8 -358,3 +364,8 @@@ int get_shared_repository(void } return the_shared_repository; } + +void reset_shared_repository(void) +{ + need_shared_repository_from_config = 1; +} diff --combined git.c index ab5c99cf70,df737682d5..be58788deb --- a/git.c +++ b/git.c @@@ -164,6 -164,20 +164,20 @@@ static int handle_options(const char ** setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1); if (envchanged) *envchanged = 1; + } else if (!strcmp(cmd, "--super-prefix")) { + if (*argc < 2) { + fprintf(stderr, "No prefix given for --super-prefix.\n" ); + usage(git_usage_string); + } + setenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1); + if (envchanged) + *envchanged = 1; + (*argv)++; + (*argc)--; + } else if (skip_prefix(cmd, "--super-prefix=", &cmd)) { + setenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1); + if (envchanged) + *envchanged = 1; } else if (!strcmp(cmd, "--bare")) { char *cwd = xgetcwd(); is_bare_repository_cfg = 1; @@@ -310,6 -324,7 +324,7 @@@ static int handle_alias(int *argcp, con * RUN_SETUP for reading from the configuration file. */ #define NEED_WORK_TREE (1<<3) + #define SUPPORT_SUPER_PREFIX (1<<4) struct cmd_struct { const char *cmd; @@@ -344,6 -359,13 +359,13 @@@ static int run_builtin(struct cmd_struc } commit_pager_choice(); + if (!help && get_super_prefix()) { + if (!(p->option & SUPPORT_SUPER_PREFIX)) + die("%s doesn't support --super-prefix", p->cmd); + if (prefix) + die("can't use --super-prefix from a subdirectory"); + } + if (!help && p->option & NEED_WORK_TREE) setup_work_tree(); @@@ -421,7 -443,7 +443,7 @@@ static struct cmd_struct commands[] = { "init-db", cmd_init_db }, { "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY }, { "log", cmd_log, RUN_SETUP }, - { "ls-files", cmd_ls_files, RUN_SETUP }, + { "ls-files", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX }, { "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY }, { "ls-tree", cmd_ls_tree, RUN_SETUP }, { "mailinfo", cmd_mailinfo }, @@@ -444,7 -466,7 +466,7 @@@ { "pack-objects", cmd_pack_objects, RUN_SETUP }, { "pack-redundant", cmd_pack_redundant, RUN_SETUP }, { "pack-refs", cmd_pack_refs, RUN_SETUP }, - { "patch-id", cmd_patch_id }, + { "patch-id", cmd_patch_id, RUN_SETUP_GENTLY }, { "pickaxe", cmd_blame, RUN_SETUP }, { "prune", cmd_prune, RUN_SETUP }, { "prune-packed", cmd_prune_packed, RUN_SETUP }, @@@ -558,6 -580,9 +580,9 @@@ static void execv_dashed_external(cons const char *tmp; int status; + if (get_super_prefix()) + die("%s doesn't support --super-prefix", argv[0]); + if (use_pager == -1) use_pager = check_pager_config(argv[0]); commit_pager_choice();