Merge branch 'nd/prune-in-worktree'

"git gc" and friends when multiple worktrees are used off of a
single repository did not consider the index and per-worktree refs
of other worktrees as the root for reachability traversal, making
objects that are in use only in other worktrees to be subject to
garbage collection.

* nd/prune-in-worktree:
  refs.c: reindent get_submodule_ref_store()
  refs.c: remove fallback-to-main-store code get_submodule_ref_store()
  rev-list: expose and document --single-worktree
  revision.c: --reflog add HEAD reflog from all worktrees
  files-backend: make reflog iterator go through per-worktree reflog
  revision.c: --all adds HEAD from all worktrees
  refs: remove dead for_each_*_submodule()
  refs.c: move for_each_remote_ref_submodule() to submodule.c
  revision.c: use refs_for_each*() instead of for_each_*_submodule()
  refs: add refs_head_ref()
  refs: move submodule slash stripping code to get_submodule_ref_store
  refs.c: refactor get_submodule_ref_store(), share common free block
  revision.c: --indexed-objects add objects from all worktrees
  revision.c: refactor add_index_objects_to_pending()
  refs.c: use is_dir_sep() in resolve_gitlink_ref()
  revision.h: new flag in struct rev_info wrt. worktree-related refs
This commit is contained in:
Junio C Hamano
2017-09-19 10:47:53 +09:00
13 changed files with 308 additions and 136 deletions

View File

