2 # TopGit - A different patch queue manager
34 --follow-tags|
--no-follow-tags)
47 echo "Usage: ${tgname:-tg} [...] push [--dry-run] [--force] [--no-deps] [--tgish-only] [-r <pushRemote>] [-a | --all | <branch>...]"
54 v_strip_ref arg
"$arg"
55 branches
="${branches:+$branches }$arg";;
58 [ -z "$push_all" ] ||
[ -z "$branches" ] || die
"branch names not allowed with --all"
60 [ -n "$remote" ] || remote
="$(git config topgit.pushremote 2>/dev/null)" ||
:
61 [ -n "$remote" ] || remote
="$base_remote"
63 if [ -z "$remote" ]; then
64 warn
"either use -r <pushRemote> argument or set topgit.[push]remote"
65 die
"no push remote location given"
68 [ -n "$branches$push_all" ] || branches
="HEAD"
69 if [ -n "$push_all" ]; then
70 branches
="$(non_annihilated_branches | paste -s -d " " -)"
72 oldbranches
="$branches"
74 while read name
&& [ -n "$name" ]; do
75 if [ "$name" = "HEAD" ] ||
[ "$name" = "@" ]; then
76 sr
="$(git symbolic-ref --quiet HEAD)" ||
:
77 [ -n "$sr" ] || die
"cannot push a detached HEAD"
78 case "$sr" in refs
/heads
/*);;*)
79 die
"HEAD is a symref to other than refs/heads/..."
81 ref_exists
"$sr" || die
"HEAD ($sr) is unborn"
84 ref_exists
"refs/heads/$name" || die
"no such ref: refs/heads/$name"
87 case " $branches " in *" $b "*);;*)
88 branches
="${branches:+$branches }$b"
91 $(sed 'y/ /\n/' <<-LIST
99 _listfile
="$(get_temp tg-push-listfile)"
100 _inclfile
="$(get_temp tg-push-inclfile)"
104 # FIXME should we abort on missing dependency?
105 [ -z "$_dep_missing" ] ||
return 0
107 # if so desired omit non tgish deps
108 [ -z "$tgish_deps_only" ] ||
[ -n "$_dep_is_tgish" ] ||
return 0
110 # filter out plain SHA1s. These don't need to be pushed explicitly as
111 # the patches that depend on the sha1 have it already in their ancestry.
112 ! is_sha1
"$_dep" ||
return 0
114 echol
"refs/heads/$_dep" >> "$_listfile"
115 [ -z "$_dep_is_tgish" ] ||
116 echo "refs/$topbases/$_dep" >> "$_listfile"
119 if [ -z "$outofdateok" ]; then
120 needs_update_check_clear
121 needs_update_check
$branches
122 if [ -n "$needs_update_behind" ]; then
123 printf 'branch not up-to-date: %s\n' $needs_update_behind >&2
124 die
"all branches to be pushed must be up-to-date (try --allow-outdated)"
129 while read name
&& [ -n "$name" ]; do
131 # re-use push_branch, which expects some pre-defined variables
135 ref_exists
"refs/$topbases/$_dep" ||
139 # deps but only if branch is tgish
140 [ -z "$recurse_deps" ] ||
[ -z "$_dep_is_tgish" ] ||
141 recurse_deps push_branch
"$name"
143 $(sed 'y/ /\n/' <<LIST
149 [ -s "$_listfile" ] || die
"nothing to push"
151 # find a suitable temporary remote name to use
152 _rmtbase
="tg-push-$(date '+%Y%m%d_%H%M%S')" ||
:
153 _rmttemp
="$(git config --name-only --get-regexp '^remote\.[^.][^.]*\.' |
154 awk -v b="$_rmtbase" '
155 {sub(/^remote\./,"");sub(/\.[^.]*$/,"");if($0!="")r[$0]=1}
158 if(!r[b]) {print b;exit 0}
164 ')" || die
"unable to create temporary remote name"
166 # attempt to allow specifying a URL as an explicit push remote
167 # first see if there's a pushurl or url setting for the given
168 # remote and if not, use it as-is thereby treating it as a URL
170 _rmturl
="$(git config --get "remote.
$remote.pushurl
" 2>/dev/null)" ||
:
172 _rmturl
="$(git config --get "remote.
$remote.url
" 2>/dev/null)" ||
:
173 [ -n "$_rmturl" ] ||
{ _rmtnm
=; _rmturl
="$remote"; } # use it as-is
175 # if we have a real remote name, check to see whether or not there is
176 # a fetch spec configured for the remote TopGit branches and/or bases
177 # and if so add suitable fetch specs for both the branches and bases
178 # to the temporary remote in order for the opportunistic ref updates
179 # to take place that would have if a temporary remote was not in use.
183 git config
--get-all "remote.$remote.fetch" 2>/dev
/null |
184 awk -v r
="$remote" -v bl
="$topbases" -v br
="${topbases#heads/}" '
187 sl0="refs/heads/*:refs/remotes/"r"/*"; sl1="+"sl0
188 sr0="refs/"bl"/*:refs/remotes/"r"/"br"/*"; sr1="+"sr0
190 function exitnow(c) {x=c;exit x}
191 END {if(x!="")exit x}
192 $0 == sl0 || $0 == sl1 || $0 == sr0 || $0 == sr1 {exitnow(0)}
198 # remove multiple occurrences of the same branch and create
199 # an include file with a temporary remote listing all of them
200 # as push specs thereby avoiding any command line length limit
201 # and keeping the push entirely atomic if desired no matter how
202 # many branches may be involved
203 sort -u "$_listfile" |
awk -v r
="$_rmttemp" -v u
="$_rmturl" -v f
="$_rmtftc" \
204 -v fr
="$remote" -v bl
="$topbases" -v br
="${topbases#heads/}" '
205 function q(s) { gsub(/[\\"]/,"\\\\&",s); return "\""s"\""; }
207 print "[remote "q(r)"]"
210 sl="+refs/heads/*:refs/remotes/"fr"/*"
211 sr="+refs/"bl"/*:refs/remotes/"fr"/"br"/*"
212 print "\tfetch = "q(sl)
213 print "\tfetch = "q(sr)
216 { print "\tpush = "q($0":"$0) }
217 ' > "$_inclfile" || die
"unable to create temporary remote include file"
219 # be careful to make sure the shell doesn't chain to git and clean up the
220 # temporary file via the EXIT trap before Git's had a chance to read it
222 git
-c "include.path=$_inclfile" push
$opt4 $opt6 $dry_run $force $atomicopt $tagsopt $signedopt "$_rmttemp" || ec
=$?