subtree: more consistent error propagation
[git] / contrib / subtree / git-subtree.sh
1 #!/bin/sh
2 #
3 # git-subtree.sh: split/join git repositories in subdirectories of this one
4 #
5 # Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>
6 #
7
8 OPTS_SPEC="\
9 git subtree add   --prefix=<prefix> <commit>
10 git subtree add   --prefix=<prefix> <repository> <ref>
11 git subtree merge --prefix=<prefix> <commit>
12 git subtree pull  --prefix=<prefix> <repository> <ref>
13 git subtree push  --prefix=<prefix> <repository> <ref>
14 git subtree split --prefix=<prefix> <commit>
15 --
16 h,help        show the help
17 q             quiet
18 d             show debug messages
19 P,prefix=     the name of the subdir to split out
20 m,message=    use the given message as the commit message for the merge commit
21  options for 'split'
22 annotate=     add a prefix to commit message of new commits
23 b,branch=     create a new branch from the split subtree
24 ignore-joins  ignore prior --rejoin commits
25 onto=         try connecting new tree to an existing one
26 rejoin        merge the new branch back into HEAD
27  options for 'add', 'merge', and 'pull'
28 squash        merge subtree changes as a single commit
29 "
30
31 PATH=$PATH:$(git --exec-path)
32
33 quiet=
34 branch=
35 debug=
36 command=
37 onto=
38 rejoin=
39 ignore_joins=
40 annotate=
41 squash=
42 message=
43 prefix=
44
45 debug () {
46         if test -n "$debug"
47         then
48                 printf "%s\n" "$*" >&2
49         fi
50 }
51
52 say () {
53         if test -z "$quiet"
54         then
55                 printf "%s\n" "$*" >&2
56         fi
57 }
58
59 progress () {
60         if test -z "$quiet"
61         then
62                 printf "%s\r" "$*" >&2
63         fi
64 }
65
66 assert () {
67         if ! "$@"
68         then
69                 die "assertion failed: " "$@"
70         fi
71 }
72
73 ensure_single_rev () {
74         if test $# -ne 1
75         then
76                 die "You must provide exactly one revision.  Got: '$@'"
77         fi
78 }
79
80 main () {
81         if test $# -eq 0
82         then
83                 set -- -h
84         fi
85         eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
86         . git-sh-setup
87         require_work_tree
88
89         while test $# -gt 0
90         do
91                 opt="$1"
92                 shift
93
94                 case "$opt" in
95                 -q)
96                         quiet=1
97                         ;;
98                 -d)
99                         debug=1
100                         ;;
101                 --annotate)
102                         annotate="$1"
103                         shift
104                         ;;
105                 --no-annotate)
106                         annotate=
107                         ;;
108                 -b)
109                         branch="$1"
110                         shift
111                         ;;
112                 -P)
113                         prefix="${1%/}"
114                         shift
115                         ;;
116                 -m)
117                         message="$1"
118                         shift
119                         ;;
120                 --no-prefix)
121                         prefix=
122                         ;;
123                 --onto)
124                         onto="$1"
125                         shift
126                         ;;
127                 --no-onto)
128                         onto=
129                         ;;
130                 --rejoin)
131                         rejoin=1
132                         ;;
133                 --no-rejoin)
134                         rejoin=
135                         ;;
136                 --ignore-joins)
137                         ignore_joins=1
138                         ;;
139                 --no-ignore-joins)
140                         ignore_joins=
141                         ;;
142                 --squash)
143                         squash=1
144                         ;;
145                 --no-squash)
146                         squash=
147                         ;;
148                 --)
149                         break
150                         ;;
151                 *)
152                         die "Unexpected option: $opt"
153                         ;;
154                 esac
155         done
156
157         command="$1"
158         shift
159
160         case "$command" in
161         add|merge|pull)
162                 default=
163                 ;;
164         split|push)
165                 default="--default HEAD"
166                 ;;
167         *)
168                 die "Unknown command '$command'"
169                 ;;
170         esac
171
172         if test -z "$prefix"
173         then
174                 die "You must provide the --prefix option."
175         fi
176
177         case "$command" in
178         add)
179                 test -e "$prefix" &&
180                         die "prefix '$prefix' already exists."
181                 ;;
182         *)
183                 test -e "$prefix" ||
184                         die "'$prefix' does not exist; use 'git subtree add'"
185                 ;;
186         esac
187
188         dir="$(dirname "$prefix/.")"
189
190         if test "$command" != "pull" &&
191                         test "$command" != "add" &&
192                         test "$command" != "push"
193         then
194                 revs=$(git rev-parse $default --revs-only "$@") || exit $?
195                 dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
196                 ensure_single_rev $revs
197                 if test -n "$dirs"
198                 then
199                         die "Error: Use --prefix instead of bare filenames."
200                 fi
201         fi
202
203         debug "command: {$command}"
204         debug "quiet: {$quiet}"
205         debug "revs: {$revs}"
206         debug "dir: {$dir}"
207         debug "opts: {$*}"
208         debug
209
210         "cmd_$command" "$@"
211 }
212
213 cache_setup () {
214         cachedir="$GIT_DIR/subtree-cache/$$"
215         rm -rf "$cachedir" ||
216                 die "Can't delete old cachedir: $cachedir"
217         mkdir -p "$cachedir" ||
218                 die "Can't create new cachedir: $cachedir"
219         mkdir -p "$cachedir/notree" ||
220                 die "Can't create new cachedir: $cachedir/notree"
221         debug "Using cachedir: $cachedir" >&2
222 }
223
224 cache_get () {
225         for oldrev in "$@"
226         do
227                 if test -r "$cachedir/$oldrev"
228                 then
229                         read newrev <"$cachedir/$oldrev"
230                         echo $newrev
231                 fi
232         done
233 }
234
235 cache_miss () {
236         for oldrev in "$@"
237         do
238                 if ! test -r "$cachedir/$oldrev"
239                 then
240                         echo $oldrev
241                 fi
242         done
243 }
244
245 check_parents () {
246         missed=$(cache_miss "$1") || exit $?
247         local indent=$(($2 + 1))
248         for miss in $missed
249         do
250                 if ! test -r "$cachedir/notree/$miss"
251                 then
252                         debug "  incorrect order: $miss"
253                         process_split_commit "$miss" "" "$indent"
254                 fi
255         done
256 }
257
258 set_notree () {
259         echo "1" > "$cachedir/notree/$1"
260 }
261
262 cache_set () {
263         oldrev="$1"
264         newrev="$2"
265         if test "$oldrev" != "latest_old" &&
266                 test "$oldrev" != "latest_new" &&
267                 test -e "$cachedir/$oldrev"
268         then
269                 die "cache for $oldrev already exists!"
270         fi
271         echo "$newrev" >"$cachedir/$oldrev"
272 }
273
274 rev_exists () {
275         if git rev-parse "$1" >/dev/null 2>&1
276         then
277                 return 0
278         else
279                 return 1
280         fi
281 }
282
283 rev_is_descendant_of_branch () {
284         newrev="$1"
285         branch="$2"
286         branch_hash=$(git rev-parse "$branch")
287         match=$(git rev-list -1 "$branch_hash" "^$newrev")
288
289         if test -z "$match"
290         then
291                 return 0
292         else
293                 return 1
294         fi
295 }
296
297 # if a commit doesn't have a parent, this might not work.  But we only want
298 # to remove the parent from the rev-list, and since it doesn't exist, it won't
299 # be there anyway, so do nothing in that case.
300 try_remove_previous () {
301         if rev_exists "$1^"
302         then
303                 echo "^$1^"
304         fi
305 }
306
307 find_latest_squash () {
308         debug "Looking for latest squash ($dir)..."
309         dir="$1"
310         sq=
311         main=
312         sub=
313         git log --grep="^git-subtree-dir: $dir/*\$" \
314                 --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' HEAD |
315         while read a b junk
316         do
317                 debug "$a $b $junk"
318                 debug "{{$sq/$main/$sub}}"
319                 case "$a" in
320                 START)
321                         sq="$b"
322                         ;;
323                 git-subtree-mainline:)
324                         main="$b"
325                         ;;
326                 git-subtree-split:)
327                         sub="$(git rev-parse "$b^0")" ||
328                         die "could not rev-parse split hash $b from commit $sq"
329                         ;;
330                 END)
331                         if test -n "$sub"
332                         then
333                                 if test -n "$main"
334                                 then
335                                         # a rejoin commit?
336                                         # Pretend its sub was a squash.
337                                         sq="$sub"
338                                 fi
339                                 debug "Squash found: $sq $sub"
340                                 echo "$sq" "$sub"
341                                 break
342                         fi
343                         sq=
344                         main=
345                         sub=
346                         ;;
347                 esac
348         done || exit $?
349 }
350
351 find_existing_splits () {
352         debug "Looking for prior splits..."
353         dir="$1"
354         revs="$2"
355         main=
356         sub=
357         local grep_format="^git-subtree-dir: $dir/*\$"
358         if test -n "$ignore_joins"
359         then
360                 grep_format="^Add '$dir/' from commit '"
361         fi
362         git log --grep="$grep_format" \
363                 --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' $revs |
364         while read a b junk
365         do
366                 case "$a" in
367                 START)
368                         sq="$b"
369                         ;;
370                 git-subtree-mainline:)
371                         main="$b"
372                         ;;
373                 git-subtree-split:)
374                         sub="$(git rev-parse "$b^0")" ||
375                         die "could not rev-parse split hash $b from commit $sq"
376                         ;;
377                 END)
378                         debug "  Main is: '$main'"
379                         if test -z "$main" -a -n "$sub"
380                         then
381                                 # squash commits refer to a subtree
382                                 debug "  Squash: $sq from $sub"
383                                 cache_set "$sq" "$sub"
384                         fi
385                         if test -n "$main" -a -n "$sub"
386                         then
387                                 debug "  Prior: $main -> $sub"
388                                 cache_set $main $sub
389                                 cache_set $sub $sub
390                                 try_remove_previous "$main"
391                                 try_remove_previous "$sub"
392                         fi
393                         main=
394                         sub=
395                         ;;
396                 esac
397         done || exit $?
398 }
399
400 copy_commit () {
401         # We're going to set some environment vars here, so
402         # do it in a subshell to get rid of them safely later
403         debug copy_commit "{$1}" "{$2}" "{$3}"
404         git log -1 --no-show-signature --pretty=format:'%an%n%ae%n%aD%n%cn%n%ce%n%cD%n%B' "$1" |
405         (
406                 read GIT_AUTHOR_NAME
407                 read GIT_AUTHOR_EMAIL
408                 read GIT_AUTHOR_DATE
409                 read GIT_COMMITTER_NAME
410                 read GIT_COMMITTER_EMAIL
411                 read GIT_COMMITTER_DATE
412                 export  GIT_AUTHOR_NAME \
413                         GIT_AUTHOR_EMAIL \
414                         GIT_AUTHOR_DATE \
415                         GIT_COMMITTER_NAME \
416                         GIT_COMMITTER_EMAIL \
417                         GIT_COMMITTER_DATE
418                 (
419                         printf "%s" "$annotate"
420                         cat
421                 ) |
422                 git commit-tree "$2" $3  # reads the rest of stdin
423         ) || die "Can't copy commit $1"
424 }
425
426 add_msg () {
427         dir="$1"
428         latest_old="$2"
429         latest_new="$3"
430         if test -n "$message"
431         then
432                 commit_message="$message"
433         else
434                 commit_message="Add '$dir/' from commit '$latest_new'"
435         fi
436         cat <<-EOF
437                 $commit_message
438
439                 git-subtree-dir: $dir
440                 git-subtree-mainline: $latest_old
441                 git-subtree-split: $latest_new
442         EOF
443 }
444
445 add_squashed_msg () {
446         if test -n "$message"
447         then
448                 echo "$message"
449         else
450                 echo "Merge commit '$1' as '$2'"
451         fi
452 }
453
454 rejoin_msg () {
455         dir="$1"
456         latest_old="$2"
457         latest_new="$3"
458         if test -n "$message"
459         then
460                 commit_message="$message"
461         else
462                 commit_message="Split '$dir/' into commit '$latest_new'"
463         fi
464         cat <<-EOF
465                 $commit_message
466
467                 git-subtree-dir: $dir
468                 git-subtree-mainline: $latest_old
469                 git-subtree-split: $latest_new
470         EOF
471 }
472
473 squash_msg () {
474         dir="$1"
475         oldsub="$2"
476         newsub="$3"
477         newsub_short=$(git rev-parse --short "$newsub")
478
479         if test -n "$oldsub"
480         then
481                 oldsub_short=$(git rev-parse --short "$oldsub")
482                 echo "Squashed '$dir/' changes from $oldsub_short..$newsub_short"
483                 echo
484                 git log --no-show-signature --pretty=tformat:'%h %s' "$oldsub..$newsub"
485                 git log --no-show-signature --pretty=tformat:'REVERT: %h %s' "$newsub..$oldsub"
486         else
487                 echo "Squashed '$dir/' content from commit $newsub_short"
488         fi
489
490         echo
491         echo "git-subtree-dir: $dir"
492         echo "git-subtree-split: $newsub"
493 }
494
495 toptree_for_commit () {
496         commit="$1"
497         git rev-parse --verify "$commit^{tree}" || exit $?
498 }
499
500 subtree_for_commit () {
501         commit="$1"
502         dir="$2"
503         git ls-tree "$commit" -- "$dir" |
504         while read mode type tree name
505         do
506                 assert test "$name" = "$dir"
507                 assert test "$type" = "tree" -o "$type" = "commit"
508                 test "$type" = "commit" && continue  # ignore submodules
509                 echo $tree
510                 break
511         done || exit $?
512 }
513
514 tree_changed () {
515         tree=$1
516         shift
517         if test $# -ne 1
518         then
519                 return 0   # weird parents, consider it changed
520         else
521                 ptree=$(toptree_for_commit $1) || exit $?
522                 if test "$ptree" != "$tree"
523                 then
524                         return 0   # changed
525                 else
526                         return 1   # not changed
527                 fi
528         fi
529 }
530
531 new_squash_commit () {
532         old="$1"
533         oldsub="$2"
534         newsub="$3"
535         tree=$(toptree_for_commit $newsub) || exit $?
536         if test -n "$old"
537         then
538                 squash_msg "$dir" "$oldsub" "$newsub" |
539                 git commit-tree "$tree" -p "$old" || exit $?
540         else
541                 squash_msg "$dir" "" "$newsub" |
542                 git commit-tree "$tree" || exit $?
543         fi
544 }
545
546 copy_or_skip () {
547         rev="$1"
548         tree="$2"
549         newparents="$3"
550         assert test -n "$tree"
551
552         identical=
553         nonidentical=
554         p=
555         gotparents=
556         copycommit=
557         for parent in $newparents
558         do
559                 ptree=$(toptree_for_commit $parent) || exit $?
560                 test -z "$ptree" && continue
561                 if test "$ptree" = "$tree"
562                 then
563                         # an identical parent could be used in place of this rev.
564                         if test -n "$identical"
565                         then
566                                 # if a previous identical parent was found, check whether
567                                 # one is already an ancestor of the other
568                                 mergebase=$(git merge-base $identical $parent)
569                                 if test "$identical" = "$mergebase"
570                                 then
571                                         # current identical commit is an ancestor of parent
572                                         identical="$parent"
573                                 elif test "$parent" != "$mergebase"
574                                 then
575                                         # no common history; commit must be copied
576                                         copycommit=1
577                                 fi
578                         else
579                                 # first identical parent detected
580                                 identical="$parent"
581                         fi
582                 else
583                         nonidentical="$parent"
584                 fi
585
586                 # sometimes both old parents map to the same newparent;
587                 # eliminate duplicates
588                 is_new=1
589                 for gp in $gotparents
590                 do
591                         if test "$gp" = "$parent"
592                         then
593                                 is_new=
594                                 break
595                         fi
596                 done
597                 if test -n "$is_new"
598                 then
599                         gotparents="$gotparents $parent"
600                         p="$p -p $parent"
601                 fi
602         done
603
604         if test -n "$identical" && test -n "$nonidentical"
605         then
606                 extras=$(git rev-list --count $identical..$nonidentical)
607                 if test "$extras" -ne 0
608                 then
609                         # we need to preserve history along the other branch
610                         copycommit=1
611                 fi
612         fi
613         if test -n "$identical" && test -z "$copycommit"
614         then
615                 echo $identical
616         else
617                 copy_commit "$rev" "$tree" "$p" || exit $?
618         fi
619 }
620
621 ensure_clean () {
622         if ! git diff-index HEAD --exit-code --quiet 2>&1
623         then
624                 die "Working tree has modifications.  Cannot add."
625         fi
626         if ! git diff-index --cached HEAD --exit-code --quiet 2>&1
627         then
628                 die "Index has modifications.  Cannot add."
629         fi
630 }
631
632 ensure_valid_ref_format () {
633         git check-ref-format "refs/heads/$1" ||
634                 die "'$1' does not look like a ref"
635 }
636
637 process_split_commit () {
638         local rev="$1"
639         local parents="$2"
640         local indent=$3
641
642         if test $indent -eq 0
643         then
644                 revcount=$(($revcount + 1))
645         else
646                 # processing commit without normal parent information;
647                 # fetch from repo
648                 parents=$(git rev-parse "$rev^@")
649                 extracount=$(($extracount + 1))
650         fi
651
652         progress "$revcount/$revmax ($createcount) [$extracount]"
653
654         debug "Processing commit: $rev"
655         exists=$(cache_get "$rev") || exit $?
656         if test -n "$exists"
657         then
658                 debug "  prior: $exists"
659                 return
660         fi
661         createcount=$(($createcount + 1))
662         debug "  parents: $parents"
663         check_parents "$parents" "$indent"
664         newparents=$(cache_get $parents) || exit $?
665         debug "  newparents: $newparents"
666
667         tree=$(subtree_for_commit "$rev" "$dir") || exit $?
668         debug "  tree is: $tree"
669
670         # ugly.  is there no better way to tell if this is a subtree
671         # vs. a mainline commit?  Does it matter?
672         if test -z "$tree"
673         then
674                 set_notree "$rev"
675                 if test -n "$newparents"
676                 then
677                         cache_set "$rev" "$rev"
678                 fi
679                 return
680         fi
681
682         newrev=$(copy_or_skip "$rev" "$tree" "$newparents") || exit $?
683         debug "  newrev is: $newrev"
684         cache_set "$rev" "$newrev"
685         cache_set latest_new "$newrev"
686         cache_set latest_old "$rev"
687 }
688
689 cmd_add () {
690         if test -e "$dir"
691         then
692                 die "'$dir' already exists.  Cannot add."
693         fi
694
695         ensure_clean
696
697         if test $# -eq 1
698         then
699                 git rev-parse -q --verify "$1^{commit}" >/dev/null ||
700                         die "'$1' does not refer to a commit"
701
702                 cmd_add_commit "$@"
703
704         elif test $# -eq 2
705         then
706                 # Technically we could accept a refspec here but we're
707                 # just going to turn around and add FETCH_HEAD under the
708                 # specified directory.  Allowing a refspec might be
709                 # misleading because we won't do anything with any other
710                 # branches fetched via the refspec.
711                 ensure_valid_ref_format "$2"
712
713                 cmd_add_repository "$@"
714         else
715                 say "error: parameters were '$@'"
716                 die "Provide either a commit or a repository and commit."
717         fi
718 }
719
720 cmd_add_repository () {
721         echo "git fetch" "$@"
722         repository=$1
723         refspec=$2
724         git fetch "$@" || exit $?
725         revs=FETCH_HEAD
726         set -- $revs
727         cmd_add_commit "$@"
728 }
729
730 cmd_add_commit () {
731         rev=$(git rev-parse $default --revs-only "$@") || exit $?
732         ensure_single_rev $rev
733
734         debug "Adding $dir as '$rev'..."
735         git read-tree --prefix="$dir" $rev || exit $?
736         git checkout -- "$dir" || exit $?
737         tree=$(git write-tree) || exit $?
738
739         headrev=$(git rev-parse HEAD) || exit $?
740         if test -n "$headrev" && test "$headrev" != "$rev"
741         then
742                 headp="-p $headrev"
743         else
744                 headp=
745         fi
746
747         if test -n "$squash"
748         then
749                 rev=$(new_squash_commit "" "" "$rev") || exit $?
750                 commit=$(add_squashed_msg "$rev" "$dir" |
751                         git commit-tree "$tree" $headp -p "$rev") || exit $?
752         else
753                 revp=$(peel_committish "$rev") || exit $?
754                 commit=$(add_msg "$dir" $headrev "$rev" |
755                         git commit-tree "$tree" $headp -p "$revp") || exit $?
756         fi
757         git reset "$commit" || exit $?
758
759         say "Added dir '$dir'"
760 }
761
762 cmd_split () {
763         debug "Splitting $dir..."
764         cache_setup || exit $?
765
766         if test -n "$onto"
767         then
768                 debug "Reading history for --onto=$onto..."
769                 git rev-list $onto |
770                 while read rev
771                 do
772                         # the 'onto' history is already just the subdir, so
773                         # any parent we find there can be used verbatim
774                         debug "  cache: $rev"
775                         cache_set "$rev" "$rev"
776                 done || exit $?
777         fi
778
779         unrevs="$(find_existing_splits "$dir" "$revs")" || exit $?
780
781         # We can't restrict rev-list to only $dir here, because some of our
782         # parents have the $dir contents the root, and those won't match.
783         # (and rev-list --follow doesn't seem to solve this)
784         grl='git rev-list --topo-order --reverse --parents $revs $unrevs'
785         revmax=$(eval "$grl" | wc -l)
786         revcount=0
787         createcount=0
788         extracount=0
789         eval "$grl" |
790         while read rev parents
791         do
792                 process_split_commit "$rev" "$parents" 0
793         done || exit $?
794
795         latest_new=$(cache_get latest_new) || exit $?
796         if test -z "$latest_new"
797         then
798                 die "No new revisions were found"
799         fi
800
801         if test -n "$rejoin"
802         then
803                 debug "Merging split branch into HEAD..."
804                 latest_old=$(cache_get latest_old) || exit $?
805                 git merge -s ours \
806                         --allow-unrelated-histories \
807                         -m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \
808                         "$latest_new" >&2 || exit $?
809         fi
810         if test -n "$branch"
811         then
812                 if rev_exists "refs/heads/$branch"
813                 then
814                         if ! rev_is_descendant_of_branch "$latest_new" "$branch"
815                         then
816                                 die "Branch '$branch' is not an ancestor of commit '$latest_new'."
817                         fi
818                         action='Updated'
819                 else
820                         action='Created'
821                 fi
822                 git update-ref -m 'subtree split' \
823                         "refs/heads/$branch" "$latest_new" || exit $?
824                 say "$action branch '$branch'"
825         fi
826         echo "$latest_new"
827         exit 0
828 }
829
830 cmd_merge () {
831         rev=$(git rev-parse $default --revs-only "$@") || exit $?
832         ensure_single_rev $rev
833         ensure_clean
834
835         if test -n "$squash"
836         then
837                 first_split="$(find_latest_squash "$dir")" || exit $?
838                 if test -z "$first_split"
839                 then
840                         die "Can't squash-merge: '$dir' was never added."
841                 fi
842                 set $first_split
843                 old=$1
844                 sub=$2
845                 if test "$sub" = "$rev"
846                 then
847                         say "Subtree is already at commit $rev."
848                         exit 0
849                 fi
850                 new=$(new_squash_commit "$old" "$sub" "$rev") || exit $?
851                 debug "New squash commit: $new"
852                 rev="$new"
853         fi
854
855         version=$(git version)
856         if test "$version" \< "git version 1.7"
857         then
858                 if test -n "$message"
859                 then
860                         git merge -s subtree --message="$message" "$rev"
861                 else
862                         git merge -s subtree "$rev"
863                 fi
864         else
865                 if test -n "$message"
866                 then
867                         git merge -Xsubtree="$prefix" \
868                                 --message="$message" "$rev"
869                 else
870                         git merge -Xsubtree="$prefix" $rev
871                 fi
872         fi
873 }
874
875 cmd_pull () {
876         if test $# -ne 2
877         then
878                 die "You must provide <repository> <ref>"
879         fi
880         ensure_clean
881         ensure_valid_ref_format "$2"
882         git fetch "$@" || exit $?
883         revs=FETCH_HEAD
884         set -- $revs
885         cmd_merge "$@"
886 }
887
888 cmd_push () {
889         if test $# -ne 2
890         then
891                 die "You must provide <repository> <ref>"
892         fi
893         ensure_valid_ref_format "$2"
894         if test -e "$dir"
895         then
896                 repository=$1
897                 refspec=$2
898                 echo "git push using: " "$repository" "$refspec"
899                 localrev=$(git subtree split --prefix="$prefix") || die
900                 git push "$repository" "$localrev":"refs/heads/$refspec"
901         else
902                 die "'$dir' must already exist. Try 'git subtree add'."
903         fi
904 }
905
906 main "$@"