Merge remote branch 'origin/master'
[gitweb.git] / git-subtree.sh
index 0a5cafa77f1acb5e0cd507864a615a065b77f0d6..a15d91ffb1b3d3318409619449745dbcfb393abf 100755 (executable)
@@ -11,6 +11,7 @@ OPTS_SPEC="\
 git subtree add   --prefix=<prefix> <commit>
 git subtree merge --prefix=<prefix> <commit>
 git subtree pull  --prefix=<prefix> <repository> <refspec...>
+git subtree push  --prefix=<prefix> <repository> <refspec...>
 git subtree split --prefix=<prefix> <commit...>
 --
 h,help        show the help
@@ -24,12 +25,16 @@ b,branch=     create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
- options for 'add', 'merge', and 'pull'
+ options for 'add', 'merge', 'pull' and 'push'
 squash        merge subtree changes as a single commit
 "
 eval $(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)
+
+OPATH=$PATH
 PATH=$(git --exec-path):$PATH
 . git-sh-setup
+PATH=$OPATH  # apparently needed for some versions of msysgit
+
 require_work_tree
 
 quiet=
@@ -98,16 +103,24 @@ command="$1"
 shift
 case "$command" in
        add|merge|pull) default= ;;
-       split) default="--default HEAD" ;;
+       split|push) default="--default HEAD" ;;
        *) die "Unknown command '$command'" ;;
 esac
 
 if [ -z "$prefix" ]; then
        die "You must provide the --prefix option."
 fi
+
+case "$command" in
+       add) [ -e "$prefix" ] && 
+               die "prefix '$prefix' already exists." ;;
+       *)   [ -e "$prefix" ] || 
+               die "'$prefix' does not exist; use 'git subtree add'" ;;
+esac
+
 dir="$(dirname "$prefix/.")"
 
-if [ "$command" != "pull" ]; then
+if [ "$command" != "pull" -a "$command" != "add" -a "$command" != "push" ]; then
        revs=$(git rev-parse $default --revs-only "$@") || exit $?
        dirs="$(git rev-parse --no-revs --no-flags "$@")" || exit $?
        if [ -n "$dirs" ]; then
@@ -166,9 +179,9 @@ rev_is_descendant_of_branch()
        newrev="$1"
        branch="$2"
        branch_hash=$(git rev-parse $branch)
-       match=$(git rev-list $newrev | grep $branch_hash)
+       match=$(git rev-list -1 $branch_hash ^$newrev)
 
-       if [ -n "$match" ]; then
+       if [ -z "$match" ]; then
                return 0
        else
                return 1
@@ -244,6 +257,7 @@ find_existing_splits()
                                if [ -n "$main" -a -n "$sub" ]; then
                                        debug "  Prior: $main -> $sub"
                                        cache_set $main $sub
+                                       cache_set $sub $sub
                                        try_remove_previous "$main"
                                        try_remove_previous "$sub"
                                fi
@@ -317,7 +331,7 @@ rejoin_msg()
                commit_message="Split '$dir/' into commit '$latest_new'"
        fi
        cat <<-EOF
-               $message
+               $commit_message
                
                git-subtree-dir: $dir
                git-subtree-mainline: $latest_old
@@ -442,10 +456,10 @@ copy_or_skip()
 
 ensure_clean()
 {
-       if ! git diff-index HEAD --exit-code --quiet; then
+       if ! git diff-index HEAD --exit-code --quiet 2>&1; then
                die "Working tree has modifications.  Cannot add."
        fi
-       if ! git diff-index --cached HEAD --exit-code --quiet; then
+       if ! git diff-index --cached HEAD --exit-code --quiet 2>&1; then
                die "Index has modifications.  Cannot add."
        fi
 }
@@ -455,12 +469,34 @@ cmd_add()
        if [ -e "$dir" ]; then
                die "'$dir' already exists.  Cannot add."
        fi
+
        ensure_clean
        
-       set -- $revs
-       if [ $# -ne 1 ]; then
-               die "You must provide exactly one revision.  Got: '$revs'"
+       if [ $# -eq 1 ]; then
+               "cmd_add_commit" "$@"
+       elif [ $# -eq 2 ]; then
+               "cmd_add_repository" "$@"
+       else
+           say "error: parameters were '$@'"
+           die "Provide either a refspec or a repository and refspec."
        fi
+}
+
+cmd_add_repository()
+{
+       echo "git fetch" "$@"
+       repository=$1
+       refspec=$2
+       git fetch "$@" || exit $?
+       revs=FETCH_HEAD
+       set -- $revs
+       cmd_add_commit "$@"
+}
+
+cmd_add_commit()
+{
+       revs=$(git rev-parse $default --revs-only "$@") || exit $?
+       set -- $revs
        rev="$1"
        
        debug "Adding $dir as '$rev'..."
@@ -520,8 +556,7 @@ cmd_split()
        eval "$grl" |
        while read rev parents; do
                revcount=$(($revcount + 1))
-               say -n "$revcount/$revmax ($createcount)
-"
+               say -n "$revcount/$revmax ($createcount)\r"
                debug "Processing commit: $rev"
                exists=$(cache_get $rev)
                if [ -n "$exists" ]; then
@@ -539,7 +574,9 @@ cmd_split()
                # ugly.  is there no better way to tell if this is a subtree
                # vs. a mainline commit?  Does it matter?
                if [ -z $tree ]; then
-                       cache_set $rev $rev
+                       if [ -n "$newparents" ]; then
+                               cache_set $rev $rev
+                       fi
                        continue
                fi
 
@@ -579,6 +616,7 @@ cmd_split()
 
 cmd_merge()
 {
+       revs=$(git rev-parse $default --revs-only "$@") || exit $?
        ensure_clean
        
        set -- $revs
@@ -603,8 +641,21 @@ cmd_merge()
                debug "New squash commit: $new"
                rev="$new"
        fi
-       
-       git merge -s subtree --message="$message" $rev
+
+       version=$(git version)
+       if [ "$version" \< "git version 1.7" ]; then
+               if [ -n "$message" ]; then
+                       git merge -s subtree --message="$message" $rev
+               else
+                       git merge -s subtree $rev
+               fi
+       else
+               if [ -n "$message" ]; then
+                       git merge -Xsubtree="$prefix" --message="$message" $rev
+               else
+                       git merge -Xsubtree="$prefix" $rev
+               fi
+       fi
 }
 
 cmd_pull()
@@ -612,7 +663,23 @@ cmd_pull()
        ensure_clean
        git fetch "$@" || exit $?
        revs=FETCH_HEAD
-       cmd_merge
+       set -- $revs
+       cmd_merge "$@"
+}
+
+cmd_push()
+{
+       if [ $# -ne 2 ]; then
+           die "You must provide <repository> <refspec>"
+       fi
+       if [ -e "$dir" ]; then
+           repository=$1
+           refspec=$2
+           echo "git push using: " $repository $refspec
+           git push $repository $(git subtree split --prefix=$prefix):refs/heads/$refspec
+       else
+           die "'$dir' must already exist. Try 'git subtree add'."
+       fi
 }
 
 "cmd_$command" "$@"