Merge branch 'es/worktree-repair'
"git worktree" gained a "repair" subcommand to help users recover after moving the worktrees or repository manually without telling Git. Also, "git init --separate-git-dir" no longer corrupts administrative data related to linked worktrees. * es/worktree-repair: init: make --separate-git-dir work from within linked worktree init: teach --separate-git-dir to repair linked worktrees worktree: teach "repair" to fix outgoing links to worktrees worktree: teach "repair" to fix worktree back-links to main worktree worktree: add skeleton "repair" command
This commit is contained in:
commit
eb7460fd31
@ -15,6 +15,7 @@ SYNOPSIS
|
||||
'git worktree move' <worktree> <new-path>
|
||||
'git worktree prune' [-n] [-v] [--expire <expire>]
|
||||
'git worktree remove' [-f] <worktree>
|
||||
'git worktree repair' [<path>...]
|
||||
'git worktree unlock' <worktree>
|
||||
|
||||
DESCRIPTION
|
||||
@ -97,7 +98,10 @@ with `--reason`.
|
||||
move::
|
||||
|
||||
Move a working tree to a new location. Note that the main working tree
|
||||
or linked working trees containing submodules cannot be moved.
|
||||
or linked working trees containing submodules cannot be moved with this
|
||||
command. (The `git worktree repair` command, however, can reestablish
|
||||
the connection with linked working trees if you move the main working
|
||||
tree manually.)
|
||||
|
||||
prune::
|
||||
|
||||
@ -110,6 +114,23 @@ and no modification in tracked files) can be removed. Unclean working
|
||||
trees or ones with submodules can be removed with `--force`. The main
|
||||
working tree cannot be removed.
|
||||
|
||||
repair [<path>...]::
|
||||
|
||||
Repair working tree administrative files, if possible, if they have
|
||||
become corrupted or outdated due to external factors.
|
||||
+
|
||||
For instance, if the main working tree (or bare repository) is moved,
|
||||
linked working trees will be unable to locate it. Running `repair` in
|
||||
the main working tree will reestablish the connection from linked
|
||||
working trees back to the main working tree.
|
||||
+
|
||||
Similarly, if a linked working tree is moved without using `git worktree
|
||||
move`, the main working tree (or bare repository) will be unable to
|
||||
locate it. Running `repair` within the recently-moved working tree will
|
||||
reestablish the connection. If multiple linked working trees are moved,
|
||||
running `repair` from any working tree with each tree's new `<path>` as
|
||||
an argument, will reestablish the connection to all the specified paths.
|
||||
|
||||
unlock::
|
||||
|
||||
Unlock a working tree, allowing it to be pruned, moved or deleted.
|
||||
@ -303,7 +324,8 @@ in the entry's directory. For example, if a linked working tree is moved
|
||||
to `/newpath/test-next` and its `.git` file points to
|
||||
`/path/main/.git/worktrees/test-next`, then update
|
||||
`/path/main/.git/worktrees/test-next/gitdir` to reference `/newpath/test-next`
|
||||
instead.
|
||||
instead. Better yet, run `git worktree repair` to reestablish the connection
|
||||
automatically.
|
||||
|
||||
To prevent a `$GIT_DIR/worktrees` entry from being pruned (which
|
||||
can be useful in some situations, such as when the
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "builtin.h"
|
||||
#include "exec-cmd.h"
|
||||
#include "parse-options.h"
|
||||
#include "worktree.h"
|
||||
|
||||
#ifndef DEFAULT_GIT_TEMPLATE_DIR
|
||||
#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
|
||||
@ -364,6 +365,7 @@ static void separate_git_dir(const char *git_dir, const char *git_link)
|
||||
|
||||
if (rename(src, git_dir))
|
||||
die_errno(_("unable to move %s to %s"), src, git_dir);
|
||||
repair_worktrees(NULL, NULL);
|
||||
}
|
||||
|
||||
write_file(git_link, "gitdir: %s", git_dir);
|
||||
@ -640,6 +642,30 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
if (!git_dir)
|
||||
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
|
||||
|
||||
/*
|
||||
* When --separate-git-dir is used inside a linked worktree, take
|
||||
* care to ensure that the common .git/ directory is relocated, not
|
||||
* the worktree-specific .git/worktrees/<id>/ directory.
|
||||
*/
|
||||
if (real_git_dir) {
|
||||
int err;
|
||||
const char *p;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
p = read_gitfile_gently(git_dir, &err);
|
||||
if (p && get_common_dir(&sb, p)) {
|
||||
struct strbuf mainwt = STRBUF_INIT;
|
||||
|
||||
strbuf_addbuf(&mainwt, &sb);
|
||||
strbuf_strip_suffix(&mainwt, "/.git");
|
||||
if (chdir(mainwt.buf) < 0)
|
||||
die_errno(_("cannot chdir to %s"), mainwt.buf);
|
||||
strbuf_release(&mainwt);
|
||||
git_dir = strbuf_detach(&sb, NULL);
|
||||
}
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
if (is_bare_repository_cfg < 0)
|
||||
is_bare_repository_cfg = guess_repository_type(git_dir);
|
||||
|
||||
|
@ -1028,6 +1028,34 @@ static int remove_worktree(int ac, const char **av, const char *prefix)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void report_repair(int iserr, const char *path, const char *msg, void *cb_data)
|
||||
{
|
||||
if (!iserr) {
|
||||
printf_ln(_("repair: %s: %s"), msg, path);
|
||||
} else {
|
||||
int *exit_status = (int *)cb_data;
|
||||
fprintf_ln(stderr, _("error: %s: %s"), msg, path);
|
||||
*exit_status = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int repair(int ac, const char **av, const char *prefix)
|
||||
{
|
||||
const char **p;
|
||||
const char *self[] = { ".", NULL };
|
||||
struct option options[] = {
|
||||
OPT_END()
|
||||
};
|
||||
int rc = 0;
|
||||
|
||||
ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
|
||||
repair_worktrees(report_repair, &rc);
|
||||
p = ac > 0 ? av : self;
|
||||
for (; *p; p++)
|
||||
repair_worktree_at_path(*p, report_repair, &rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cmd_worktree(int ac, const char **av, const char *prefix)
|
||||
{
|
||||
struct option options[] = {
|
||||
@ -1054,5 +1082,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
|
||||
return move_worktree(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "remove"))
|
||||
return remove_worktree(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "repair"))
|
||||
return repair(ac - 1, av + 1, prefix);
|
||||
usage_with_options(worktree_usage, options);
|
||||
}
|
||||
|
@ -329,6 +329,15 @@ test_expect_success 'implicit bare & --separate-git-dir incompatible' '
|
||||
test_i18ngrep "incompatible" err
|
||||
'
|
||||
|
||||
test_expect_success 'bare & --separate-git-dir incompatible within worktree' '
|
||||
test_when_finished "rm -rf bare.git linkwt seprepo" &&
|
||||
test_commit gumby &&
|
||||
git clone --bare . bare.git &&
|
||||
git -C bare.git worktree add --detach ../linkwt &&
|
||||
test_must_fail git -C linkwt init --separate-git-dir seprepo 2>err &&
|
||||
test_i18ngrep "incompatible" err
|
||||
'
|
||||
|
||||
test_lazy_prereq GETCWD_IGNORES_PERMS '
|
||||
base=GETCWD_TEST_BASE_DIR &&
|
||||
mkdir -p $base/dir &&
|
||||
@ -405,6 +414,25 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
|
||||
test_path_is_dir realgitdir/refs
|
||||
'
|
||||
|
||||
sep_git_dir_worktree () {
|
||||
test_when_finished "rm -rf mainwt linkwt seprepo" &&
|
||||
git init mainwt &&
|
||||
test_commit -C mainwt gumby &&
|
||||
git -C mainwt worktree add --detach ../linkwt &&
|
||||
git -C "$1" init --separate-git-dir ../seprepo &&
|
||||
git -C mainwt rev-parse --git-common-dir >expect &&
|
||||
git -C linkwt rev-parse --git-common-dir >actual &&
|
||||
test_cmp expect actual
|
||||
}
|
||||
|
||||
test_expect_success 're-init to move gitdir with linked worktrees' '
|
||||
sep_git_dir_worktree mainwt
|
||||
'
|
||||
|
||||
test_expect_success 're-init to move gitdir within linked worktree' '
|
||||
sep_git_dir_worktree linkwt
|
||||
'
|
||||
|
||||
test_expect_success MINGW '.git hidden' '
|
||||
rm -rf newdir &&
|
||||
(
|
||||
|
179
t/t2406-worktree-repair.sh
Executable file
179
t/t2406-worktree-repair.sh
Executable file
@ -0,0 +1,179 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='test git worktree repair'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
test_commit init
|
||||
'
|
||||
|
||||
test_expect_success 'skip missing worktree' '
|
||||
test_when_finished "git worktree prune" &&
|
||||
git worktree add --detach missing &&
|
||||
rm -rf missing &&
|
||||
git worktree repair >out 2>err &&
|
||||
test_must_be_empty out &&
|
||||
test_must_be_empty err
|
||||
'
|
||||
|
||||
test_expect_success 'worktree path not directory' '
|
||||
test_when_finished "git worktree prune" &&
|
||||
git worktree add --detach notdir &&
|
||||
rm -rf notdir &&
|
||||
>notdir &&
|
||||
test_must_fail git worktree repair >out 2>err &&
|
||||
test_must_be_empty out &&
|
||||
test_i18ngrep "not a directory" err
|
||||
'
|
||||
|
||||
test_expect_success "don't clobber .git repo" '
|
||||
test_when_finished "rm -rf repo && git worktree prune" &&
|
||||
git worktree add --detach repo &&
|
||||
rm -rf repo &&
|
||||
test_create_repo repo &&
|
||||
test_must_fail git worktree repair >out 2>err &&
|
||||
test_must_be_empty out &&
|
||||
test_i18ngrep ".git is not a file" err
|
||||
'
|
||||
|
||||
test_corrupt_gitfile () {
|
||||
butcher=$1 &&
|
||||
problem=$2 &&
|
||||
repairdir=${3:-.} &&
|
||||
test_when_finished 'rm -rf corrupt && git worktree prune' &&
|
||||
git worktree add --detach corrupt &&
|
||||
git -C corrupt rev-parse --absolute-git-dir >expect &&
|
||||
eval "$butcher" &&
|
||||
git -C "$repairdir" worktree repair >out 2>err &&
|
||||
test_i18ngrep "$problem" out &&
|
||||
test_must_be_empty err &&
|
||||
git -C corrupt rev-parse --absolute-git-dir >actual &&
|
||||
test_cmp expect actual
|
||||
}
|
||||
|
||||
test_expect_success 'repair missing .git file' '
|
||||
test_corrupt_gitfile "rm -f corrupt/.git" ".git file broken"
|
||||
'
|
||||
|
||||
test_expect_success 'repair bogus .git file' '
|
||||
test_corrupt_gitfile "echo \"gitdir: /nowhere\" >corrupt/.git" \
|
||||
".git file broken"
|
||||
'
|
||||
|
||||
test_expect_success 'repair incorrect .git file' '
|
||||
test_when_finished "rm -rf other && git worktree prune" &&
|
||||
test_create_repo other &&
|
||||
other=$(git -C other rev-parse --absolute-git-dir) &&
|
||||
test_corrupt_gitfile "echo \"gitdir: $other\" >corrupt/.git" \
|
||||
".git file incorrect"
|
||||
'
|
||||
|
||||
test_expect_success 'repair .git file from main/.git' '
|
||||
test_corrupt_gitfile "rm -f corrupt/.git" ".git file broken" .git
|
||||
'
|
||||
|
||||
test_expect_success 'repair .git file from linked worktree' '
|
||||
test_when_finished "rm -rf other && git worktree prune" &&
|
||||
git worktree add --detach other &&
|
||||
test_corrupt_gitfile "rm -f corrupt/.git" ".git file broken" other
|
||||
'
|
||||
|
||||
test_expect_success 'repair .git file from bare.git' '
|
||||
test_when_finished "rm -rf bare.git corrupt && git worktree prune" &&
|
||||
git clone --bare . bare.git &&
|
||||
git -C bare.git worktree add --detach ../corrupt &&
|
||||
git -C corrupt rev-parse --absolute-git-dir >expect &&
|
||||
rm -f corrupt/.git &&
|
||||
git -C bare.git worktree repair &&
|
||||
git -C corrupt rev-parse --absolute-git-dir >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'invalid worktree path' '
|
||||
test_must_fail git worktree repair /notvalid >out 2>err &&
|
||||
test_must_be_empty out &&
|
||||
test_i18ngrep "not a valid path" err
|
||||
'
|
||||
|
||||
test_expect_success 'repo not found; .git not file' '
|
||||
test_when_finished "rm -rf not-a-worktree" &&
|
||||
test_create_repo not-a-worktree &&
|
||||
test_must_fail git worktree repair not-a-worktree >out 2>err &&
|
||||
test_must_be_empty out &&
|
||||
test_i18ngrep ".git is not a file" err
|
||||
'
|
||||
|
||||
test_expect_success 'repo not found; .git file broken' '
|
||||
test_when_finished "rm -rf orig moved && git worktree prune" &&
|
||||
git worktree add --detach orig &&
|
||||
echo /invalid >orig/.git &&
|
||||
mv orig moved &&
|
||||
test_must_fail git worktree repair moved >out 2>err &&
|
||||
test_must_be_empty out &&
|
||||
test_i18ngrep ".git file broken" err
|
||||
'
|
||||
|
||||
test_expect_success 'repair broken gitdir' '
|
||||
test_when_finished "rm -rf orig moved && git worktree prune" &&
|
||||
git worktree add --detach orig &&
|
||||
sed s,orig/\.git$,moved/.git, .git/worktrees/orig/gitdir >expect &&
|
||||
rm .git/worktrees/orig/gitdir &&
|
||||
mv orig moved &&
|
||||
git worktree repair moved >out 2>err &&
|
||||
test_cmp expect .git/worktrees/orig/gitdir &&
|
||||
test_i18ngrep "gitdir unreadable" out &&
|
||||
test_must_be_empty err
|
||||
'
|
||||
|
||||
test_expect_success 'repair incorrect gitdir' '
|
||||
test_when_finished "rm -rf orig moved && git worktree prune" &&
|
||||
git worktree add --detach orig &&
|
||||
sed s,orig/\.git$,moved/.git, .git/worktrees/orig/gitdir >expect &&
|
||||
mv orig moved &&
|
||||
git worktree repair moved >out 2>err &&
|
||||
test_cmp expect .git/worktrees/orig/gitdir &&
|
||||
test_i18ngrep "gitdir incorrect" out &&
|
||||
test_must_be_empty err
|
||||
'
|
||||
|
||||
test_expect_success 'repair gitdir (implicit) from linked worktree' '
|
||||
test_when_finished "rm -rf orig moved && git worktree prune" &&
|
||||
git worktree add --detach orig &&
|
||||
sed s,orig/\.git$,moved/.git, .git/worktrees/orig/gitdir >expect &&
|
||||
mv orig moved &&
|
||||
git -C moved worktree repair >out 2>err &&
|
||||
test_cmp expect .git/worktrees/orig/gitdir &&
|
||||
test_i18ngrep "gitdir incorrect" out &&
|
||||
test_must_be_empty err
|
||||
'
|
||||
|
||||
test_expect_success 'unable to repair gitdir (implicit) from main worktree' '
|
||||
test_when_finished "rm -rf orig moved && git worktree prune" &&
|
||||
git worktree add --detach orig &&
|
||||
cat .git/worktrees/orig/gitdir >expect &&
|
||||
mv orig moved &&
|
||||
git worktree repair >out 2>err &&
|
||||
test_cmp expect .git/worktrees/orig/gitdir &&
|
||||
test_must_be_empty out &&
|
||||
test_must_be_empty err
|
||||
'
|
||||
|
||||
test_expect_success 'repair multiple gitdir files' '
|
||||
test_when_finished "rm -rf orig1 orig2 moved1 moved2 &&
|
||||
git worktree prune" &&
|
||||
git worktree add --detach orig1 &&
|
||||
git worktree add --detach orig2 &&
|
||||
sed s,orig1/\.git$,moved1/.git, .git/worktrees/orig1/gitdir >expect1 &&
|
||||
sed s,orig2/\.git$,moved2/.git, .git/worktrees/orig2/gitdir >expect2 &&
|
||||
mv orig1 moved1 &&
|
||||
mv orig2 moved2 &&
|
||||
git worktree repair moved1 moved2 >out 2>err &&
|
||||
test_cmp expect1 .git/worktrees/orig1/gitdir &&
|
||||
test_cmp expect2 .git/worktrees/orig2/gitdir &&
|
||||
test_i18ngrep "gitdir incorrect:.*orig1/gitdir$" out &&
|
||||
test_i18ngrep "gitdir incorrect:.*orig2/gitdir$" out &&
|
||||
test_must_be_empty err
|
||||
'
|
||||
|
||||
test_done
|
135
worktree.c
135
worktree.c
@ -571,3 +571,138 @@ int other_head_refs(each_ref_fn fn, void *cb_data)
|
||||
free_worktrees(worktrees);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Repair worktree's /path/to/worktree/.git file if missing, corrupt, or not
|
||||
* pointing at <repo>/worktrees/<id>.
|
||||
*/
|
||||
static void repair_gitfile(struct worktree *wt,
|
||||
worktree_repair_fn fn, void *cb_data)
|
||||
{
|
||||
struct strbuf dotgit = STRBUF_INIT;
|
||||
struct strbuf repo = STRBUF_INIT;
|
||||
char *backlink;
|
||||
const char *repair = NULL;
|
||||
int err;
|
||||
|
||||
/* missing worktree can't be repaired */
|
||||
if (!file_exists(wt->path))
|
||||
return;
|
||||
|
||||
if (!is_directory(wt->path)) {
|
||||
fn(1, wt->path, _("not a directory"), cb_data);
|
||||
return;
|
||||
}
|
||||
|
||||
strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
|
||||
strbuf_addf(&dotgit, "%s/.git", wt->path);
|
||||
backlink = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
|
||||
|
||||
if (err == READ_GITFILE_ERR_NOT_A_FILE)
|
||||
fn(1, wt->path, _(".git is not a file"), cb_data);
|
||||
else if (err)
|
||||
repair = _(".git file broken");
|
||||
else if (fspathcmp(backlink, repo.buf))
|
||||
repair = _(".git file incorrect");
|
||||
|
||||
if (repair) {
|
||||
fn(0, wt->path, repair, cb_data);
|
||||
write_file(dotgit.buf, "gitdir: %s", repo.buf);
|
||||
}
|
||||
|
||||
free(backlink);
|
||||
strbuf_release(&repo);
|
||||
strbuf_release(&dotgit);
|
||||
}
|
||||
|
||||
static void repair_noop(int iserr, const char *path, const char *msg,
|
||||
void *cb_data)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
void repair_worktrees(worktree_repair_fn fn, void *cb_data)
|
||||
{
|
||||
struct worktree **worktrees = get_worktrees();
|
||||
struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
|
||||
|
||||
if (!fn)
|
||||
fn = repair_noop;
|
||||
for (; *wt; wt++)
|
||||
repair_gitfile(*wt, fn, cb_data);
|
||||
free_worktrees(worktrees);
|
||||
}
|
||||
|
||||
static int is_main_worktree_path(const char *path)
|
||||
{
|
||||
struct strbuf target = STRBUF_INIT;
|
||||
struct strbuf maindir = STRBUF_INIT;
|
||||
int cmp;
|
||||
|
||||
strbuf_add_real_path(&target, path);
|
||||
strbuf_strip_suffix(&target, "/.git");
|
||||
strbuf_add_real_path(&maindir, get_git_common_dir());
|
||||
strbuf_strip_suffix(&maindir, "/.git");
|
||||
cmp = fspathcmp(maindir.buf, target.buf);
|
||||
|
||||
strbuf_release(&maindir);
|
||||
strbuf_release(&target);
|
||||
return !cmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Repair <repo>/worktrees/<id>/gitdir if missing, corrupt, or not pointing at
|
||||
* the worktree's path.
|
||||
*/
|
||||
void repair_worktree_at_path(const char *path,
|
||||
worktree_repair_fn fn, void *cb_data)
|
||||
{
|
||||
struct strbuf dotgit = STRBUF_INIT;
|
||||
struct strbuf realdotgit = STRBUF_INIT;
|
||||
struct strbuf gitdir = STRBUF_INIT;
|
||||
struct strbuf olddotgit = STRBUF_INIT;
|
||||
char *backlink = NULL;
|
||||
const char *repair = NULL;
|
||||
int err;
|
||||
|
||||
if (!fn)
|
||||
fn = repair_noop;
|
||||
|
||||
if (is_main_worktree_path(path))
|
||||
goto done;
|
||||
|
||||
strbuf_addf(&dotgit, "%s/.git", path);
|
||||
if (!strbuf_realpath(&realdotgit, dotgit.buf, 0)) {
|
||||
fn(1, path, _("not a valid path"), cb_data);
|
||||
goto done;
|
||||
}
|
||||
|
||||
backlink = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));
|
||||
if (err == READ_GITFILE_ERR_NOT_A_FILE) {
|
||||
fn(1, realdotgit.buf, _("unable to locate repository; .git is not a file"), cb_data);
|
||||
goto done;
|
||||
} else if (err) {
|
||||
fn(1, realdotgit.buf, _("unable to locate repository; .git file broken"), cb_data);
|
||||
goto done;
|
||||
}
|
||||
|
||||
strbuf_addf(&gitdir, "%s/gitdir", backlink);
|
||||
if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
|
||||
repair = _("gitdir unreadable");
|
||||
else {
|
||||
strbuf_rtrim(&olddotgit);
|
||||
if (fspathcmp(olddotgit.buf, realdotgit.buf))
|
||||
repair = _("gitdir incorrect");
|
||||
}
|
||||
|
||||
if (repair) {
|
||||
fn(0, gitdir.buf, repair, cb_data);
|
||||
write_file(gitdir.buf, "%s", realdotgit.buf);
|
||||
}
|
||||
done:
|
||||
free(backlink);
|
||||
strbuf_release(&olddotgit);
|
||||
strbuf_release(&gitdir);
|
||||
strbuf_release(&realdotgit);
|
||||
strbuf_release(&dotgit);
|
||||
}
|
||||
|
23
worktree.h
23
worktree.h
@ -89,6 +89,29 @@ int validate_worktree(const struct worktree *wt,
|
||||
void update_worktree_location(struct worktree *wt,
|
||||
const char *path_);
|
||||
|
||||
typedef void (* worktree_repair_fn)(int iserr, const char *path,
|
||||
const char *msg, void *cb_data);
|
||||
|
||||
/*
|
||||
* Visit each registered linked worktree and repair corruptions. For each
|
||||
* repair made or error encountered while attempting a repair, the callback
|
||||
* function, if non-NULL, is called with the path of the worktree and a
|
||||
* description of the repair or error, along with the callback user-data.
|
||||
*/
|
||||
void repair_worktrees(worktree_repair_fn, void *cb_data);
|
||||
|
||||
/*
|
||||
* Repair administrative files corresponding to the worktree at the given path.
|
||||
* The worktree's .git file pointing at the repository must be intact for the
|
||||
* repair to succeed. Useful for re-associating an orphaned worktree with the
|
||||
* repository if the worktree has been moved manually (without using "git
|
||||
* worktree move"). For each repair made or error encountered while attempting
|
||||
* a repair, the callback function, if non-NULL, is called with the path of the
|
||||
* worktree and a description of the repair or error, along with the callback
|
||||
* user-data.
|
||||
*/
|
||||
void repair_worktree_at_path(const char *, worktree_repair_fn, void *cb_data);
|
||||
|
||||
/*
|
||||
* Free up the memory for worktree(s)
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user