-
Notifications
You must be signed in to change notification settings - Fork 0
/
cg-clone
executable file
·196 lines (174 loc) · 6.09 KB
/
cg-clone
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#!/usr/bin/env bash
#
# Clone a remote repository
# Copyright (c) Petr Baudis, 2005
#
# This clones a remote GIT repository and checks it out locally.
#
# Takes a parameter specifying the location of the source repository and an
# optional second parameter specifying the destination. If the second
# parameter is omitted, the basename of the source repository is used as the
# destination.
#
# For detailed description of the location of the source repository format
# (available protocols, specifying different remote branch, etc) please see
# the `cg-branch-add` documentation.
#
# OPTIONS
# -------
# -b:: Create a bare repository - do not check out working copy
# Create only the bare repository, without a working copy attached;
# this is useful e.g. for public repository mirrors. `cg-clone`
# is to `cg-init` as `cg-clone -b` is to `cg-admin-setuprepo`.
# (Still, if you are setting up a public or a central repository
# other people will push into, it might be more practical to just
# `cg-admin-setuprepo` it and then populate it with `cg-push`
# from the other side.)
#
# -l:: "Borrow" the object database when cloning locally
# Instead of hardlinking all the objects, set up an "alternate"
# record pointing at the source object database; this will cause
# any objects not found locally to be looked up remotely, which
# effectively eliminates the need to copy/hardlink the objects
# around. This is suitable for very fast cloning of arbitrarily
# big repositories, but your repository will become largely useless
# if the source repository disappears or gets damaged (note that
# it is generally BAD IDEA to prune the original repository if any
# repository is borrowing objects from it). The choice is yours.
#
# --reference PATH:: "Borrow" the object database from a third-party source
# This does the same thing as '-l' but instead of borrowing the
# objects from the source repository, it borrows them from yet
# another local repository. E.g. if you have Linus' kernel repository
# cloned locally and now want to clone akpm's repository, you can
# do something like
#
# cg-clone --reference /path/to/linus/repo git://kernel.org/akpm/repo
#
# and it will download and keep only the objects that are really
# missing. Same considerations and warnings on the third-party source
# as in the case of '-l' apply. Also, you can reference only local
# repositories.
#
# -s:: Clone into the current directory
# Clone in the current directory instead of creating a new one.
# Specifying both -s and a destination directory makes no sense.
#
# NOTES
# -----
# If the clone has been interrupted for any reason, do not panic, calmly
# cd to the destination directory and run `cg-fetch`, which will in this case
# restart the initial clone. Chances are that you will not actually download
# any duplicate data. (At the time of writing this, the chances aren't for
# the native git protocol and ssh, but this may change in the future).
#
# EXAMPLE USAGE
# -------------
# If you want to clone the Cogito repository, you can say:
#
# $ cg-clone http://www.kernel.org/pub/scm/cogito/cogito.git
#
# and it will be cloned to the 'cogito' subdirectory of the current directory.
#
# To clone the 'next' branch of the Git repository, do e.g.:
#
# $ cg-clone git://git.kernel.org/pub/scm/git/git.git#next
# Testsuite: Checked as part of t-9105-fetch-local but tests for some features
# are missing.
USAGE="cg-clone [-l] [-b] [-s] LOCATION [DESTDIR]"
_git_repo_unneeded=1
. "${COGITO_LIB}"cg-Xlib || exit 1
same_dir=
repoonly=
alternate=
reference=()
while optparse; do
if optparse -l; then
alternate=1
elif optparse -b; then
repoonly=1
elif optparse --reference=; then
reference[${#reference[@]}]="$OPTARG"
elif optparse -s; then
same_dir=1
else
optfail
fi
done
location="${ARGS[0]}"
[ -n "$location" ] || usage
location="${location%/}"
destdir="${ARGS[1]}"
if [ "$destdir" ]; then
[ ! "$same_dir" ] || die "specifying both -s and DESTDIR makes no sense"
dir="$destdir"
else
dir="${location%#*}"; dir="${dir%/.git}"; dir="${dir##*/}"; dir="${dir%.git}"
[ "$repoonly" ] && dir="$dir.git"
fi
if ! echo "$location" | grep -q ":" ; then
location=$(echo "$location" | sed -e "s#^[^/]#$(pwd)\/&#")
else
[ ! "$alternate" ] || die "specifying -l for non-local clone makes no sense"
location="$location"
fi
if [ ! "$same_dir" ]; then
[ -e "$dir" ] && die "$dir/ already exists"
if [ "$repoonly" ]; then
cg-admin-setuprepo "$dir" || exit $?
else
mkdir -p "$dir" || exit $?
fi
cd "$dir" || exit $?
else
dir=.
fi
if [ "$repoonly" ]; then
_git=.
export GIT_DIR=.
_git_no_wc=1
fi
cleanup ()
{
if [ -s "$_git/info/cg-fetch-earlydie" ] && [ ! "$same_dir" ]; then
cd ..
rm -rf "$dir"
fi
}
cleanup_trap "cleanup"
if [ ! "$repoonly" ]; then
cg-init -I || die "init failed"
fi
echo $$ >"$_git/info/cg-fetch-earlydie"
repoloc="$location"
[ ! -d "$repoloc/.git/objects" ] || repoloc="$repoloc/.git"
[ "$alternate" ] && echo "$repoloc/objects" >> "$_git/objects/info/alternates"
for ref in "${reference[@]}"; do
relpath=
[ "${ref#/}" != "$ref" ] || relpath=1
# Relative path; reference is relative to the object repository; we
# need to add one .. for objects, another .. for .git/, another .. for
# projdir unless ! same_Dir
if [ ! "$same_dir" ] && [ "$relpath" ]; then
# Relative path, account for project subdir
ref="../$ref"
fi
[ -d "$ref" ] || die "referenced repository $ref not found"
[ ! -d "$ref/.git/objects" ] || ref="$ref/.git"
[ -d "$ref/objects" ] || die "reference $ref not a git repository"
[ ! "$relpath" ] || ref="../../$ref"
echo "$ref/objects" >>"$_git/objects/info/alternates"
done
cg-branch-add origin "$location"
mkdir -p "$_git/info"
[ "$repoonly" ] && echo $$ >"$_git/info/cg-fetch-initial-wcless"
echo $$ >"$_git/info/cg-fetch-initial"
cat >___ <<__EOT__
This is a clone-in-progress GIT working tree containing a GIT repository
in the .git subdirectory. If you see this file and noone is fetching or
cloning in this repository, the clone has been interrupted; you can restart
it by issuing this command (it's enough as-is):
cg-fetch
__EOT__
cg-fetch origin || { cleanup; exit 1; }
echo "Cloned to $dir/ (origin $location available as branch \"origin\")"