chiark / gitweb /
tg-push: new command pushing a tgish branch
[topgit.git] / tg-create.sh
index 30c69c9ee1929ba80af155e46e704c4e339f7d73..2edd5379d54c9cc533a0904dafc51b6f566e728c 100644 (file)
@@ -7,6 +7,7 @@ deps= # List of dependent branches
 restarted= # Set to 1 if we are picking up in the middle of base setup
 merge= # List of branches to be merged; subset of $deps
 name=
+rname= # Remote branch to base this one on
 
 
 ## Parse options
@@ -14,33 +15,50 @@ name=
 while [ -n "$1" ]; do
        arg="$1"; shift
        case "$arg" in
-       -d)
-               deps="$(echo "$1" | sed 's/,/ /g')"; shift;;
+       -r)
+               rname="$1"; shift;;
        -*)
-               echo "Usage: tg create [-d DEPS...] NAME" >&2
+               echo "Usage: tg [...] create NAME [DEPS...|-r RNAME]" >&2
                exit 1;;
        *)
-               [ -z "$name" ] || die "name already specified ($name)"
-               name="$arg";;
+               if [ -z "$name" ]; then
+                       name="$arg"
+               else
+                       deps="$deps $arg"
+               fi;;
        esac
 done
 
 
+## Fast-track creating branches based on remote ones
+
+if [ -n "$rname" ]; then
+       [ -n "$name" ] || die "no branch name given"
+       ! ref_exists "$name" || die "branch '$name' already exists"
+       has_remote "$rname" || die "no branch $rname in remote $base_remote"
+
+       git update-ref "refs/top-bases/$name" "refs/remotes/$base_remote/top-bases/$rname"
+       git update-ref "refs/heads/$name" "refs/remotes/$base_remote/$rname"
+       info "Topic branch $name based on $base_remote : $rname set up."
+       exit 0
+fi
+
+
 ## Auto-guess dependencies
 
+deps="${deps# }"
 if [ -z "$deps" ]; then
-       head="$(git symbolic-ref HEAD)"
-       bname="${head#refs/top-bases/}"
-       if [ "$bname" != "$head" -a -s "$git_dir/top-deps" -a -s "$git_dir/top-merge" ]; then
-               # We are on a base branch now; resume merge!
+       if [ -z "$name" -a -s "$git_dir/top-name" -a -s "$git_dir/top-deps" -a -s "$git_dir/top-merge" ]; then
+               # We are setting up the base branch now; resume merge!
+               name="$(cat "$git_dir/top-name")"
                deps="$(cat "$git_dir/top-deps")"
                merge="$(cat "$git_dir/top-merge")"
-               name="$bname"
                restarted=1
                info "Resuming $name setup..."
        else
                # The common case
                [ -z "$name" ] && die "no branch name given"
+               head="$(git symbolic-ref HEAD)"
                deps="${head#refs/heads/}"
                [ "$deps" != "$head" ] || die "refusing to auto-depend on non-head ref ($head)"
                info "Automatically marking dependency on $deps"
@@ -50,24 +68,25 @@ fi
 [ -n "$merge" -o -n "$restarted" ] || merge="$deps "
 
 for d in $deps; do
-       git rev-parse --verify "$d" >/dev/null 2>&1 ||
+       ref_exists "$d"  ||
                die "unknown branch dependency '$d'"
 done
-! git rev-parse --verify "$name" >/dev/null 2>&1 ||
+! ref_exists "$name"  ||
        die "branch '$name' already exists"
 
 # Clean up any stale stuff
-rm -f "$git_dir/top-deps" "$git_dir/top-merge"
+rm -f "$git_dir/top-name" "$git_dir/top-deps" "$git_dir/top-merge"
 
 
-## Create base
+## Find starting commit to create the base
 
-if [ -n "$merge" ]; then
+if [ -n "$merge" -a -z "$restarted" ]; then
        # Unshift the first item from the to-merge list
        branch="${merge%% *}"
        merge="${merge#* }"
        info "Creating $name base from $branch..."
-       switch_to_base "$name" "$branch"
+       # We create a detached head so that we can abort this operation
+       git checkout -q "$(git rev-parse "$branch")"
 fi
 
 
@@ -80,10 +99,11 @@ while [ -n "$merge" ]; do
        info "Merging $name base with $branch..."
 
        if ! git merge "$branch"; then
-               info "Please commit merge resolution and call: tg create"
-               info "It is also safe to abort this operation using \`git reset --hard\`"
-               info "but please remember you are on the base branch now;"
-               info "you will want to switch to a different branch."
+               info "Please commit merge resolution and call: $tg create"
+               info "It is also safe to abort this operation using:"
+               info "git reset --hard some_branch"
+               info "(You are on a detached HEAD now.)"
+               echo "$name" >"$git_dir/top-name"
                echo "$deps" >"$git_dir/top-deps"
                echo "$merge" >"$git_dir/top-merge"
                exit 2
@@ -93,16 +113,21 @@ done
 
 ## Set up the topic branch
 
+git update-ref "refs/top-bases/$name" "HEAD" ""
 git checkout -b "$name"
 
 echo "$deps" | sed 's/ /\n/g' >"$root_dir/.topdeps"
-git add "$root_dir/.topdeps"
+git add -f "$root_dir/.topdeps"
 
 author="$(git var GIT_AUTHOR_IDENT)"
 author_addr="${author%> *}>"
 {
        echo "From: $author_addr"
-       echo "Subject: [PATCH] $1"
+       ! header="$(git config topgit.to)" || echo "To: $header"
+       ! header="$(git config topgit.cc)" || echo "Cc: $header"
+       ! header="$(git config topgit.bcc)" || echo "Bcc: $header"
+       ! subject_prefix="$(git config topgit.subjectprefix)" || subject_prefix="$subject_prefix "
+       echo "Subject: [${subject_prefix}PATCH] $name"
        echo
        cat <<EOT
 <patch description>
@@ -110,9 +135,11 @@ author_addr="${author%> *}>"
 Signed-off-by: $author_addr
 EOT
 } >"$root_dir/.topmsg"
-git add "$root_dir/.topmsg"
+git add -f "$root_dir/.topmsg"
 
 
 
 info "Topic branch $name set up. Please fill .topmsg now and make initial commit."
-info "To abort: git rm -f .top* && git checkout ${deps%% *} && tg delete $name"
+info "To abort: git rm -f .top* && git checkout ${deps%% *} && $tg delete $name"
+
+# vim:noet