mirror of
https://github.com/git/git
synced 2024-10-30 14:03:28 +00:00
ea09ea22d6
Recently I found that doing a sequence like the following: git-new-workdir a b ... git-new-workdir a b by accident will cause a (and now also b) to have an infinite cycle in its refs directory. This is caused by git-new-workdir trying to create the "refs" symlink over again, only during the second time it is being created within a's refs directory and is now also pointing back at a's refs. This causes confusion in git as suddenly branches are named things like "refs/refs/refs/refs/refs/refs/refs/heads/foo" instead of the more commonly accepted "refs/heads/foo". Plenty of commands start to see ambiguous ref names and others just take ages to compute. git-clone has the same safety check, so git-new-workdir should behave just like it. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
82 lines
1.8 KiB
Bash
Executable file
82 lines
1.8 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
usage () {
|
|
echo "usage:" $@
|
|
exit 127
|
|
}
|
|
|
|
die () {
|
|
echo $@
|
|
exit 128
|
|
}
|
|
|
|
if test $# -lt 2 || test $# -gt 3
|
|
then
|
|
usage "$0 <repository> <new_workdir> [<branch>]"
|
|
fi
|
|
|
|
orig_git=$1
|
|
new_workdir=$2
|
|
branch=$3
|
|
|
|
# want to make sure that what is pointed to has a .git directory ...
|
|
git_dir=$(cd "$orig_git" 2>/dev/null &&
|
|
git rev-parse --git-dir 2>/dev/null) ||
|
|
die "\"$orig_git\" is not a git repository!"
|
|
|
|
case "$git_dir" in
|
|
.git)
|
|
git_dir="$orig_git/.git"
|
|
;;
|
|
.)
|
|
git_dir=$orig_git
|
|
;;
|
|
esac
|
|
|
|
# don't link to a configured bare repository
|
|
isbare=$(git --git-dir="$git_dir" config --bool --get core.bare)
|
|
if test ztrue = z$isbare
|
|
then
|
|
die "\"$git_dir\" has core.bare set to true," \
|
|
" remove from \"$git_dir/config\" to use $0"
|
|
fi
|
|
|
|
# don't link to a workdir
|
|
if test -L "$git_dir/config"
|
|
then
|
|
die "\"$orig_git\" is a working directory only, please specify" \
|
|
"a complete repository."
|
|
fi
|
|
|
|
# don't recreate a workdir over an existing repository
|
|
if test -e "$new_workdir"
|
|
then
|
|
die "destination directory '$new_workdir' already exists."
|
|
fi
|
|
|
|
# make sure the the links use full paths
|
|
git_dir=$(cd "$git_dir"; pwd)
|
|
|
|
# create the workdir
|
|
mkdir -p "$new_workdir/.git" || die "unable to create \"$new_workdir\"!"
|
|
|
|
# create the links to the original repo. explictly exclude index, HEAD and
|
|
# logs/HEAD from the list since they are purely related to the current working
|
|
# directory, and should not be shared.
|
|
for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache
|
|
do
|
|
case $x in
|
|
*/*)
|
|
mkdir -p "$(dirname "$new_workdir/.git/$x")"
|
|
;;
|
|
esac
|
|
ln -s "$git_dir/$x" "$new_workdir/.git/$x"
|
|
done
|
|
|
|
# now setup the workdir
|
|
cd "$new_workdir"
|
|
# copy the HEAD from the original repository as a default branch
|
|
cp "$git_dir/HEAD" .git/HEAD
|
|
# checkout the branch (either the same as HEAD from the original repository, or
|
|
# the one that was asked for)
|
|
git checkout -f $branch
|