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
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=
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
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
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
commit_message="Split '$dir/' into commit '$latest_new'"
fi
cat <<-EOF
- $message
+ $commit_message
git-subtree-dir: $dir
git-subtree-mainline: $latest_old
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
}
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'..."
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
# 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
cmd_merge()
{
+ revs=$(git rev-parse $default --revs-only "$@") || exit $?
ensure_clean
set -- $revs
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()
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" "$@"