3 # Fetch changes from a remote branch to the local repository
4 # Copyright (c) Petr Baudis, 2005.
6 # Takes the branch name as an argument. If no branch name was specified,
7 # the default remote branch for the current branch (as selected by
8 # `cg-switch -o`, that is the 'branch."currenthead".merge' option) is used.
9 # If no such option exists, 'origin' is used.
11 # This will fetch the latest changes from a remote repository to the
12 # corresponding branch in your local repository. Note that this operation
13 # does not involve merging those changes to your own branch - that is being
14 # done by the `cg-merge` command. `cg-update` exists to conveniently bundle
15 # the act of fetching and merging to your working branch together.
17 # Before the first fetch, you have to tell Cogito about the remote branch.
18 # This should be done by the `cg-branch-add` command. See its documentation
19 # for the list of supported fetching protocols and other details. Note that
20 # one exception to this is the 'origin' branch, which was set to the location
21 # of the source repository if you created yours using the `cg-clone` command.
23 # Note that in the GIT newspeak, the operation being performed by cg-update
24 # is now called 'pull', even though in the past and in many other version
25 # control systems systems, 'pull' is the name for the operation performed by
26 # `cg-fetch`. Please do not let this confuse you. (Cogito won't call this
27 # 'update' operation 'pull', since about everyone but GIT and BK users uses
28 # it in the 'fetch' meaning.)
32 # -f:: Force the complete fetch even if the heads are the same.
33 # Force the complete fetch even if the heads are the same.
35 # -v:: Enable verbosity
36 # Display more verbose output - most notably list all the files
37 # touched by the fetched changes. Use twice to get even more verbosity,
38 # that is raw progress information instead of the progress bar.
43 # The command to invoke when we want to call the rsync tool (only used
44 # when fetching over the rsync protocol). Defaults to 'rsync'.
47 # Additional flags to be passed to the rsync tool when fetching over
50 # Testsuite: Largely covered (t91xx testsuite family, incomplete coverage)
53 USAGE
="cg-fetch [-f] [-v] [BRANCH_NAME]"
56 .
"${COGITO_LIB}"cg-Xlib ||
exit 1
61 [ $verbose -ge 2 ] && exec cat
63 exec "${COGITO_LIB}"cg-Xfetchprogress
"$_git_objects"
69 show_changes_summary
()
73 if [ ! "$orig_head" ]; then
74 echo "New branch: $new_head"
76 elif [ "$orig_head" != "$new_head" ]; then
77 echo "Tree change: $orig_head..$new_head"
78 [ $verbose -ge 1 ] && git-diff-tree
--abbrev -r "$(cg-object-id -t "$orig_head")" "$(cg-object-id -t "$new_head")"
87 git-update-ref
"refs/heads/master" "$(get_ref "refs
/heads
/origin
")" ||
88 die
"initial checkout failed"
89 if [ -s "$_git/info/cg-fetch-initial-wcless" ]; then
90 rm "$_git/info/cg-fetch-initial-wcless"
93 git-checkout-index
-a &&
94 git-update-index
--refresh ||
95 die
"initial checkout failed"
97 rm "$_git/info/cg-fetch-initial"
103 [ "$1" = "-b" ] && shift
106 if [ "$1" = "-i" ]; then # ignore-errors
112 if [ "$1" = "-s" ]; then # subsequent
113 # We already saw the MOTD, thank you very much.
114 filter
="grep -v ^MOTD:"
119 if [ "$1" = "-d" ]; then # directory
120 appenduri
="/." # CowboyNeal
124 echo "${RSYNC:-rsync}" $RSYNC_FLAGS -v --partial -Lr \
125 "$1$appenduri" "$2$appenduri" $redir
126 eval '"${RSYNC:-rsync}"' $RSYNC_FLAGS -v --partial -Lr \
127 '"$1$appenduri"' '"$2$appenduri"' $redir |
$filter
128 return ${PIPESTATUS[0]}
133 if [ $verbose -ge 2 ]; then
134 # We must not pipe to prevent buffered I/O
135 get_rsync
-s -d "$2/objects" "$_git_objects"
137 get_rsync
-s -d "$2/objects" "$_git_objects" | fetch_progress
141 if [ "$3" ] && [ "$ret" -eq "0" ]; then
142 if [ "$orig_head" ]; then
143 git-rev-list
--objects $new_head ^
$orig_head |
144 while read obj
type; do
145 git-cat-file
-t $obj >/dev
/null ||
exit $?
147 die
"rsync fetch incomplete, some objects missing"
149 git-update-ref
"refs/$3" "$1"
157 if [ x
"$1" = x
"--stdin" ]; then
159 git-update-ref
"refs/$w" "$c"
162 fetch_rsync_verify
"$1" "$2" "$3"
168 [ "$1" = "-b" ] && shift
169 [ "$1" = "-i" ] && shift
170 [ "$1" = "-s" ] && shift
171 [ "$1" = "-d" ] && die
"INTERNAL ERROR: HTTP recursive not implemented"
177 [ "$GIT_SSL_NO_VERIFY" ] && curl_extra_args
="-k"
178 curl
-nsfL $curl_extra_args -o "$dest" "$src"
184 [ "$3" ] && whead
="-w $3"
185 (git-http-fetch
-a -v $whead $recovery "$1" "$2/" 2>&1 /dev
/null
) | fetch_progress
186 return ${PIPESTATUS[0]}
194 if [ "$1" = "-b" ]; then
195 # Dereference symlinks
196 cp_flags_l
="$cp_flags_l -L"
199 cp_flags_l
="$cp_flags_l -pRP"
202 [ "$1" = "-i" ] && shift
203 [ "$1" = "-s" ] && shift
204 [ "$1" = "-d" ] && die
"INTERNAL ERROR: local-fetch recursive not implemented"
209 cp $cp_flags_l "$src" "$dest"
215 [ "$3" ] && whead
="-w $3"
216 (git-local-fetch
-a -l -v $whead $recovery "$1" "$2" 2>&1 /dev
/null
) | fetch_progress
217 return ${PIPESTATUS[0]}
223 echo -n "Fetching tags... "
225 # FIXME: Warn about conflicting tag names?
227 if [ "$get" = "get_rsync" ]; then
229 warn
"WHAT I'M DOING NOW IS RACY AND BROKEN IF YOU USE PACKED REFS!"
230 warn
"Please switch from rsync to something else."
231 [ -d "$_git/refs/tags" ] || mkdir
-p "$_git/refs/tags"
232 if ! $get -i -s -d "$uri/refs/tags" "$_git/refs/tags"; then
233 echo "unable to get tags list (non-fatal)" >&2
240 git-ls-remote
--tags "$uri" |
241 # SHA1 refs/tags/v0.99.8^{} --> SHA1 tags/v0.99.8
242 # where SHA1 is the object v0.99.8 tag points at.
243 sed -n -e 's:\([^ ]\) refs/\(tags/.*\)^{}$:\1 \2:p' \
244 -e 's:\([^ ]\) refs/\(tags/.*\)$:\1 \2:p' | \
245 while read sha1 tagname
; do
246 # Do we have the tag itself?
247 exists_ref
"refs/$tagname" && continue
248 # Do we have the object pointed at by the tag?
249 git-cat-file
-t "$sha1" >/dev
/null
2>&1 ||
continue
251 # In common case we will get both "normal" and ^{} entries.
252 # Filter out the dupes.
253 [ "$last_tag" = "$tagname" ] && continue
256 # if so, fetch the tag -- which should be
257 # a cheap operation -- to complete the chain.
258 echo -n "${tagname#tags/} " >&3
259 echo -e "$tagname"\\t
"$tagname"
261 sort |
uniq |
$fetch --stdin "$uri"
264 if [ "${PIPESTATUS[0]}" -ne 0 -o "$?" -ne 0 ]; then
265 echo "unable to fetch tags (non-fatal)" >&2
275 # When forcing, let the fetch tools make more extensive
276 # walk over the dependency tree with --recover.
278 elif optparse
-v; then
279 verbose
=$
((verbose
+1))
287 [ "$name" ] || name
="$(choose_origin branches "where to fetch from?
")" ||
exit 1
288 uri
=$
(cat "$_git/branches/$name" 2>/dev
/null
) || die
"unknown branch: $name"
291 if echo "$uri" |
grep -q '#'; then
292 rembranch
=$
(echo "$uri" | cut
-d '#' -f 2)
293 uri
=$
(echo "$uri" | cut
-d '#' -f 1)
296 if [ "$_git_no_wc" ]; then
297 [ -s "$_git/info/cg-fetch-initial" ] && [ ! -s "$_git/info/cg-fetch-initial-wcless" ] &&
298 die
"you must run the initial cg-fetch from the working copy root directory"
301 # Some other process with the same pid might appear, that's why
302 # we won't die but rather let the user check quickly.
303 dirtyfile
="$_git/info/cg-fetch-$(echo "$name" | sed -e 's/\//-.-/g')-dirty"
304 if [ -s "$dirtyfile" ]; then
305 kill -0 $
(cat "$dirtyfile") 2>/dev
/null
&& \
306 warn
"aren't you fetching $name twice at once? (waiting 10s)" && \
308 if [ -s "$_git/info/cg-fetch-initial" ]; then
309 echo "Recovering from a previously interrupted initial clone..."
311 echo "Recovering from a previously interrupted fetch..."
315 mkdir
-p "$_git/info"
316 echo $$
> "$dirtyfile"
319 orig_head
="$(get_ref "refs
/heads
/$name")" ||
: may stay empty
324 if echo "$uri" |
grep -q "^\(https\?\|ftp\)://"; then
327 elif echo "$uri" |
grep -q "^git+ssh://"; then
329 elif echo "$uri" |
grep -q "^git://"; then
331 elif echo "$uri" |
grep -q "^rsync://"; then
332 echo "WARNING: The rsync access method is DEPRECATED and will be REMOVED in the future!" >&2
335 elif echo "$uri" |
grep -q ":"; then
336 echo "WARNING: I guessed the host:path syntax was used and fell back to the git+ssh protocol." >&2
337 echo "WARNING: The host:path syntax is evil because it is implicit. Please just use a URI." >&2
340 [ -d "$uri/.git" ] && uri
="$uri/.git"
341 [ -d "$uri" ] || die
"repository not found"
345 # Perhaps the object database is shared
347 is_same_repo
"$_git_objects" "$uri/objects" && symlinked
=1
349 # See if we can hardlink and add "-l" to cp flags.
351 sample_file
="$(find "$uri" -type f -print | head -n 1)"
352 rm -f "$_git/.,,lntest"
353 if cp -fl "$sample_file" "$_git/.,,lntest" 2>/dev
/null
; then
355 echo "Using hard links"
357 echo "Hard links don't work - using copy"
359 rm -f "$_git/.,,lntest"
363 if [ "$packed_transport" ]; then
364 # This is a really special case.
365 [ "$rembranch" ] || rembranch
="HEAD"
368 [ -s "$_git/info/cg-fetch-initial" ] && cloneorfetch
=-k #clone
370 rm -f "$_git/info/cg-fetch-earlydie"
372 fetch_pack_recorder
() {
373 while read sha1 remote_name
; do
374 [ "$sha1" = "failed" ] && die
"$2"
375 ref
="$1"; [ "$ref" ] || ref
="$remote_name"
376 git-update-ref
"$ref" "$sha1"
379 echo "Fetching pack (head and objects)..."
380 ( git-fetch-pack
$cloneorfetch "$uri" "$rembranch" ||
381 echo "failed" "$rembranch" ) |
382 fetch_pack_recorder
"refs/heads/$name" "fetching pack failed" ||
385 record_tags_to_fetch
() {
386 ( cut
-f 1 |
tr '\n' '\0' |
387 xargs -0 git-fetch-pack
$cloneorfetch "$uri" ||
388 echo "failed" "$rembranch" ) |
390 fetch_pack_recorder
"" "unable to retrieve tags (non-fatal)"
392 fetch
=record_tags_to_fetch
396 show_changes_summary
"$orig_head" "$(cg-object-id "$name")"
397 [ -s "$_git/info/cg-fetch-initial" ] && initial_done
402 ### Behold, the fetch itself
405 echo "Fetching head..."
407 tmpname
="$(mktemp -t githead.XXXXXX)"
411 cleanup_trap
"cleanup"
413 if [ "$rembranch" ]; then
414 $get -i "$uri/refs/heads/$rembranch" "$tmpname" ||
415 die
"unable to get the head pointer of branch $rembranch"
417 $get -b "$uri/HEAD" "$tmpname" ||
418 die
"unable to get the HEAD branch"
421 new_head
="$(cat "$tmpname")"
422 if [ "${new_head#ref:}" != "$new_head" ]; then
423 new_head
="$(echo "$new_head" | sed 's/^ref: *//')"
424 $get -i "$uri/$new_head" "$tmpname" ||
425 die
"unable to get the head pointer of branch $new_head (referenced by HEAD)"
426 new_head
="$(cat "$tmpname")"
429 rm -f "$_git/info/cg-fetch-earlydie"
431 echo "Fetching objects..."
433 if ! [ "$symlinked" ]; then
434 if [ "$recovery" -o "$orig_head" != "$new_head" ]; then
435 [ -d "$_git_objects" ] || mkdir
-p "$_git_objects"
436 $fetch "$(cat "$tmpname")" "$uri" "heads/$name" || die
"objects fetch failed"
439 git-update-ref
"refs/heads/$name" "$(cat "$tmpname")"
447 if ! fetch_tags
; then
452 show_changes_summary
"$orig_head" "$new_head"
453 [ -s "$_git/info/cg-fetch-initial" ] && initial_done