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:
131
revision.c
131
revision.c
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user