@ -20,6 +20,7 @@
#include "cache-tree.h"
#include "bisect.h"
#include "packfile.h"
#include "worktree.h"
volatile show_early_output_fn_t show_early_output;
@ -1132,6 +1133,7 @@ struct all_refs_cb {
int warned_bad_reflog;
struct rev_info *all_revs;
const char *name_for_errormsg;
struct ref_store *refs;
};
int ref_excluded(struct string_list *ref_excludes, const char *path)
@ -1168,6 +1170,7 @@ static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs,
cb->all_revs = revs;
cb->all_flags = flags;
revs->rev_input_given = 1;
cb->refs = NULL;
}
void clear_ref_exclusion(struct string_list **ref_excludes_p)
@ -1188,12 +1191,19 @@ void add_ref_exclusion(struct string_list **ref_excludes_p, const char *exclude)
string_list_append(*ref_excludes_p, exclude);
}
static void handle_refs(const char *submodule, struct rev_info *revs, unsigned flags,
int (*for_each)(const char *, each_ref_fn, void *))
static void handle_refs(struct ref_store *refs,
struct rev_info *revs, unsigned flags,
int (*for_each)(struct ref_store *, each_ref_fn, void *))
{
struct all_refs_cb cb;
if (!refs) {
/* this could happen with uninitialized submodules */
return;
}
init_all_refs_cb(&cb, revs, flags);
for_each(submodule, handle_one_ref, &cb);
for_each(refs, handle_one_ref, &cb);
}
static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)
@ -1229,17 +1239,41 @@ static int handle_one_reflog(const char *path, const struct object_id *oid,
struct all_refs_cb *cb = cb_data;
cb->warned_bad_reflog = 0;
cb->name_for_errormsg = path;
for_each_reflog_ent(path, handle_one_reflog_ent, cb_data);
refs_for_each_reflog_ent(cb->refs, path,
handle_one_reflog_ent, cb_data);
return 0;
}
static void add_other_reflogs_to_pending(struct all_refs_cb *cb)
{
struct worktree **worktrees, **p;
worktrees = get_worktrees(0);
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;
if (wt->is_current)
continue;
cb->refs = get_worktree_ref_store(wt);
refs_for_each_reflog(cb->refs,
handle_one_reflog,
cb);
}
free_worktrees(worktrees);
}
void add_reflogs_to_pending(struct rev_info *revs, unsigned flags)
{
struct all_refs_cb cb;
cb.all_revs = revs;
cb.all_flags = flags;
cb.refs = get_main_ref_store();
for_each_reflog(handle_one_reflog, &cb);
if (!revs->single_worktree)
add_other_reflogs_to_pending(&cb);
}
static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,
@ -1263,13 +1297,13 @@ static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,
}
void add_index_objects_to_pending(struct rev_info *revs, unsigned flags)
static void do_add_index_objects_to_pending(struct rev_info *revs,
struct index_state *istate)
{
int i;
read_cache();
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
for (i = 0; i < istate->cache_nr; i++) {
struct cache_entry *ce = istate->cache[i];
struct blob *blob;
if (S_ISGITLINK(ce->ce_mode))
@ -1282,13 +1316,39 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned flags)
ce->ce_mode, ce->name);
}
if (active_cache_tree) {
if (istate->cache_tree) {
struct strbuf path = STRBUF_INIT;
add_cache_tree(active_cache_tree, revs, &path);
add_cache_tree(istate->cache_tree, revs, &path);
strbuf_release(&path);
}
}
void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
{
struct worktree **worktrees, **p;
read_cache();
do_add_index_objects_to_pending(revs, &the_index);
if (revs->single_worktree)
return;
worktrees = get_worktrees(0);
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;
struct index_state istate = { NULL };
if (wt->is_current)
continue; /* current index already taken care of */
if (read_index_from(&istate,
worktree_git_path(wt, "index")) > 0)
do_add_index_objects_to_pending(revs, &istate);
discard_index(&istate);
}
free_worktrees(worktrees);
}
static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
int exclude_parent)
{
@ -2069,23 +2129,25 @@ void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
ctx->argc -= n;
}
static int for_each_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data, const char *term) {
static int for_each_bisect_ref(struct ref_store *refs, each_ref_fn fn,
void *cb_data, const char *term)
{
struct strbuf bisect_refs = STRBUF_INIT;
int status;
strbuf_addf(&bisect_refs, "refs/bisect/%s", term);
status = for_each_fullref_in_submodule(submodule, bisect_refs.buf, fn, cb_data, 0);
status = refs_for_each_fullref_in(refs, bisect_refs.buf, fn, cb_data, 0);
strbuf_release(&bisect_refs);
return status;
}
static int for_each_bad_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)
static int for_each_bad_bisect_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
return for_each_bisect_ref(submodule, fn, cb_data, term_bad);
return for_each_bisect_ref(refs, fn, cb_data, term_bad);
}
static int for_each_good_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)
static int for_each_good_bisect_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
{
return for_each_bisect_ref(submodule, fn, cb_data, term_good);
return for_each_bisect_ref(refs, fn, cb_data, term_good);
}
static int handle_revision_pseudo_opt(const char *submodule,
@ -2094,8 +2156,22 @@ static int handle_revision_pseudo_opt(const char *submodule,
{
const char *arg = argv[0];
const char *optarg;
struct ref_store *refs;
int argcount;
if (submodule) {
/*
* We need some something like get_submodule_worktrees()
* before we can go through all worktrees of a submodule,
* .e.g with adding all HEADs from --all, which is not
* supported right now, so stick to single worktree.
*/
if (!revs->single_worktree)
die("BUG: --single-worktree cannot be used together with submodule");
refs = get_submodule_ref_store(submodule);
} else
refs = get_main_ref_store();
/*
* NOTE!
*
@ -2107,22 +2183,29 @@ static int handle_revision_pseudo_opt(const char *submodule,
* register it in the list at the top of handle_revision_opt.
*/
if (!strcmp(arg, "--all")) {
handle_refs(submodule, revs, *flags, for_each_ref_submodule);
handle_refs(submodule, revs, *flags, head_ref_submodule);
handle_refs(refs, revs, *flags, refs_for_each_ref);
handle_refs(refs, revs, *flags, refs_head_ref);
if (!revs->single_worktree) {
struct all_refs_cb cb;
init_all_refs_cb(&cb, revs, *flags);
other_head_refs(handle_one_ref, &cb);
}
clear_ref_exclusion(&revs->ref_excludes);
} else if (!strcmp(arg, "--branches")) {
handle_refs(submodule, revs, *flags, for_each_branch_ref_submodule);
handle_refs(refs, revs, *flags, refs_for_each_branch_ref);
clear_ref_exclusion(&revs->ref_excludes);
} else if (!strcmp(arg, "--bisect")) {
read_bisect_terms(&term_bad, &term_good);
handle_refs(submodule, revs, *flags, for_each_bad_bisect_ref);
handle_refs(submodule, revs, *flags ^ (UNINTERESTING | BOTTOM), for_each_good_bisect_ref);
handle_refs(refs, revs, *flags, for_each_bad_bisect_ref);
handle_refs(refs, revs, *flags ^ (UNINTERESTING | BOTTOM),
for_each_good_bisect_ref);
revs->bisect = 1;
} else if (!strcmp(arg, "--tags")) {
handle_refs(submodule, revs, *flags, for_each_tag_ref_submodule);
handle_refs(refs, revs, *flags, refs_for_each_tag_ref);
clear_ref_exclusion(&revs->ref_excludes);
} else if (!strcmp(arg, "--remotes")) {
handle_refs(submodule, revs, *flags, for_each_remote_ref_submodule);
handle_refs(refs, revs, *flags, refs_for_each_remote_ref);
clear_ref_exclusion(&revs->ref_excludes);
} else if ((argcount = parse_long_opt("glob", argv, &optarg))) {
struct all_refs_cb cb;
@ -2169,6 +2252,8 @@ static int handle_revision_pseudo_opt(const char *submodule,
return error("invalid argument to --no-walk");
} else if (!strcmp(arg, "--do-walk")) {
revs->no_walk = 0;
} else if (!strcmp(arg, "--single-worktree")) {
revs->single_worktree = 1;
} else {
return 0;
}