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