Skip to content

Commit 3b8925c

Browse files
pcloudsgitster
authored andcommitted
checkout: clean up half-prepared directories in --to mode
Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5883034 commit 3b8925c

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

builtin/checkout.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "resolve-undo.h"
2121
#include "submodule.h"
2222
#include "argv-array.h"
23+
#include "sigchain.h"
2324

2425
static const char * const checkout_usage[] = {
2526
N_("git checkout [options] <branch>"),
@@ -823,6 +824,35 @@ static int switch_branches(const struct checkout_opts *opts,
823824
return ret || writeout_error;
824825
}
825826

827+
static char *junk_work_tree;
828+
static char *junk_git_dir;
829+
static int is_junk;
830+
static pid_t junk_pid;
831+
832+
static void remove_junk(void)
833+
{
834+
struct strbuf sb = STRBUF_INIT;
835+
if (!is_junk || getpid() != junk_pid)
836+
return;
837+
if (junk_git_dir) {
838+
strbuf_addstr(&sb, junk_git_dir);
839+
remove_dir_recursively(&sb, 0);
840+
strbuf_reset(&sb);
841+
}
842+
if (junk_work_tree) {
843+
strbuf_addstr(&sb, junk_work_tree);
844+
remove_dir_recursively(&sb, 0);
845+
}
846+
strbuf_release(&sb);
847+
}
848+
849+
static void remove_junk_on_signal(int signo)
850+
{
851+
remove_junk();
852+
sigchain_pop(signo);
853+
raise(signo);
854+
}
855+
826856
static int prepare_linked_checkout(const struct checkout_opts *opts,
827857
struct branch_info *new)
828858
{
@@ -859,8 +889,15 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,
859889
strbuf_addf(&sb_repo, "%d", counter);
860890
}
861891
name = strrchr(sb_repo.buf, '/') + 1;
892+
893+
junk_pid = getpid();
894+
atexit(remove_junk);
895+
sigchain_push_common(remove_junk_on_signal);
896+
862897
if (mkdir(sb_repo.buf, 0777))
863898
die_errno(_("could not create directory of '%s'"), sb_repo.buf);
899+
junk_git_dir = xstrdup(sb_repo.buf);
900+
is_junk = 1;
864901

865902
/*
866903
* lock the incomplete repo so prune won't delete it, unlock
@@ -873,6 +910,7 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,
873910
if (safe_create_leading_directories_const(sb_git.buf))
874911
die_errno(_("could not create leading directories of '%s'"),
875912
sb_git.buf);
913+
junk_work_tree = xstrdup(path);
876914

877915
strbuf_reset(&sb);
878916
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
@@ -902,9 +940,19 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,
902940
cp.git_cmd = 1;
903941
cp.argv = opts->saved_argv;
904942
ret = run_command(&cp);
943+
if (!ret) {
944+
is_junk = 0;
945+
free(junk_work_tree);
946+
free(junk_git_dir);
947+
junk_work_tree = NULL;
948+
junk_git_dir = NULL;
949+
}
905950
strbuf_reset(&sb);
906951
strbuf_addf(&sb, "%s/locked", sb_repo.buf);
907952
unlink_or_warn(sb.buf);
953+
strbuf_release(&sb);
954+
strbuf_release(&sb_repo);
955+
strbuf_release(&sb_git);
908956
return ret;
909957
}
910958

t/t2025-checkout-to.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ test_expect_success 'checkout --to an existing worktree' '
1717
test_must_fail git checkout --detach --to existing master
1818
'
1919

20+
test_expect_success 'checkout --to refuses to checkout locked branch' '
21+
test_must_fail git checkout --to zere master &&
22+
! test -d zere &&
23+
! test -d .git/worktrees/zere
24+
'
25+
2026
test_expect_success 'checkout --to a new worktree' '
2127
git rev-parse HEAD >expect &&
2228
git checkout --detach --to here master &&

0 commit comments

Comments
 (0)