checkout: clean up half-prepared directories in --to mode
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
Nov 30, 2014 at 15:24 UTC
3b8925c78bdbea49c846e350e66c13923441fff8
2 files changed
+54
builtin/checkout.c
+48
@@ -20,6 +20,7 @@
20
#include "resolve-undo.h"
21
#include "submodule.h"
22
#include "argv-array.h"
23
+#include "sigchain.h"
24
25
static const char * const checkout_usage[] = {
26
N_("git checkout [options] <branch>"),
@@ -823,6 +824,35 @@ static int switch_branches(const struct checkout_opts *opts,
824
return ret || writeout_error;
825
}
826
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
+
856
static int prepare_linked_checkout(const struct checkout_opts *opts,
857
struct branch_info *new)
858
{
@@ -859,8 +889,15 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,
889
strbuf_addf(&sb_repo, "%d", counter);
890
}
891
name = strrchr(sb_repo.buf, '/') + 1;
892
+
893
+ junk_pid = getpid();
894
+ atexit(remove_junk);
895
+ sigchain_push_common(remove_junk_on_signal);
896
+
897
if (mkdir(sb_repo.buf, 0777))
898
die_errno(_("could not create directory of '%s'"), sb_repo.buf);
899
+ junk_git_dir = xstrdup(sb_repo.buf);
900
+ is_junk = 1;
901
902
/*
903
* 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,
910
if (safe_create_leading_directories_const(sb_git.buf))
911
die_errno(_("could not create leading directories of '%s'"),
912
sb_git.buf);
913
+ junk_work_tree = xstrdup(path);
914
915
strbuf_reset(&sb);
916
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
@@ -902,9 +940,19 @@ static int prepare_linked_checkout(const struct checkout_opts *opts,
940
cp.git_cmd = 1;
941
cp.argv = opts->saved_argv;
942
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
+ }
950
strbuf_reset(&sb);
951
strbuf_addf(&sb, "%s/locked", sb_repo.buf);
952
unlink_or_warn(sb.buf);
953
+ strbuf_release(&sb);
954
+ strbuf_release(&sb_repo);
955
+ strbuf_release(&sb_git);
956
return ret;
957
}
958
t/t2025-checkout-to.sh
+6
@@ -17,6 +17,12 @@ test_expect_success 'checkout --to an existing worktree' '
17
test_must_fail git checkout --detach --to existing master
18
'
19
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
+
26
test_expect_success 'checkout --to a new worktree' '
27
git rev-parse HEAD >expect &&
28
git checkout --detach --to here master &&