3 # Push changes to a remote repository
4 # Copyright (c) Petr Baudis, 2005.
6 # It will push your commits on the current branch (or as specified by
7 # the -r option) to one or more remote repositories, provided that your
8 # commits follow the last commit in each of the remote repositories.
10 # Note that if a remote repository is associated with a working
11 # tree copy, this command won't update that. Use cg-reset at the
12 # remote side to bring it in sync (but throw away any local changes
13 # in that tree). Consider setting up a standalone repository (see
14 # `cg-admin-setuprepo`).
16 # You can set up update hooks in the remote repository to bind
17 # any action to the push (e.g. sending an email or CIA notification
18 # or even verifying if the commits are well-formed before letting
19 # them in). See `git-receive-pack`(1) documentation for details.
21 # Takes the branch names as arguments, defaulting to 'origin' or the
22 # current branch's default remote branch, see `cg-fetch` for details.
26 # -f:: Force push even if the fast-forward check fails (DANGEROUS)
27 # Force the push even if the fast-forward check fails, that is,
28 # the commit you are pushing is not a descendant of the current
29 # commit in the remote branch. DO NOT USE THIS FLAG - that error
30 # usually means that someone else pushed out some commits in
31 # the meantime and you should do `cg-update` in order to get
32 # them merged locally, then try to push again.
34 # You might want to use this flag only if you had to rewrite your
35 # history (e.g. using `cg-admin-uncommit` or 'cg-commit --amend')
36 # and now you want to push the new history out. However if you
37 # published your original commits in the meantime, you are now
38 # setting up quite some trouble for others who track your repository
39 # since Git will get confused. Use with care.
41 # -r BRANCH:: Push the given branch
42 # Pushes the given branch instead of the current one. Note that
43 # we lie a little here and you can actually specify a particular
44 # commit here, but you probably will not want to do that.
46 # -t TAG:: Push the given TAG
47 # Tells cg-push to also push the given tag. Note that in the
48 # future, cg-push should push tags automatically. Also note
49 # that even if you pass `cg-push` the '-t' arguments, your
50 # HEAD is still pushed as well in addition to the tags.
54 USAGE
="cg-push [-f] [-r LOCAL_BRANCH] [-t TAG]... [REMOTE_BRANCH]..."
57 .
"${COGITO_LIB}"cg-Xlib ||
exit 1
63 commit
="$(cg-object-id -c "$locbranch")"
64 old
="$(get_ref "refs
/heads
/$name")" ||
: may stay empty
65 git-send-pack
$force "$@" && git-update-ref refs
/heads
/"$name" "$commit" $old
69 locbranch
="$_git_head"
75 [ "$(cg-object-id -c "$locbranch")" ] ||
exit 1
76 elif optparse
-t=; then
77 tags
[${#tags[@]}]="refs/tags/$OPTARG"
78 elif optparse
-f; then
88 uri
="$(cat "$_git/branches
/$name" 2>/dev/null)" || die
"unknown branch: $name"
91 if echo "$uri" |
grep -q '#'; then
92 rembranch
="$(echo "$uri" | cut -d '#' -f 2)"
93 uri
="$(echo "$uri" | cut -d '#' -f 1)"
95 sprembranch
=":refs/heads/$rembranch"
97 if [ "${uri#http://}" != "$uri" -o "${uri#https://}" != "$uri" ]; then
98 git-http-push
$force "$uri/" "$locbranch$sprembranch" "${tags[@]}"
100 elif [ "${uri#git+ssh://}" != "$uri" ]; then
101 send_pack_update
"$name" "$(echo "$uri" | sed 's#^git+ssh://\([^/]*\)\(/.*\)$#\1:\2#')" "$locbranch$sprembranch" "${tags[@]}"
103 elif [ "${uri#rsync://}" != "$uri" ]; then
104 die
"pushing over rsync not supported"
106 elif [ "${uri#*:}" != "$uri" ]; then
107 echo "WARNING: I guessed the host:path syntax was used and fell back to the git+ssh protocol."
108 echo "WARNING: The host:path syntax is evil because it is implicit. Please just use a URI."
109 send_pack_update
"$name" "$uri" "$locbranch$sprembranch" "${tags[@]}"
112 remgit
="$uri"; [ -d "$remgit/.git" ] && remgit
="$remgit/.git"
113 if is_same_repo
"$_git_objects" "$remgit/objects"; then
114 commit
="$(cg-object-id -c "$locbranch")"
115 remid
="$(GIT_DIR="$remgit" get_ref refs/heads/$rembranch)" || die
"$remgit: no branch $master"
116 if [ "$remid" = "$commit" ] && [ ! "${tags[*]}" ]; then
117 echo "$remgit#$rembranch: Already up-to-date." >&2
120 if [ "$remid" != "$(git-merge-base "$remid" "$commit")" ]; then
121 if [ -z "$force" ]; then
122 echo "ERROR: Remote '$rembranch' has some changes you don't have in your '$locbranch'" >&2
123 echo "Try to cg-update from it first, then push." >&2
126 echo "Warning: Forcing $rembranch update even though remote $remid is not ancestor of local $commit." >&2
130 echo "Pushing $commit to $remgit#$rembranch" >&2
131 [ -x "$remgit/hooks/update" ] && "$remgit/hooks/update" "$rembranch" "$remid" "$commit"
132 GIT_DIR
="$remgit" git-update-ref refs
/heads
/"$rembranch" "$commit" "$remid" || die
"push failed"
133 git-update-ref refs
/heads
/"$name" "$commit"
134 for tag
in "${tags[@]}"; do
135 tagval
="$(get_ref "refs
/tags
/$tag")"
136 GIT_DIR
="$remgit" git-update-ref refs
/tags
/"$tag" "$tagval"
138 [ -x "$remgit/hooks/post-update" ] && "$remgit/hooks/post-update" "$rembranch"
140 send_pack_update
"$name" "$uri" "$locbranch$sprembranch" "${tags[@]}"
145 if [ "${#ARGS[@]}" == 0 ]; then
146 name
="$(choose_origin branches "where to push to?
")" ||
exit 1
150 for name
in "${ARGS[@]}"; do