зеркало из https://github.com/microsoft/git.git
revamp git-clone.
This does two things. * A new flag --reference can be used to name a local repository that is to be used as an alternate. This is in response to an inquiry by James Cloos in the message on the list <m3r74ykue7.fsf@lugabout.cloos.reno.nv.us>. * A new flag --use-separate-remote stops contaminating local branch namespace by upstream branch names. The upstream branch heads are copied in .git/refs/remotes/ instead of .git/refs/heads/ and .git/remotes/origin file is set up to reflect this as well. It requires to have fetch/pull update to understand .git/refs/remotes by Eric Wong to further update the repository cloned this way. For the former change, git-fetch-pack is taught a new flag --all to fetch from all the remote heads. Nobody uses the git-clone-pack with this change, so we could deprecate the command, but removal of the command will be left to a separate round. Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Родитель
687b8be8bb
Коммит
dfeff66ed9
18
fetch-pack.c
18
fetch-pack.c
|
@ -7,8 +7,9 @@
|
||||||
static int keep_pack;
|
static int keep_pack;
|
||||||
static int quiet;
|
static int quiet;
|
||||||
static int verbose;
|
static int verbose;
|
||||||
|
static int fetch_all;
|
||||||
static const char fetch_pack_usage[] =
|
static const char fetch_pack_usage[] =
|
||||||
"git-fetch-pack [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory <refs>...";
|
"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory <refs>...";
|
||||||
static const char *exec = "git-upload-pack";
|
static const char *exec = "git-upload-pack";
|
||||||
|
|
||||||
#define COMPLETE (1U << 0)
|
#define COMPLETE (1U << 0)
|
||||||
|
@ -266,8 +267,9 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
|
||||||
for (prev = NULL, current = *refs; current; current = next) {
|
for (prev = NULL, current = *refs; current; current = next) {
|
||||||
next = current->next;
|
next = current->next;
|
||||||
if ((!memcmp(current->name, "refs/", 5) &&
|
if ((!memcmp(current->name, "refs/", 5) &&
|
||||||
check_ref_format(current->name + 5)) ||
|
check_ref_format(current->name + 5)) ||
|
||||||
!path_match(current->name, nr_match, match)) {
|
(!fetch_all &&
|
||||||
|
!path_match(current->name, nr_match, match))) {
|
||||||
if (prev == NULL)
|
if (prev == NULL)
|
||||||
*refs = next;
|
*refs = next;
|
||||||
else
|
else
|
||||||
|
@ -376,7 +378,11 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
|
||||||
goto all_done;
|
goto all_done;
|
||||||
}
|
}
|
||||||
if (find_common(fd, sha1, ref) < 0)
|
if (find_common(fd, sha1, ref) < 0)
|
||||||
fprintf(stderr, "warning: no common commits\n");
|
if (!keep_pack)
|
||||||
|
/* When cloning, it is not unusual to have
|
||||||
|
* no common commit.
|
||||||
|
*/
|
||||||
|
fprintf(stderr, "warning: no common commits\n");
|
||||||
|
|
||||||
if (keep_pack)
|
if (keep_pack)
|
||||||
status = receive_keep_pack(fd, "git-fetch-pack", quiet);
|
status = receive_keep_pack(fd, "git-fetch-pack", quiet);
|
||||||
|
@ -426,6 +432,10 @@ int main(int argc, char **argv)
|
||||||
use_thin_pack = 1;
|
use_thin_pack = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp("--all", arg)) {
|
||||||
|
fetch_all = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!strcmp("-v", arg)) {
|
if (!strcmp("-v", arg)) {
|
||||||
verbose = 1;
|
verbose = 1;
|
||||||
continue;
|
continue;
|
||||||
|
|
184
git-clone.sh
184
git-clone.sh
|
@ -9,7 +9,7 @@
|
||||||
unset CDPATH
|
unset CDPATH
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
echo >&2 "Usage: $0 [--bare] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]"
|
echo >&2 "Usage: $0 [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,22 +40,72 @@ Perhaps git-update-server-info needs to be run there?"
|
||||||
do
|
do
|
||||||
name=`expr "$refname" : 'refs/\(.*\)'` &&
|
name=`expr "$refname" : 'refs/\(.*\)'` &&
|
||||||
case "$name" in
|
case "$name" in
|
||||||
*^*) ;;
|
*^*) continue;;
|
||||||
*)
|
|
||||||
git-http-fetch -v -a -w "$name" "$name" "$1/" || exit 1
|
|
||||||
esac
|
esac
|
||||||
|
if test -n "$use_separate_remote" &&
|
||||||
|
branch_name=`expr "$name" : 'heads/\(.*\)'`
|
||||||
|
then
|
||||||
|
tname="remotes/$branch_name"
|
||||||
|
else
|
||||||
|
tname=$name
|
||||||
|
fi
|
||||||
|
git-http-fetch -v -a -w "$tname" "$name" "$1/" || exit 1
|
||||||
done <"$clone_tmp/refs"
|
done <"$clone_tmp/refs"
|
||||||
rm -fr "$clone_tmp"
|
rm -fr "$clone_tmp"
|
||||||
|
http_fetch "$1/HEAD" "$GIT_DIR/REMOTE_HEAD"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Read git-fetch-pack -k output and store the remote branches.
|
||||||
|
copy_refs='
|
||||||
|
use File::Path qw(mkpath);
|
||||||
|
use File::Basename qw(dirname);
|
||||||
|
my $git_dir = $ARGV[0];
|
||||||
|
my $use_separate_remote = $ARGV[1];
|
||||||
|
|
||||||
|
my $branch_top = ($use_separate_remote ? "remotes" : "heads");
|
||||||
|
my $tag_top = "tags";
|
||||||
|
|
||||||
|
sub store {
|
||||||
|
my ($sha1, $name, $top) = @_;
|
||||||
|
$name = "$git_dir/refs/$top/$name";
|
||||||
|
mkpath(dirname($name));
|
||||||
|
open O, ">", "$name";
|
||||||
|
print O "$sha1\n";
|
||||||
|
close O;
|
||||||
|
}
|
||||||
|
|
||||||
|
open FH, "<", "$git_dir/CLONE_HEAD";
|
||||||
|
while (<FH>) {
|
||||||
|
my ($sha1, $name) = /^([0-9a-f]{40})\s(.*)$/;
|
||||||
|
next if ($name =~ /\^\173/);
|
||||||
|
if ($name eq "HEAD") {
|
||||||
|
open O, ">", "$git_dir/REMOTE_HEAD";
|
||||||
|
print O "$sha1\n";
|
||||||
|
close O;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($name =~ s/^refs\/heads\///) {
|
||||||
|
store($sha1, $name, $branch_top);
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($name =~ s/^refs\/tags\///) {
|
||||||
|
store($sha1, $name, $tag_top);
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close FH;
|
||||||
|
'
|
||||||
|
|
||||||
quiet=
|
quiet=
|
||||||
use_local=no
|
use_local=no
|
||||||
local_shared=no
|
local_shared=no
|
||||||
no_checkout=
|
no_checkout=
|
||||||
upload_pack=
|
upload_pack=
|
||||||
bare=
|
bare=
|
||||||
origin=origin
|
reference=
|
||||||
|
origin=
|
||||||
origin_override=
|
origin_override=
|
||||||
|
use_separate_remote=
|
||||||
while
|
while
|
||||||
case "$#,$1" in
|
case "$#,$1" in
|
||||||
0,*) break ;;
|
0,*) break ;;
|
||||||
|
@ -68,7 +118,14 @@ while
|
||||||
*,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared)
|
*,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared)
|
||||||
local_shared=yes; use_local=yes ;;
|
local_shared=yes; use_local=yes ;;
|
||||||
*,-q|*,--quiet) quiet=-q ;;
|
*,-q|*,--quiet) quiet=-q ;;
|
||||||
|
*,--use-separate-remote)
|
||||||
|
use_separate_remote=t ;;
|
||||||
1,-o) usage;;
|
1,-o) usage;;
|
||||||
|
1,--reference) usage ;;
|
||||||
|
*,--reference)
|
||||||
|
shift; reference="$1" ;;
|
||||||
|
*,--reference=*)
|
||||||
|
reference=`expr "$1" : '--reference=\(.*\)'` ;;
|
||||||
*,-o)
|
*,-o)
|
||||||
git-check-ref-format "$2" || {
|
git-check-ref-format "$2" || {
|
||||||
echo >&2 "'$2' is not suitable for a branch name"
|
echo >&2 "'$2' is not suitable for a branch name"
|
||||||
|
@ -100,9 +157,24 @@ then
|
||||||
echo >&2 '--bare and -o $origin options are incompatible.'
|
echo >&2 '--bare and -o $origin options are incompatible.'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
if test t = "$use_separate_remote"
|
||||||
|
then
|
||||||
|
echo >&2 '--bare and --use-separate-remote options are incompatible.'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
no_checkout=yes
|
no_checkout=yes
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test -z "$origin_override$origin"
|
||||||
|
then
|
||||||
|
if test -n "$use_separate_remote"
|
||||||
|
then
|
||||||
|
origin=remotes/master
|
||||||
|
else
|
||||||
|
origin=heads/origin
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Turn the source into an absolute path if
|
# Turn the source into an absolute path if
|
||||||
# it is local
|
# it is local
|
||||||
repo="$1"
|
repo="$1"
|
||||||
|
@ -130,6 +202,28 @@ yes)
|
||||||
GIT_DIR="$D/.git" ;;
|
GIT_DIR="$D/.git" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
if test -n "$reference"
|
||||||
|
then
|
||||||
|
if test -d "$reference"
|
||||||
|
then
|
||||||
|
if test -d "$reference/.git/objects"
|
||||||
|
then
|
||||||
|
reference="$reference/.git"
|
||||||
|
fi
|
||||||
|
reference=$(cd "$reference" && pwd)
|
||||||
|
echo "$reference/objects" >"$GIT_DIR/objects/info/alternates"
|
||||||
|
(cd "$reference" && tar cf - refs) |
|
||||||
|
(cd "$GIT_DIR/refs" &&
|
||||||
|
mkdir reference-tmp &&
|
||||||
|
cd reference-tmp &&
|
||||||
|
tar xf -)
|
||||||
|
else
|
||||||
|
echo >&2 "$reference: not a local directory." && usage
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$GIT_DIR/CLONE_HEAD"
|
||||||
|
|
||||||
# We do local magic only when the user tells us to.
|
# We do local magic only when the user tells us to.
|
||||||
case "$local,$use_local" in
|
case "$local,$use_local" in
|
||||||
yes,yes)
|
yes,yes)
|
||||||
|
@ -165,24 +259,14 @@ yes,yes)
|
||||||
} >"$GIT_DIR/objects/info/alternates"
|
} >"$GIT_DIR/objects/info/alternates"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD"
|
||||||
# Make a duplicate of refs and HEAD pointer
|
|
||||||
HEAD=
|
|
||||||
if test -f "$repo/HEAD"
|
|
||||||
then
|
|
||||||
HEAD=HEAD
|
|
||||||
fi
|
|
||||||
(cd "$repo" && tar cf - refs $HEAD) |
|
|
||||||
(cd "$GIT_DIR" && tar xf -) || exit 1
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
case "$repo" in
|
case "$repo" in
|
||||||
rsync://*)
|
rsync://*)
|
||||||
rsync $quiet -av --ignore-existing \
|
rsync $quiet -av --ignore-existing \
|
||||||
--exclude info "$repo/objects/" "$GIT_DIR/objects/" &&
|
--exclude info "$repo/objects/" "$GIT_DIR/objects/" ||
|
||||||
rsync $quiet -av --ignore-existing \
|
exit
|
||||||
--exclude info "$repo/refs/" "$GIT_DIR/refs/" || exit
|
|
||||||
|
|
||||||
# Look at objects/info/alternates for rsync -- http will
|
# Look at objects/info/alternates for rsync -- http will
|
||||||
# support it natively and git native ones will do it on the
|
# support it natively and git native ones will do it on the
|
||||||
# remote end. Not having that file is not a crime.
|
# remote end. Not having that file is not a crime.
|
||||||
|
@ -205,6 +289,7 @@ yes,yes)
|
||||||
done
|
done
|
||||||
rm -f "$GIT_DIR/TMP_ALT"
|
rm -f "$GIT_DIR/TMP_ALT"
|
||||||
fi
|
fi
|
||||||
|
git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD"
|
||||||
;;
|
;;
|
||||||
http://*)
|
http://*)
|
||||||
if test -z "@@NO_CURL@@"
|
if test -z "@@NO_CURL@@"
|
||||||
|
@ -217,37 +302,71 @@ yes,yes)
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
cd "$D" && case "$upload_pack" in
|
cd "$D" && case "$upload_pack" in
|
||||||
'') git-clone-pack $quiet "$repo" ;;
|
'') git-fetch-pack --all -k $quiet "$repo" ;;
|
||||||
*) git-clone-pack $quiet "$upload_pack" "$repo" ;;
|
*) git-fetch-pack --all -k $quiet "$upload_pack" "$repo" ;;
|
||||||
esac || {
|
esac >"$GIT_DIR/CLONE_HEAD" || {
|
||||||
echo >&2 "clone-pack from '$repo' failed."
|
echo >&2 "fetch-pack from '$repo' failed."
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
test -d "$GIT_DIR/refs/reference-tmp" && rm -fr "$GIT_DIR/refs/reference-tmp"
|
||||||
|
|
||||||
|
if test -f "$GIT_DIR/CLONE_HEAD"
|
||||||
|
then
|
||||||
|
# Figure out where the remote HEAD points at.
|
||||||
|
perl -e "$copy_refs" "$GIT_DIR" "$use_separate_remote"
|
||||||
|
fi
|
||||||
|
|
||||||
cd "$D" || exit
|
cd "$D" || exit
|
||||||
|
|
||||||
if test -f "$GIT_DIR/HEAD" && test -z "$bare"
|
if test -z "$bare" && test -f "$GIT_DIR/REMOTE_HEAD"
|
||||||
then
|
then
|
||||||
head_points_at=`git-symbolic-ref HEAD`
|
head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"`
|
||||||
|
# Figure out which remote branch HEAD points at.
|
||||||
|
case "$use_separate_remote" in
|
||||||
|
'') remote_top=refs/heads ;;
|
||||||
|
*) remote_top=refs/remotes ;;
|
||||||
|
esac
|
||||||
|
head_points_at=$(
|
||||||
|
(
|
||||||
|
echo "master"
|
||||||
|
cd "$GIT_DIR/$remote_top" &&
|
||||||
|
find . -type f -print | sed -e 's/^\.\///'
|
||||||
|
) | (
|
||||||
|
done=f
|
||||||
|
while read name
|
||||||
|
do
|
||||||
|
test t = $done && continue
|
||||||
|
branch_tip=`cat "$GIT_DIR/$remote_top/$name"`
|
||||||
|
if test "$head_sha1" = "$branch_tip"
|
||||||
|
then
|
||||||
|
echo "$name"
|
||||||
|
done=t
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
)
|
||||||
|
)
|
||||||
case "$head_points_at" in
|
case "$head_points_at" in
|
||||||
refs/heads/*)
|
?*)
|
||||||
head_points_at=`expr "$head_points_at" : 'refs/heads/\(.*\)'`
|
|
||||||
mkdir -p "$GIT_DIR/remotes" &&
|
mkdir -p "$GIT_DIR/remotes" &&
|
||||||
echo >"$GIT_DIR/remotes/origin" \
|
echo >"$GIT_DIR/remotes/origin" \
|
||||||
"URL: $repo
|
"URL: $repo
|
||||||
Pull: $head_points_at:$origin" &&
|
Pull: refs/heads/$head_points_at:refs/$origin" &&
|
||||||
git-update-ref "refs/heads/$origin" $(git-rev-parse HEAD) &&
|
case "$use_separate_remote" in
|
||||||
(cd "$GIT_DIR" && find "refs/heads" -type f -print) |
|
t) git-update-ref HEAD "$head_sha1" ;;
|
||||||
|
*) git-update-ref "refs/$origin" $(git-rev-parse HEAD)
|
||||||
|
esac &&
|
||||||
|
(cd "$GIT_DIR" && find "$remote_top" -type f -print) |
|
||||||
while read ref
|
while read ref
|
||||||
do
|
do
|
||||||
head=`expr "$ref" : 'refs/heads/\(.*\)'` &&
|
head=`expr "$ref" : 'refs/\(.*\)'` &&
|
||||||
test "$head_points_at" = "$head" ||
|
name=`expr "$ref" : 'refs/[^\/]*/\(.*\)'` &&
|
||||||
|
test "$head_points_at" = "$name" ||
|
||||||
test "$origin" = "$head" ||
|
test "$origin" = "$head" ||
|
||||||
echo "Pull: ${head}:${head}"
|
echo "Pull: refs/heads/${name}:$remote_top/${name}"
|
||||||
done >>"$GIT_DIR/remotes/origin"
|
done >>"$GIT_DIR/remotes/origin"
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
@ -256,6 +375,7 @@ Pull: $head_points_at:$origin" &&
|
||||||
git-read-tree -m -u -v HEAD HEAD
|
git-read-tree -m -u -v HEAD HEAD
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD"
|
||||||
|
|
||||||
trap - exit
|
trap - exit
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче