git-new-workdir: don't fail if the target directory is empty

Allow new workdirs to be created in an empty directory (similar to "git clone"). Provide more error checking and clean up on failure. Signed-off-by: Paul Smith <paul@mad-scientist.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Paul Smith committed Nov 26, 2014 at 15:38 UTC e32afab7b0376a7b07601a87cd5c6841ff2a811a
1 file changed +38 -15
contrib/workdir/git-new-workdir
+38 -15
@@ -10,6 +10,10 @@ die () {
10 exit 128
11 }
12
13 +failed () {
14 + die "unable to create new workdir '$new_workdir'!"
15 +}
16 +
17 if test $# -lt 2 || test $# -gt 3
18 then
19 usage "$0 <repository> <new_workdir> [<branch>]"
@@ -35,7 +39,7 @@ esac
39
40 # don't link to a configured bare repository
41 isbare=$(git --git-dir="$git_dir" config --bool --get core.bare)
38 -if test ztrue = z$isbare
42 +if test ztrue = "z$isbare"
43 then
44 die "\"$git_dir\" has core.bare set to true," \
45 " remove from \"$git_dir/config\" to use $0"
@@ -48,35 +52,54 @@ then
52 "a complete repository."
53 fi
54
51 -# don't recreate a workdir over an existing repository
52 -if test -e "$new_workdir"
55 +# make sure the links in the workdir have full paths to the original repo
56 +git_dir=$(cd "$git_dir" && pwd) || exit 1
57 +
58 +# don't recreate a workdir over an existing directory, unless it's empty
59 +if test -d "$new_workdir"
60 then
54 - die "destination directory '$new_workdir' already exists."
61 + if test $(ls -a1 "$new_workdir/." | wc -l) -ne 2
62 + then
63 + die "destination directory '$new_workdir' is not empty."
64 + fi
65 + cleandir="$new_workdir/.git"
66 +else
67 + cleandir="$new_workdir"
68 fi
69
57 -# make sure the links use full paths
58 -git_dir=$(cd "$git_dir"; pwd)
70 +mkdir -p "$new_workdir/.git" || failed
71 +cleandir=$(cd "$cleandir" && pwd) || failed
72
60 -# create the workdir
61 -mkdir -p "$new_workdir/.git" || die "unable to create \"$new_workdir\"!"
73 +cleanup () {
74 + rm -rf "$cleandir"
75 +}
76 +siglist="0 1 2 15"
77 +trap cleanup $siglist
78
79 # create the links to the original repo. explicitly exclude index, HEAD and
80 # logs/HEAD from the list since they are purely related to the current working
81 # directory, and should not be shared.
82 for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache svn
83 do
84 + # create a containing directory if needed
85 case $x in
86 */*)
70 - mkdir -p "$(dirname "$new_workdir/.git/$x")"
87 + mkdir -p "$new_workdir/.git/${x%/*}"
88 ;;
89 esac
73 - ln -s "$git_dir/$x" "$new_workdir/.git/$x"
90 +
91 + ln -s "$git_dir/$x" "$new_workdir/.git/$x" || failed
92 done
93
76 -# now setup the workdir
77 -cd "$new_workdir"
94 +# commands below this are run in the context of the new workdir
95 +cd "$new_workdir" || failed
96 +
97 # copy the HEAD from the original repository as a default branch
79 -cp "$git_dir/HEAD" .git/HEAD
80 -# checkout the branch (either the same as HEAD from the original repository, or
81 -# the one that was asked for)
98 +cp "$git_dir/HEAD" .git/HEAD || failed
99 +
100 +# the workdir is set up. if the checkout fails, the user can fix it.
101 +trap - $siglist
102 +
103 +# checkout the branch (either the same as HEAD from the original repository,
104 +# or the one that was asked for)
105 git checkout -f $branch