From: Junio C Hamano Date: Thu, 25 Apr 2019 07:41:10 +0000 (+0900) Subject: Merge branch 'bp/post-index-change-hook' X-Git-Tag: v2.22.0-rc0~75 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/5795a75f9bd7a7f008b213c2f099e8c6b0468512?hp=-c Merge branch 'bp/post-index-change-hook' A new hook "post-index-change" is called when the on-disk index file changes, which can help e.g. a virtualized working tree implementation. * bp/post-index-change-hook: read-cache: add post-index-change hook --- 5795a75f9bd7a7f008b213c2f099e8c6b0468512 diff --combined Documentation/githooks.txt index 5bf653c111,bfb0be3659..786e778ab8 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@@ -99,10 -99,6 +99,10 @@@ All the `git commit` hooks are invoked variable `GIT_EDITOR=:` if the command will not bring up an editor to modify the commit message. +The default 'pre-commit' hook, when enabled--and with the +`hooks.allownonascii` config option unset or set to false--prevents +the use of non-ASCII filenames. + prepare-commit-msg ~~~~~~~~~~~~~~~~~~ @@@ -496,6 -492,24 +496,24 @@@ This hook is invoked by `git-p4 submit` from standard input. Exiting with non-zero status from this script prevent `git-p4 submit` from launching. Run `git-p4 submit --help` for details. + post-index-change + ~~~~~~~~~~~~~~~~~ + + This hook is invoked when the index is written in read-cache.c + do_write_locked_index. + + The first parameter passed to the hook is the indicator for the + working directory being updated. "1" meaning working directory + was updated or "0" when the working directory was not updated. + + The second parameter passed to the hook is the indicator for whether + or not the index was updated and the skip-worktree bit could have + changed. "1" meaning skip-worktree bits could have been updated + and "0" meaning they were not. + + Only one parameter should be set to "1" when the hook runs. The hook + running passing "1", "1" should not be possible. + GIT --- Part of the linkgit:git[1] suite diff --combined builtin/reset.c index 7882829a95,e173afcaac..26ef9a7bd0 --- a/builtin/reset.c +++ b/builtin/reset.c @@@ -341,7 -341,6 +341,7 @@@ int cmd_reset(int argc, const char **ar if (patch_mode) { if (reset_type != NONE) die(_("--patch is incompatible with --{hard,mixed,soft}")); + trace2_cmd_mode("patch-interactive"); return run_add_interactive(rev, "--patch=reset", &pathspec); } @@@ -358,11 -357,6 +358,11 @@@ if (reset_type == NONE) reset_type = MIXED; /* by default */ + if (pathspec.nr) + trace2_cmd_mode("path"); + else + trace2_cmd_mode(reset_type_names[reset_type]); + if (reset_type != SOFT && (reset_type != MIXED || get_git_work_tree())) setup_work_tree(); @@@ -386,6 -380,7 +386,7 @@@ int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN; if (read_from_tree(&pathspec, &oid, intent_to_add)) return 1; + the_index.updated_skipworktree = 1; if (!quiet && get_git_work_tree()) { uint64_t t_begin, t_delta_in_ms; diff --combined builtin/update-index.c index 1b6c42f748,cf731640fa..73fe04e1c2 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@@ -848,16 -848,14 +848,16 @@@ static int parse_new_style_cacheinfo(co return 0; } -static int cacheinfo_callback(struct parse_opt_ctx_t *ctx, - const struct option *opt, int unset) +static enum parse_opt_result cacheinfo_callback( + struct parse_opt_ctx_t *ctx, const struct option *opt, + const char *arg, int unset) { struct object_id oid; unsigned int mode; const char *path; BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); if (!parse_new_style_cacheinfo(ctx->argv[1], &mode, &oid, &path)) { if (add_cacheinfo(mode, &oid, path, 0)) @@@ -876,14 -874,12 +876,14 @@@ return 0; } -static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx, - const struct option *opt, int unset) +static enum parse_opt_result stdin_cacheinfo_callback( + struct parse_opt_ctx_t *ctx, const struct option *opt, + const char *arg, int unset) { int *nul_term_line = opt->value; BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); if (ctx->argc != 1) return error("option '%s' must be the last argument", opt->long_name); @@@ -892,14 -888,12 +892,14 @@@ return 0; } -static int stdin_callback(struct parse_opt_ctx_t *ctx, - const struct option *opt, int unset) +static enum parse_opt_result stdin_callback( + struct parse_opt_ctx_t *ctx, const struct option *opt, + const char *arg, int unset) { int *read_from_stdin = opt->value; BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); if (ctx->argc != 1) return error("option '%s' must be the last argument", opt->long_name); @@@ -907,15 -901,13 +907,15 @@@ return 0; } -static int unresolve_callback(struct parse_opt_ctx_t *ctx, - const struct option *opt, int unset) +static enum parse_opt_result unresolve_callback( + struct parse_opt_ctx_t *ctx, const struct option *opt, + const char *arg, int unset) { int *has_errors = opt->value; const char *prefix = startup_info->prefix; BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); /* consume remaining arguments. */ *has_errors = do_unresolve(ctx->argc, ctx->argv, @@@ -928,15 -920,13 +928,15 @@@ return 0; } -static int reupdate_callback(struct parse_opt_ctx_t *ctx, - const struct option *opt, int unset) +static enum parse_opt_result reupdate_callback( + struct parse_opt_ctx_t *ctx, const struct option *opt, + const char *arg, int unset) { int *has_errors = opt->value; const char *prefix = startup_info->prefix; BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); /* consume remaining arguments. */ setup_work_tree(); @@@ -996,8 -986,7 +996,8 @@@ int cmd_update_index(int argc, const ch N_("add the specified entry to the index"), PARSE_OPT_NOARG | /* disallow --cacheinfo= form */ PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, - (parse_opt_cb *) cacheinfo_callback}, + NULL, 0, + cacheinfo_callback}, {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+|-)x", N_("override the executable bit of the listed files"), PARSE_OPT_NONEG, @@@ -1023,19 -1012,19 +1023,19 @@@ {OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL, N_("read list of paths to be updated from standard input"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, - (parse_opt_cb *) stdin_callback}, + NULL, 0, stdin_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &nul_term_line, NULL, N_("add entries from standard input to the index"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, - (parse_opt_cb *) stdin_cacheinfo_callback}, + NULL, 0, stdin_cacheinfo_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL, N_("repopulate stages #2 and #3 for the listed paths"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, - (parse_opt_cb *) unresolve_callback}, + NULL, 0, unresolve_callback}, {OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL, N_("only update entries that differ from HEAD"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, - (parse_opt_cb *) reupdate_callback}, + NULL, 0, reupdate_callback}, OPT_BIT(0, "ignore-missing", &refresh_args.flags, N_("ignore files missing from worktree"), REFRESH_IGNORE_MISSING), @@@ -1082,6 -1071,8 +1082,8 @@@ if (entries < 0) die("cache corrupted"); + the_index.updated_skipworktree = 1; + /* * Custom copy of parse_options() because we want to handle * filename arguments as they come. diff --combined cache.h index e3c2ab9628,46eb862d3e..e928fe9d3b --- a/cache.h +++ b/cache.h @@@ -9,7 -9,6 +9,7 @@@ #include "gettext.h" #include "convert.h" #include "trace.h" +#include "trace2.h" #include "string-list.h" #include "pack-revindex.h" #include "hash.h" @@@ -339,7 -338,9 +339,9 @@@ struct index_state struct cache_time timestamp; unsigned name_hash_initialized : 1, initialized : 1, - drop_cache_tree : 1; + drop_cache_tree : 1, + updated_workdir : 1, + updated_skipworktree : 1; struct hashmap name_hash; struct hashmap dir_hash; struct object_id oid; @@@ -759,7 -760,7 +761,7 @@@ extern void rename_index_entry_at(struc /* Remove entry, return true if there are more entries to go. */ extern int remove_index_entry_at(struct index_state *, int pos); -extern void remove_marked_cache_entries(struct index_state *istate); +extern void remove_marked_cache_entries(struct index_state *istate, int invalidate); extern int remove_file_from_index(struct index_state *, const char *path); #define ADD_CACHE_VERBOSE 1 #define ADD_CACHE_PRETEND 2 @@@ -962,10 -963,6 +964,10 @@@ extern char *repository_format_partial_ extern const char *core_partial_clone_filter_default; extern int repository_format_worktree_config; +/* + * You _have_ to initialize a `struct repository_format` using + * `= REPOSITORY_FORMAT_INIT` before calling `read_repository_format()`. + */ struct repository_format { int version; int precious_objects; @@@ -977,35 -974,14 +979,35 @@@ struct string_list unknown_extensions; }; +/* + * Always use this to initialize a `struct repository_format` + * to a well-defined, default state before calling + * `read_repository()`. + */ +#define REPOSITORY_FORMAT_INIT \ +{ \ + .version = -1, \ + .is_bare = -1, \ + .hash_algo = GIT_HASH_SHA1, \ + .unknown_extensions = STRING_LIST_INIT_DUP, \ +} + /* * Read the repository format characteristics from the config file "path" into - * "format" struct. Returns the numeric version. On error, -1 is returned, - * format->version is set to -1, and all other fields in the struct are - * undefined. + * "format" struct. Returns the numeric version. On error, or if no version is + * found in the configuration, -1 is returned, format->version is set to -1, + * and all other fields in the struct are set to the default configuration + * (REPOSITORY_FORMAT_INIT). Always initialize the struct using + * REPOSITORY_FORMAT_INIT before calling this function. */ int read_repository_format(struct repository_format *format, const char *path); +/* + * Free the memory held onto by `format`, but not the struct itself. + * (No need to use this after `read_repository_format()` fails.) + */ +void clear_repository_format(struct repository_format *format); + /* * Verify that the repository described by repository_format is something we * can read. If it is, return 0. Otherwise, return -1, and "err" will describe @@@ -1379,7 -1355,6 +1381,7 @@@ enum get_oid_result }; extern int get_oid(const char *str, struct object_id *oid); +extern int get_oidf(struct object_id *oid, const char *fmt, ...); extern int get_oid_commit(const char *str, struct object_id *oid); extern int get_oid_committish(const char *str, struct object_id *oid); extern int get_oid_tree(const char *str, struct object_id *oid); @@@ -1533,19 -1508,10 +1535,19 @@@ int date_overflows(timestamp_t date) #define IDENT_STRICT 1 #define IDENT_NO_DATE 2 #define IDENT_NO_NAME 4 + +enum want_ident { + WANT_BLANK_IDENT, + WANT_AUTHOR_IDENT, + WANT_COMMITTER_IDENT +}; + extern const char *git_author_info(int); extern const char *git_committer_info(int); -extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int); -extern const char *fmt_name(const char *name, const char *email); +extern const char *fmt_ident(const char *name, const char *email, + enum want_ident whose_ident, + const char *date_str, int); +extern const char *fmt_name(enum want_ident); extern const char *ident_default_name(void); extern const char *ident_default_email(void); extern const char *git_editor(void); @@@ -1553,10 -1519,6 +1555,10 @@@ extern const char *git_sequence_editor( extern const char *git_pager(int stdout_is_tty); extern int is_terminal_dumb(void); extern int git_ident_config(const char *, const char *, void *); +/* + * Prepare an ident to fall back on if the user didn't configure it. + */ +void prepare_fallback_ident(const char *name, const char *email); extern void reset_ident_date(void); struct ident_split { @@@ -1609,11 -1571,6 +1611,11 @@@ struct checkout extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath, int *nr_checkouts); extern void enable_delayed_checkout(struct checkout *state); extern int finish_delayed_checkout(struct checkout *state, int *nr_checkouts); +/* + * Unlink the last component and schedule the leading directories for + * removal, such that empty directories get removed. + */ +extern void unlink_entry(const struct cache_entry *ce); struct cache_def { struct strbuf path; diff --combined read-cache.c index 4dc6de1b55,862bdf383d..c62eae651d --- a/read-cache.c +++ b/read-cache.c @@@ -17,6 -17,7 +17,7 @@@ #include "commit.h" #include "blob.h" #include "resolve-undo.h" + #include "run-command.h" #include "strbuf.h" #include "varint.h" #include "split-index.h" @@@ -588,19 -589,13 +589,19 @@@ int remove_index_entry_at(struct index_ * CE_REMOVE is set in ce_flags. This is much more effective than * calling remove_index_entry_at() for each entry to be removed. */ -void remove_marked_cache_entries(struct index_state *istate) +void remove_marked_cache_entries(struct index_state *istate, int invalidate) { struct cache_entry **ce_array = istate->cache; unsigned int i, j; for (i = j = 0; i < istate->cache_nr; i++) { if (ce_array[i]->ce_flags & CE_REMOVE) { + if (invalidate) { + cache_tree_invalidate_path(istate, + ce_array[i]->name); + untracked_cache_remove_from_index(istate, + ce_array[i]->name); + } remove_name_hash(istate, ce_array[i]); save_or_free_index_entry(istate, ce_array[i]); } @@@ -2226,16 -2221,6 +2227,16 @@@ int do_read_index(struct index_state *i load_index_extensions(&p); } munmap((void *)mmap, mmap_size); + + /* + * TODO trace2: replace "the_repository" with the actual repo instance + * that is associated with the given "istate". + */ + trace2_data_intmax("index", the_repository, "read/version", + istate->version); + trace2_data_intmax("index", the_repository, "read/cache_nr", + istate->cache_nr); + return istate->cache_nr; unmap: @@@ -2267,17 -2252,9 +2268,17 @@@ int read_index_from(struct index_state if (istate->initialized) return istate->cache_nr; + /* + * TODO trace2: replace "the_repository" with the actual repo instance + * that is associated with the given "istate". + */ + trace2_region_enter_printf("index", "do_read_index", the_repository, + "%s", path); trace_performance_enter(); ret = do_read_index(istate, path, 0); trace_performance_leave("read cache %s", path); + trace2_region_leave_printf("index", "do_read_index", the_repository, + "%s", path); split_index = istate->split_index; if (!split_index || is_null_oid(&split_index->base_oid)) { @@@ -2293,11 -2270,7 +2294,11 @@@ base_oid_hex = oid_to_hex(&split_index->base_oid); base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_oid_hex); + trace2_region_enter_printf("index", "shared/do_read_index", + the_repository, "%s", base_path); ret = do_read_index(split_index->base, base_path, 1); + trace2_region_leave_printf("index", "shared/do_read_index", + the_repository, "%s", base_path); if (!oideq(&split_index->base_oid, &split_index->base->oid)) die(_("broken index, expect %s in %s, got %s"), base_oid_hex, base_path, @@@ -2922,8 -2895,7 +2923,8 @@@ static int do_write_index(struct index_ return -1; } - if (!strip_extensions && istate->split_index) { + if (!strip_extensions && istate->split_index && + !is_null_oid(&istate->split_index->base_oid)) { struct strbuf sb = STRBUF_INIT; err = write_link_extension(&sb, istate) < 0 || @@@ -3005,16 -2977,6 +3006,16 @@@ istate->timestamp.sec = (unsigned int)st.st_mtime; istate->timestamp.nsec = ST_MTIME_NSEC(st); trace_performance_since(start, "write index, changed mask = %x", istate->cache_changed); + + /* + * TODO trace2: replace "the_repository" with the actual repo instance + * that is associated with the given "istate". + */ + trace2_data_intmax("index", the_repository, "write/version", + istate->version); + trace2_data_intmax("index", the_repository, "write/cache_nr", + istate->cache_nr); + return 0; } @@@ -3034,23 -2996,21 +3035,32 @@@ static int commit_locked_index(struct l static int do_write_locked_index(struct index_state *istate, struct lock_file *lock, unsigned flags) { - int ret = do_write_index(istate, lock->tempfile, 0); + int ret; + + /* + * TODO trace2: replace "the_repository" with the actual repo instance + * that is associated with the given "istate". + */ + trace2_region_enter_printf("index", "do_write_index", the_repository, + "%s", lock->tempfile->filename.buf); + ret = do_write_index(istate, lock->tempfile, 0); + trace2_region_leave_printf("index", "do_write_index", the_repository, + "%s", lock->tempfile->filename.buf); + if (ret) return ret; if (flags & COMMIT_LOCK) - return commit_locked_index(lock); - return close_lock_file_gently(lock); + ret = commit_locked_index(lock); + else + ret = close_lock_file_gently(lock); + + run_hook_le(NULL, "post-index-change", + istate->updated_workdir ? "1" : "0", + istate->updated_skipworktree ? "1" : "0", NULL); + istate->updated_workdir = 0; + istate->updated_skipworktree = 0; + + return ret; } static int write_split_index(struct index_state *istate, @@@ -3130,13 -3090,7 +3140,13 @@@ static int write_shared_index(struct in int ret; move_cache_to_base_index(istate); + + trace2_region_enter_printf("index", "shared/do_write_index", + the_repository, "%s", (*temp)->filename.buf); ret = do_write_index(si->base, *temp, 1); + trace2_region_enter_printf("index", "shared/do_write_index", + the_repository, "%s", (*temp)->filename.buf); + if (ret) return ret; ret = adjust_shared_perm(get_tempfile_path(*temp)); @@@ -3245,7 -3199,7 +3255,7 @@@ int write_locked_index(struct index_sta ret = write_split_index(istate, lock, flags); /* Freshen the shared index only if the split-index was written */ - if (!ret && !new_shared_index) { + if (!ret && !new_shared_index && !is_null_oid(&si->base_oid)) { const char *shared_index = git_path("sharedindex.%s", oid_to_hex(&si->base_oid)); freshen_shared_index(shared_index, 1); diff --combined unpack-trees.c index 1ccd343cad,8665a4a7c0..c5ec30f25f --- a/unpack-trees.c +++ b/unpack-trees.c @@@ -299,6 -299,25 +299,6 @@@ static void load_gitmodules_file(struc } } -/* - * Unlink the last component and schedule the leading directories for - * removal, such that empty directories get removed. - */ -static void unlink_entry(const struct cache_entry *ce) -{ - const struct submodule *sub = submodule_from_ce(ce); - if (sub) { - /* state.force is set at the caller. */ - submodule_move_head(ce->name, "HEAD", NULL, - SUBMODULE_MOVE_HEAD_FORCE); - } - if (!check_leading_path(ce->name, ce_namelen(ce))) - return; - if (remove_or_warn(ce->ce_mode, ce->name)) - return; - schedule_dir_for_removal(ce->name, ce_namelen(ce)); -} - static struct progress *get_progress(struct unpack_trees_options *o) { unsigned cnt = 0, total = 0; @@@ -391,7 -410,7 +391,7 @@@ static int check_updates(struct unpack_ unlink_entry(ce); } } - remove_marked_cache_entries(index); + remove_marked_cache_entries(index, 0); remove_scheduled_dirs(); if (should_update_submodules() && o->update && !o->dry_run) @@@ -1618,6 -1637,8 +1618,8 @@@ int unpack_trees(unsigned len, struct t WRITE_TREE_SILENT | WRITE_TREE_REPAIR); } + + o->result.updated_workdir = 1; discard_index(o->dst_index); *o->dst_index = o->result; } else { @@@ -2386,7 -2407,7 +2388,7 @@@ int oneway_merge(const struct cache_ent if (o->update && S_ISGITLINK(old->ce_mode) && should_update_submodules() && !verify_uptodate(old, o)) update |= CE_UPDATE; - add_entry(o, old, update, 0); + add_entry(o, old, update, CE_STAGEMASK); return 0; } return merged_entry(a, old, o);