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:
commit
8a044c7f1d
@ -184,6 +184,14 @@ explicitly.
|
|||||||
Pretend as if all objects mentioned by reflogs are listed on the
|
Pretend as if all objects mentioned by reflogs are listed on the
|
||||||
command line as `<commit>`.
|
command line as `<commit>`.
|
||||||
|
|
||||||
|
--single-worktree::
|
||||||
|
By default, all working trees will be examined by the
|
||||||
|
following options when there are more than one (see
|
||||||
|
linkgit:git-worktree[1]): `--all`, `--reflog` and
|
||||||
|
`--indexed-objects`.
|
||||||
|
This option forces them to examine the current working tree
|
||||||
|
only.
|
||||||
|
|
||||||
--ignore-missing::
|
--ignore-missing::
|
||||||
Upon seeing an invalid object name in the input, pretend as if
|
Upon seeing an invalid object name in the input, pretend as if
|
||||||
the bad input was not given.
|
the bad input was not given.
|
||||||
|
@ -32,11 +32,8 @@ Iteration functions
|
|||||||
|
|
||||||
* `for_each_glob_ref_in()` the previous and `for_each_ref_in()` combined.
|
* `for_each_glob_ref_in()` the previous and `for_each_ref_in()` combined.
|
||||||
|
|
||||||
* `head_ref_submodule()`, `for_each_ref_submodule()`,
|
* Use `refs_` API for accessing submodules. The submodule ref store could
|
||||||
`for_each_ref_in_submodule()`, `for_each_tag_ref_submodule()`,
|
be obtained with `get_submodule_ref_store()`.
|
||||||
`for_each_branch_ref_submodule()`, `for_each_remote_ref_submodule()`
|
|
||||||
do the same as the functions described above but for a specified
|
|
||||||
submodule.
|
|
||||||
|
|
||||||
* `for_each_rawref()` can be used to learn about broken ref and symref.
|
* `for_each_rawref()` can be used to learn about broken ref and symref.
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "progress.h"
|
#include "progress.h"
|
||||||
#include "list-objects.h"
|
#include "list-objects.h"
|
||||||
#include "packfile.h"
|
#include "packfile.h"
|
||||||
|
#include "worktree.h"
|
||||||
|
|
||||||
struct connectivity_progress {
|
struct connectivity_progress {
|
||||||
struct progress *progress;
|
struct progress *progress;
|
||||||
@ -177,6 +178,7 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,
|
|||||||
|
|
||||||
/* detached HEAD is not included in the list above */
|
/* detached HEAD is not included in the list above */
|
||||||
head_ref(add_one_ref, revs);
|
head_ref(add_one_ref, revs);
|
||||||
|
other_head_refs(add_one_ref, revs);
|
||||||
|
|
||||||
/* Add all reflog info */
|
/* Add all reflog info */
|
||||||
if (mark_reflog)
|
if (mark_reflog)
|
||||||
|
110
refs.c
110
refs.c
@ -336,12 +336,6 @@ int for_each_tag_ref(each_ref_fn fn, void *cb_data)
|
|||||||
return refs_for_each_tag_ref(get_main_ref_store(), fn, cb_data);
|
return refs_for_each_tag_ref(get_main_ref_store(), fn, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
|
|
||||||
{
|
|
||||||
return refs_for_each_tag_ref(get_submodule_ref_store(submodule),
|
|
||||||
fn, cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
||||||
{
|
{
|
||||||
return refs_for_each_ref_in(refs, "refs/heads/", fn, cb_data);
|
return refs_for_each_ref_in(refs, "refs/heads/", fn, cb_data);
|
||||||
@ -352,12 +346,6 @@ int for_each_branch_ref(each_ref_fn fn, void *cb_data)
|
|||||||
return refs_for_each_branch_ref(get_main_ref_store(), fn, cb_data);
|
return refs_for_each_branch_ref(get_main_ref_store(), fn, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
|
|
||||||
{
|
|
||||||
return refs_for_each_branch_ref(get_submodule_ref_store(submodule),
|
|
||||||
fn, cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
||||||
{
|
{
|
||||||
return refs_for_each_ref_in(refs, "refs/remotes/", fn, cb_data);
|
return refs_for_each_ref_in(refs, "refs/remotes/", fn, cb_data);
|
||||||
@ -368,12 +356,6 @@ int for_each_remote_ref(each_ref_fn fn, void *cb_data)
|
|||||||
return refs_for_each_remote_ref(get_main_ref_store(), fn, cb_data);
|
return refs_for_each_remote_ref(get_main_ref_store(), fn, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
|
|
||||||
{
|
|
||||||
return refs_for_each_remote_ref(get_submodule_ref_store(submodule),
|
|
||||||
fn, cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
int head_ref_namespaced(each_ref_fn fn, void *cb_data)
|
int head_ref_namespaced(each_ref_fn fn, void *cb_data)
|
||||||
{
|
{
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
@ -1266,19 +1248,13 @@ int refs_rename_ref_available(struct ref_store *refs,
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
|
int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
||||||
{
|
{
|
||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
int flag;
|
int flag;
|
||||||
|
|
||||||
if (submodule) {
|
if (!refs_read_ref_full(refs, "HEAD", RESOLVE_REF_READING,
|
||||||
if (resolve_gitlink_ref(submodule, "HEAD", oid.hash) == 0)
|
oid.hash, &flag))
|
||||||
return fn("HEAD", &oid, 0, cb_data);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!read_ref_full("HEAD", RESOLVE_REF_READING, oid.hash, &flag))
|
|
||||||
return fn("HEAD", &oid, flag, cb_data);
|
return fn("HEAD", &oid, flag, cb_data);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1286,7 +1262,7 @@ int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
|
|||||||
|
|
||||||
int head_ref(each_ref_fn fn, void *cb_data)
|
int head_ref(each_ref_fn fn, void *cb_data)
|
||||||
{
|
{
|
||||||
return head_ref_submodule(NULL, fn, cb_data);
|
return refs_head_ref(get_main_ref_store(), fn, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ref_iterator *refs_ref_iterator_begin(
|
struct ref_iterator *refs_ref_iterator_begin(
|
||||||
@ -1344,11 +1320,6 @@ int for_each_ref(each_ref_fn fn, void *cb_data)
|
|||||||
return refs_for_each_ref(get_main_ref_store(), fn, cb_data);
|
return refs_for_each_ref(get_main_ref_store(), fn, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
|
|
||||||
{
|
|
||||||
return refs_for_each_ref(get_submodule_ref_store(submodule), fn, cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,
|
int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,
|
||||||
each_ref_fn fn, void *cb_data)
|
each_ref_fn fn, void *cb_data)
|
||||||
{
|
{
|
||||||
@ -1370,23 +1341,15 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsig
|
|||||||
prefix, fn, 0, flag, cb_data);
|
prefix, fn, 0, flag, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int for_each_ref_in_submodule(const char *submodule, const char *prefix,
|
int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
|
||||||
each_ref_fn fn, void *cb_data)
|
each_ref_fn fn, void *cb_data,
|
||||||
{
|
unsigned int broken)
|
||||||
return refs_for_each_ref_in(get_submodule_ref_store(submodule),
|
|
||||||
prefix, fn, cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
int for_each_fullref_in_submodule(const char *submodule, const char *prefix,
|
|
||||||
each_ref_fn fn, void *cb_data,
|
|
||||||
unsigned int broken)
|
|
||||||
{
|
{
|
||||||
unsigned int flag = 0;
|
unsigned int flag = 0;
|
||||||
|
|
||||||
if (broken)
|
if (broken)
|
||||||
flag = DO_FOR_EACH_INCLUDE_BROKEN;
|
flag = DO_FOR_EACH_INCLUDE_BROKEN;
|
||||||
return do_for_each_ref(get_submodule_ref_store(submodule),
|
return do_for_each_ref(refs, prefix, fn, 0, flag, cb_data);
|
||||||
prefix, fn, 0, flag, cb_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int for_each_replace_ref(each_ref_fn fn, void *cb_data)
|
int for_each_replace_ref(each_ref_fn fn, void *cb_data)
|
||||||
@ -1521,25 +1484,10 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
|
|||||||
int resolve_gitlink_ref(const char *submodule, const char *refname,
|
int resolve_gitlink_ref(const char *submodule, const char *refname,
|
||||||
unsigned char *sha1)
|
unsigned char *sha1)
|
||||||
{
|
{
|
||||||
size_t len = strlen(submodule);
|
|
||||||
struct ref_store *refs;
|
struct ref_store *refs;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
while (len && submodule[len - 1] == '/')
|
refs = get_submodule_ref_store(submodule);
|
||||||
len--;
|
|
||||||
|
|
||||||
if (!len)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (submodule[len]) {
|
|
||||||
/* We need to strip off one or more trailing slashes */
|
|
||||||
char *stripped = xmemdupz(submodule, len);
|
|
||||||
|
|
||||||
refs = get_submodule_ref_store(stripped);
|
|
||||||
free(stripped);
|
|
||||||
} else {
|
|
||||||
refs = get_submodule_ref_store(submodule);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!refs)
|
if (!refs)
|
||||||
return -1;
|
return -1;
|
||||||
@ -1654,31 +1602,32 @@ struct ref_store *get_submodule_ref_store(const char *submodule)
|
|||||||
{
|
{
|
||||||
struct strbuf submodule_sb = STRBUF_INIT;
|
struct strbuf submodule_sb = STRBUF_INIT;
|
||||||
struct ref_store *refs;
|
struct ref_store *refs;
|
||||||
int ret;
|
char *to_free = NULL;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
if (!submodule || !*submodule) {
|
if (!submodule)
|
||||||
/*
|
return NULL;
|
||||||
* FIXME: This case is ideally not allowed. But that
|
|
||||||
* can't happen until we clean up all the callers.
|
len = strlen(submodule);
|
||||||
*/
|
while (len && is_dir_sep(submodule[len - 1]))
|
||||||
return get_main_ref_store();
|
len--;
|
||||||
}
|
if (!len)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (submodule[len])
|
||||||
|
/* We need to strip off one or more trailing slashes */
|
||||||
|
submodule = to_free = xmemdupz(submodule, len);
|
||||||
|
|
||||||
refs = lookup_ref_store_map(&submodule_ref_stores, submodule);
|
refs = lookup_ref_store_map(&submodule_ref_stores, submodule);
|
||||||
if (refs)
|
if (refs)
|
||||||
return refs;
|
goto done;
|
||||||
|
|
||||||
strbuf_addstr(&submodule_sb, submodule);
|
strbuf_addstr(&submodule_sb, submodule);
|
||||||
ret = is_nonbare_repository_dir(&submodule_sb);
|
if (!is_nonbare_repository_dir(&submodule_sb))
|
||||||
strbuf_release(&submodule_sb);
|
goto done;
|
||||||
if (!ret)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ret = submodule_to_gitdir(&submodule_sb, submodule);
|
if (submodule_to_gitdir(&submodule_sb, submodule))
|
||||||
if (ret) {
|
goto done;
|
||||||
strbuf_release(&submodule_sb);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* assume that add_submodule_odb() has been called */
|
/* assume that add_submodule_odb() has been called */
|
||||||
refs = ref_store_init(submodule_sb.buf,
|
refs = ref_store_init(submodule_sb.buf,
|
||||||
@ -1686,7 +1635,10 @@ struct ref_store *get_submodule_ref_store(const char *submodule)
|
|||||||
register_ref_store_map(&submodule_ref_stores, "submodule",
|
register_ref_store_map(&submodule_ref_stores, "submodule",
|
||||||
refs, submodule);
|
refs, submodule);
|
||||||
|
|
||||||
|
done:
|
||||||
strbuf_release(&submodule_sb);
|
strbuf_release(&submodule_sb);
|
||||||
|
free(to_free);
|
||||||
|
|
||||||
return refs;
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
refs.h
20
refs.h
@ -275,6 +275,8 @@ typedef int each_ref_fn(const char *refname,
|
|||||||
* modifies the reference also returns a nonzero value to immediately
|
* modifies the reference also returns a nonzero value to immediately
|
||||||
* stop the iteration. Returned references are sorted.
|
* stop the iteration. Returned references are sorted.
|
||||||
*/
|
*/
|
||||||
|
int refs_head_ref(struct ref_store *refs,
|
||||||
|
each_ref_fn fn, void *cb_data);
|
||||||
int refs_for_each_ref(struct ref_store *refs,
|
int refs_for_each_ref(struct ref_store *refs,
|
||||||
each_ref_fn fn, void *cb_data);
|
each_ref_fn fn, void *cb_data);
|
||||||
int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,
|
int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,
|
||||||
@ -289,6 +291,9 @@ int refs_for_each_remote_ref(struct ref_store *refs,
|
|||||||
int head_ref(each_ref_fn fn, void *cb_data);
|
int head_ref(each_ref_fn fn, void *cb_data);
|
||||||
int for_each_ref(each_ref_fn fn, void *cb_data);
|
int for_each_ref(each_ref_fn fn, void *cb_data);
|
||||||
int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);
|
int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);
|
||||||
|
int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
|
||||||
|
each_ref_fn fn, void *cb_data,
|
||||||
|
unsigned int broken);
|
||||||
int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,
|
int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,
|
||||||
unsigned int broken);
|
unsigned int broken);
|
||||||
int for_each_tag_ref(each_ref_fn fn, void *cb_data);
|
int for_each_tag_ref(each_ref_fn fn, void *cb_data);
|
||||||
@ -299,21 +304,6 @@ int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
|
|||||||
int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
|
int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
|
||||||
const char *prefix, void *cb_data);
|
const char *prefix, void *cb_data);
|
||||||
|
|
||||||
int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
|
|
||||||
int for_each_ref_submodule(const char *submodule,
|
|
||||||
each_ref_fn fn, void *cb_data);
|
|
||||||
int for_each_ref_in_submodule(const char *submodule, const char *prefix,
|
|
||||||
each_ref_fn fn, void *cb_data);
|
|
||||||
int for_each_fullref_in_submodule(const char *submodule, const char *prefix,
|
|
||||||
each_ref_fn fn, void *cb_data,
|
|
||||||
unsigned int broken);
|
|
||||||
int for_each_tag_ref_submodule(const char *submodule,
|
|
||||||
each_ref_fn fn, void *cb_data);
|
|
||||||
int for_each_branch_ref_submodule(const char *submodule,
|
|
||||||
each_ref_fn fn, void *cb_data);
|
|
||||||
int for_each_remote_ref_submodule(const char *submodule,
|
|
||||||
each_ref_fn fn, void *cb_data);
|
|
||||||
|
|
||||||
int head_ref_namespaced(each_ref_fn fn, void *cb_data);
|
int head_ref_namespaced(each_ref_fn fn, void *cb_data);
|
||||||
int for_each_namespaced_ref(each_ref_fn fn, void *cb_data);
|
int for_each_namespaced_ref(each_ref_fn fn, void *cb_data);
|
||||||
|
|
||||||
|
@ -106,15 +106,6 @@ static void files_reflog_path(struct files_ref_store *refs,
|
|||||||
struct strbuf *sb,
|
struct strbuf *sb,
|
||||||
const char *refname)
|
const char *refname)
|
||||||
{
|
{
|
||||||
if (!refname) {
|
|
||||||
/*
|
|
||||||
* FIXME: of course this is wrong in multi worktree
|
|
||||||
* setting. To be fixed real soon.
|
|
||||||
*/
|
|
||||||
strbuf_addf(sb, "%s/logs", refs->gitcommondir);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ref_type(refname)) {
|
switch (ref_type(refname)) {
|
||||||
case REF_TYPE_PER_WORKTREE:
|
case REF_TYPE_PER_WORKTREE:
|
||||||
case REF_TYPE_PSEUDOREF:
|
case REF_TYPE_PSEUDOREF:
|
||||||
@ -2059,23 +2050,63 @@ static struct ref_iterator_vtable files_reflog_iterator_vtable = {
|
|||||||
files_reflog_iterator_abort
|
files_reflog_iterator_abort
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_store)
|
static struct ref_iterator *reflog_iterator_begin(struct ref_store *ref_store,
|
||||||
|
const char *gitdir)
|
||||||
{
|
{
|
||||||
struct files_ref_store *refs =
|
|
||||||
files_downcast(ref_store, REF_STORE_READ,
|
|
||||||
"reflog_iterator_begin");
|
|
||||||
struct files_reflog_iterator *iter = xcalloc(1, sizeof(*iter));
|
struct files_reflog_iterator *iter = xcalloc(1, sizeof(*iter));
|
||||||
struct ref_iterator *ref_iterator = &iter->base;
|
struct ref_iterator *ref_iterator = &iter->base;
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
|
|
||||||
base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable);
|
base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable);
|
||||||
files_reflog_path(refs, &sb, NULL);
|
strbuf_addf(&sb, "%s/logs", gitdir);
|
||||||
iter->dir_iterator = dir_iterator_begin(sb.buf);
|
iter->dir_iterator = dir_iterator_begin(sb.buf);
|
||||||
iter->ref_store = ref_store;
|
iter->ref_store = ref_store;
|
||||||
strbuf_release(&sb);
|
strbuf_release(&sb);
|
||||||
|
|
||||||
return ref_iterator;
|
return ref_iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum iterator_selection reflog_iterator_select(
|
||||||
|
struct ref_iterator *iter_worktree,
|
||||||
|
struct ref_iterator *iter_common,
|
||||||
|
void *cb_data)
|
||||||
|
{
|
||||||
|
if (iter_worktree) {
|
||||||
|
/*
|
||||||
|
* We're a bit loose here. We probably should ignore
|
||||||
|
* common refs if they are accidentally added as
|
||||||
|
* per-worktree refs.
|
||||||
|
*/
|
||||||
|
return ITER_SELECT_0;
|
||||||
|
} else if (iter_common) {
|
||||||
|
if (ref_type(iter_common->refname) == REF_TYPE_NORMAL)
|
||||||
|
return ITER_SELECT_1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The main ref store may contain main worktree's
|
||||||
|
* per-worktree refs, which should be ignored
|
||||||
|
*/
|
||||||
|
return ITER_SKIP_1;
|
||||||
|
} else
|
||||||
|
return ITER_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_store)
|
||||||
|
{
|
||||||
|
struct files_ref_store *refs =
|
||||||
|
files_downcast(ref_store, REF_STORE_READ,
|
||||||
|
"reflog_iterator_begin");
|
||||||
|
|
||||||
|
if (!strcmp(refs->gitdir, refs->gitcommondir)) {
|
||||||
|
return reflog_iterator_begin(ref_store, refs->gitcommondir);
|
||||||
|
} else {
|
||||||
|
return merge_ref_iterator_begin(
|
||||||
|
reflog_iterator_begin(ref_store, refs->gitdir),
|
||||||
|
reflog_iterator_begin(ref_store, refs->gitcommondir),
|
||||||
|
reflog_iterator_select, refs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If update is a direct update of head_ref (the reference pointed to
|
* If update is a direct update of head_ref (the reference pointed to
|
||||||
* by HEAD), then add an extra REF_LOG_ONLY update for HEAD.
|
* by HEAD), then add an extra REF_LOG_ONLY update for HEAD.
|
||||||
|
131
revision.c
131
revision.c
@ -20,6 +20,7 @@
|
|||||||
#include "cache-tree.h"
|
#include "cache-tree.h"
|
||||||
#include "bisect.h"
|
#include "bisect.h"
|
||||||
#include "packfile.h"
|
#include "packfile.h"
|
||||||
|
#include "worktree.h"
|
||||||
|
|
||||||
volatile show_early_output_fn_t show_early_output;
|
volatile show_early_output_fn_t show_early_output;
|
||||||
|
|
||||||
@ -1132,6 +1133,7 @@ struct all_refs_cb {
|
|||||||
int warned_bad_reflog;
|
int warned_bad_reflog;
|
||||||
struct rev_info *all_revs;
|
struct rev_info *all_revs;
|
||||||
const char *name_for_errormsg;
|
const char *name_for_errormsg;
|
||||||
|
struct ref_store *refs;
|
||||||
};
|
};
|
||||||
|
|
||||||
int ref_excluded(struct string_list *ref_excludes, const char *path)
|
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_revs = revs;
|
||||||
cb->all_flags = flags;
|
cb->all_flags = flags;
|
||||||
revs->rev_input_given = 1;
|
revs->rev_input_given = 1;
|
||||||
|
cb->refs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_ref_exclusion(struct string_list **ref_excludes_p)
|
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);
|
string_list_append(*ref_excludes_p, exclude);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_refs(const char *submodule, struct rev_info *revs, unsigned flags,
|
static void handle_refs(struct ref_store *refs,
|
||||||
int (*for_each)(const char *, each_ref_fn, void *))
|
struct rev_info *revs, unsigned flags,
|
||||||
|
int (*for_each)(struct ref_store *, each_ref_fn, void *))
|
||||||
{
|
{
|
||||||
struct all_refs_cb cb;
|
struct all_refs_cb cb;
|
||||||
|
|
||||||
|
if (!refs) {
|
||||||
|
/* this could happen with uninitialized submodules */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
init_all_refs_cb(&cb, revs, flags);
|
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)
|
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;
|
struct all_refs_cb *cb = cb_data;
|
||||||
cb->warned_bad_reflog = 0;
|
cb->warned_bad_reflog = 0;
|
||||||
cb->name_for_errormsg = path;
|
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;
|
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)
|
void add_reflogs_to_pending(struct rev_info *revs, unsigned flags)
|
||||||
{
|
{
|
||||||
struct all_refs_cb cb;
|
struct all_refs_cb cb;
|
||||||
|
|
||||||
cb.all_revs = revs;
|
cb.all_revs = revs;
|
||||||
cb.all_flags = flags;
|
cb.all_flags = flags;
|
||||||
|
cb.refs = get_main_ref_store();
|
||||||
for_each_reflog(handle_one_reflog, &cb);
|
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,
|
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;
|
int i;
|
||||||
|
|
||||||
read_cache();
|
for (i = 0; i < istate->cache_nr; i++) {
|
||||||
for (i = 0; i < active_nr; i++) {
|
struct cache_entry *ce = istate->cache[i];
|
||||||
struct cache_entry *ce = active_cache[i];
|
|
||||||
struct blob *blob;
|
struct blob *blob;
|
||||||
|
|
||||||
if (S_ISGITLINK(ce->ce_mode))
|
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);
|
ce->ce_mode, ce->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (active_cache_tree) {
|
if (istate->cache_tree) {
|
||||||
struct strbuf path = STRBUF_INIT;
|
struct strbuf path = STRBUF_INIT;
|
||||||
add_cache_tree(active_cache_tree, revs, &path);
|
add_cache_tree(istate->cache_tree, revs, &path);
|
||||||
strbuf_release(&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,
|
static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
|
||||||
int exclude_parent)
|
int exclude_parent)
|
||||||
{
|
{
|
||||||
@ -2069,23 +2129,25 @@ void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
|
|||||||
ctx->argc -= n;
|
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;
|
struct strbuf bisect_refs = STRBUF_INIT;
|
||||||
int status;
|
int status;
|
||||||
strbuf_addf(&bisect_refs, "refs/bisect/%s", term);
|
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);
|
strbuf_release(&bisect_refs);
|
||||||
return status;
|
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,
|
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 *arg = argv[0];
|
||||||
const char *optarg;
|
const char *optarg;
|
||||||
|
struct ref_store *refs;
|
||||||
int argcount;
|
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!
|
* 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.
|
* register it in the list at the top of handle_revision_opt.
|
||||||
*/
|
*/
|
||||||
if (!strcmp(arg, "--all")) {
|
if (!strcmp(arg, "--all")) {
|
||||||
handle_refs(submodule, revs, *flags, for_each_ref_submodule);
|
handle_refs(refs, revs, *flags, refs_for_each_ref);
|
||||||
handle_refs(submodule, revs, *flags, head_ref_submodule);
|
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);
|
clear_ref_exclusion(&revs->ref_excludes);
|
||||||
} else if (!strcmp(arg, "--branches")) {
|
} 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);
|
clear_ref_exclusion(&revs->ref_excludes);
|
||||||
} else if (!strcmp(arg, "--bisect")) {
|
} else if (!strcmp(arg, "--bisect")) {
|
||||||
read_bisect_terms(&term_bad, &term_good);
|
read_bisect_terms(&term_bad, &term_good);
|
||||||
handle_refs(submodule, revs, *flags, for_each_bad_bisect_ref);
|
handle_refs(refs, revs, *flags, for_each_bad_bisect_ref);
|
||||||
handle_refs(submodule, revs, *flags ^ (UNINTERESTING | BOTTOM), for_each_good_bisect_ref);
|
handle_refs(refs, revs, *flags ^ (UNINTERESTING | BOTTOM),
|
||||||
|
for_each_good_bisect_ref);
|
||||||
revs->bisect = 1;
|
revs->bisect = 1;
|
||||||
} else if (!strcmp(arg, "--tags")) {
|
} 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);
|
clear_ref_exclusion(&revs->ref_excludes);
|
||||||
} else if (!strcmp(arg, "--remotes")) {
|
} 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);
|
clear_ref_exclusion(&revs->ref_excludes);
|
||||||
} else if ((argcount = parse_long_opt("glob", argv, &optarg))) {
|
} else if ((argcount = parse_long_opt("glob", argv, &optarg))) {
|
||||||
struct all_refs_cb cb;
|
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");
|
return error("invalid argument to --no-walk");
|
||||||
} else if (!strcmp(arg, "--do-walk")) {
|
} else if (!strcmp(arg, "--do-walk")) {
|
||||||
revs->no_walk = 0;
|
revs->no_walk = 0;
|
||||||
|
} else if (!strcmp(arg, "--single-worktree")) {
|
||||||
|
revs->single_worktree = 1;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,7 @@ struct rev_info {
|
|||||||
topo_order:1,
|
topo_order:1,
|
||||||
simplify_merges:1,
|
simplify_merges:1,
|
||||||
simplify_by_decoration:1,
|
simplify_by_decoration:1,
|
||||||
|
single_worktree:1,
|
||||||
tag_objects:1,
|
tag_objects:1,
|
||||||
tree_objects:1,
|
tree_objects:1,
|
||||||
blob_objects:1,
|
blob_objects:1,
|
||||||
|
@ -69,6 +69,13 @@ int is_staging_gitmodules_ok(const struct index_state *istate)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int for_each_remote_ref_submodule(const char *submodule,
|
||||||
|
each_ref_fn fn, void *cb_data)
|
||||||
|
{
|
||||||
|
return refs_for_each_remote_ref(get_submodule_ref_store(submodule),
|
||||||
|
fn, cb_data);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to update the "path" entry in the "submodule.<name>" section of the
|
* Try to update the "path" entry in the "submodule.<name>" section of the
|
||||||
* .gitmodules file. Return 0 only if a .gitmodules file was found, a section
|
* .gitmodules file. Return 0 only if a .gitmodules file was found, a section
|
||||||
@ -1627,6 +1634,8 @@ static int find_first_merges(struct object_array *result, const char *path,
|
|||||||
oid_to_hex(&a->object.oid));
|
oid_to_hex(&a->object.oid));
|
||||||
init_revisions(&revs, NULL);
|
init_revisions(&revs, NULL);
|
||||||
rev_opts.submodule = path;
|
rev_opts.submodule = path;
|
||||||
|
/* FIXME: can't handle linked worktrees in submodules yet */
|
||||||
|
revs.single_worktree = path != NULL;
|
||||||
setup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts);
|
setup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts);
|
||||||
|
|
||||||
/* save all revisions from the above list that contain b */
|
/* save all revisions from the above list that contain b */
|
||||||
|
@ -49,4 +49,34 @@ test_expect_success 'create_symref(FOO, refs/heads/master)' '
|
|||||||
test_cmp expected actual
|
test_cmp expected actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'for_each_reflog()' '
|
||||||
|
echo $_z40 > .git/logs/PSEUDO-MAIN &&
|
||||||
|
mkdir -p .git/logs/refs/bisect &&
|
||||||
|
echo $_z40 > .git/logs/refs/bisect/random &&
|
||||||
|
|
||||||
|
echo $_z40 > .git/worktrees/wt/logs/PSEUDO-WT &&
|
||||||
|
mkdir -p .git/worktrees/wt/logs/refs/bisect &&
|
||||||
|
echo $_z40 > .git/worktrees/wt/logs/refs/bisect/wt-random &&
|
||||||
|
|
||||||
|
$RWT for-each-reflog | cut -c 42- | sort >actual &&
|
||||||
|
cat >expected <<-\EOF &&
|
||||||
|
HEAD 0x1
|
||||||
|
PSEUDO-WT 0x0
|
||||||
|
refs/bisect/wt-random 0x0
|
||||||
|
refs/heads/master 0x0
|
||||||
|
refs/heads/wt-master 0x0
|
||||||
|
EOF
|
||||||
|
test_cmp expected actual &&
|
||||||
|
|
||||||
|
$RMAIN for-each-reflog | cut -c 42- | sort >actual &&
|
||||||
|
cat >expected <<-\EOF &&
|
||||||
|
HEAD 0x1
|
||||||
|
PSEUDO-MAIN 0x0
|
||||||
|
refs/bisect/random 0x0
|
||||||
|
refs/heads/master 0x0
|
||||||
|
refs/heads/wt-master 0x0
|
||||||
|
EOF
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
@ -283,4 +283,41 @@ test_expect_success 'prune: handle alternate object database' '
|
|||||||
git -C B prune
|
git -C B prune
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'prune: handle index in multiple worktrees' '
|
||||||
|
git worktree add second-worktree &&
|
||||||
|
echo "new blob for second-worktree" >second-worktree/blob &&
|
||||||
|
git -C second-worktree add blob &&
|
||||||
|
git prune --expire=now &&
|
||||||
|
git -C second-worktree show :blob >actual &&
|
||||||
|
test_cmp second-worktree/blob actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'prune: handle HEAD in multiple worktrees' '
|
||||||
|
git worktree add --detach third-worktree &&
|
||||||
|
echo "new blob for third-worktree" >third-worktree/blob &&
|
||||||
|
git -C third-worktree add blob &&
|
||||||
|
git -C third-worktree commit -m "third" &&
|
||||||
|
rm .git/worktrees/third-worktree/index &&
|
||||||
|
test_must_fail git -C third-worktree show :blob &&
|
||||||
|
git prune --expire=now &&
|
||||||
|
git -C third-worktree show HEAD:blob >actual &&
|
||||||
|
test_cmp third-worktree/blob actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'prune: handle HEAD reflog in multiple worktrees' '
|
||||||
|
git config core.logAllRefUpdates true &&
|
||||||
|
echo "lost blob for third-worktree" >expected &&
|
||||||
|
(
|
||||||
|
cd third-worktree &&
|
||||||
|
cat ../expected >blob &&
|
||||||
|
git add blob &&
|
||||||
|
git commit -m "second commit in third" &&
|
||||||
|
git reset --hard HEAD^
|
||||||
|
) &&
|
||||||
|
git prune --expire=now &&
|
||||||
|
SHA1=`git hash-object expected` &&
|
||||||
|
git -C third-worktree show "$SHA1" >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
22
worktree.c
22
worktree.c
@ -386,3 +386,25 @@ int submodule_uses_worktrees(const char *path)
|
|||||||
closedir(dir);
|
closedir(dir);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int other_head_refs(each_ref_fn fn, void *cb_data)
|
||||||
|
{
|
||||||
|
struct worktree **worktrees, **p;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
worktrees = get_worktrees(0);
|
||||||
|
for (p = worktrees; *p; p++) {
|
||||||
|
struct worktree *wt = *p;
|
||||||
|
struct ref_store *refs;
|
||||||
|
|
||||||
|
if (wt->is_current)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
refs = get_worktree_ref_store(wt);
|
||||||
|
ret = refs_head_ref(refs, fn, cb_data);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free_worktrees(worktrees);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef WORKTREE_H
|
#ifndef WORKTREE_H
|
||||||
#define WORKTREE_H
|
#define WORKTREE_H
|
||||||
|
|
||||||
|
#include "refs.h"
|
||||||
|
|
||||||
struct worktree {
|
struct worktree {
|
||||||
char *path;
|
char *path;
|
||||||
char *id;
|
char *id;
|
||||||
@ -70,6 +72,12 @@ extern void free_worktrees(struct worktree **);
|
|||||||
extern const struct worktree *find_shared_symref(const char *symref,
|
extern const struct worktree *find_shared_symref(const char *symref,
|
||||||
const char *target);
|
const char *target);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Similar to head_ref() for all HEADs _except_ one from the current
|
||||||
|
* worktree, which is covered by head_ref().
|
||||||
|
*/
|
||||||
|
int other_head_refs(each_ref_fn fn, void *cb_data);
|
||||||
|
|
||||||
int is_worktree_being_rebased(const struct worktree *wt, const char *target);
|
int is_worktree_being_rebased(const struct worktree *wt, const char *target);
|
||||||
int is_worktree_being_bisected(const struct worktree *wt, const char *target);
|
int is_worktree_being_bisected(const struct worktree *wt, const char *target);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user