tg-annihilate.sh: autostash and support --stash and --no-stash
[topgit/pro.git] / tg-import.sh
blobe0dca9872470379df946e26a08f692e25f732c33
1 #!/bin/sh
2 # TopGit - A different patch queue manager
3 # Copyright (C) Petr Baudis <pasky@suse.cz> 2008
4 # Copyright (C) Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> 2008
5 # Copyright (C) Kyle J. McKay <mackyle@gmail.com> 2015
6 # All rights reserved.
7 # GPLv2
9 branch_prefix=t/
10 single=
11 ranges=
12 rangecnt=0
13 basedep=
15 USAGE="Usage: ${tgname:-tg} [...] import [-d <base-branch>] ([-p <prefix>] <range>... | -s <name> <commit>)"
17 ## Parse options
19 while [ -n "$1" ]; do
20 arg="$1"; shift
21 case "$arg" in
22 -d)
23 basedep="$1"; shift;;
24 -p)
25 branch_prefix="$1"; shift;;
26 -s)
27 single="$1"; shift;;
28 -*)
29 printf '%s\n' "$USAGE" >&2
30 exit 1;;
32 ranges="$ranges $arg"; rangecnt=$(( $rangecnt + 1 ));;
33 esac
34 done
37 ensure_clean_tree
38 ensure_ident_available
40 ## Perform import
42 get_commit_msg()
44 commit="$1"
45 headers=""
46 ! header="$(git config topgit.to)" || headers="$headers%nTo: $header"
47 ! header="$(git config topgit.cc)" || headers="$headers%nCc: $header"
48 ! header="$(git config topgit.bcc)" || headers="$headers%nBcc: $header"
49 git --no-pager log -1 --pretty=format:"From: %an <%ae>$headers%nSubject: [PATCH] %s%n%n%b" "$commit"
52 get_branch_name()
54 # nice sed script from git-format-patch.sh
55 commit="$1"
56 titleScript='
57 s/[^-a-z.A-Z_0-9]/-/g
58 s/\.\.\.*/\./g
59 s/\.*$//
60 s/--*/-/g
61 s/^-//
62 s/-$//
65 git --no-pager log -1 --pretty=format:"%s" "$commit" | sed -e "$titleScript"
68 origbasedep="$basedep"
69 isfirst=1
70 lasthead=
71 lastsymref=
73 process_commit()
75 commit="$1"
76 branch_name="$2"
77 info "---- Importing $commit to $branch_name"
78 lastsymref="$(git symbolic-ref --quiet HEAD)" || :
79 lasthead="$(git rev-parse --verify --quiet HEAD -- 2>/dev/null)" || :
80 tg create --quiet --no-edit "$branch_name" $basedep || die "tg create failed"
81 basedep=
82 get_commit_msg "$commit" > .topmsg
83 git add -f .topmsg .topdeps || die "git add failed"
84 if [ -n "$tgnosequester" ]; then
85 info "topgit.sequester is set to false, unadvisedly skipping sequester commit"
86 else
87 git commit -m "tg import create $branch_name" || die "git commit failed"
89 if ! git cherry-pick --no-commit "$commit"; then
90 info "The commit will also finish the import of this patch."
91 return 2
93 git -c topgit.sequester=false commit -C "$commit"
94 info "++++ Importing $commit finished"
95 isfirst=
98 if [ -n "$single" ]; then
99 process_commit $ranges "$single"
100 exit
103 handle_pick_failure()
105 # The import got stuck! Let the user fix it up.
106 info "You are in a subshell."
107 info "Please commit the cherry-pick resolution and then \`exit\`"
108 info "If you want to abort the cherry-pick,"
109 info "use \`exit 1\` to abort the tg import process at this point."
110 info "Use \`exit 2\` to skip importing this commit and continue."
111 if ! "${SHELL:-@SHELL_PATH@}" -i </dev/tty; then
112 ret=$?
113 if [ $ret -eq 2 ]; then
114 info "Ok, I will try to continue without importing this commit."
115 if [ -n "$tgnosequester" ]; then
116 git reset --hard HEAD
117 else
118 git reset --hard HEAD^
120 [ -z "$isfirst" ] || basedep="$(origbasedep)"
121 [ -z "$lasthead" ] || git update-ref --no-deref HEAD "$lasthead"
122 [ -z "$lastsymref" ] || git symbolic-ref HEAD "$lastsymref"
123 git update-ref -d "refs/$topbases/$branch_name" || :
124 git update-ref -d "refs/heads/$branch_name" || :
125 git reset --hard HEAD
126 return 0
127 else
128 info "Ok, you aborted the import operation at this point. Now, you just need"
129 info "to switch back to some sane branch using \`git$gitcdopt checkout\`."
130 exit 3
135 handle_one_commit()
137 case "$sign" in
138 '-')
139 info "Merged already: $comment"
142 if ! process_commit "$rev" "$branch_prefix$(get_branch_name "$rev")"; then
143 ret=$?
144 [ -z "$islast" ] || return $ret
145 handle_pick_failure
148 esac
151 # nice arg verification stolen from git-format-patch.sh
152 rangeidx=0
153 islast=
154 for revpair in $ranges; do
155 rangeidx=$(( $rangeidx + 1 ))
156 case "$revpair" in
157 ?*..?*)
158 rev1="$(expr "z$revpair" : 'z\(.*\)\.\.')"
159 rev2="$(expr "z$revpair" : 'z.*\.\.\(.*\)')"
162 die "Unknown range spec $revpair"
164 esac
165 git rev-parse --verify "$rev1^0" -- >/dev/null 2>&1 ||
166 die "Not a valid rev $rev1 ($revpair)"
167 git rev-parse --verify "$rev2^0" -- >/dev/null 2>&1 ||
168 die "Not a valid rev $rev2 ($revpair)"
169 git cherry -v "$rev1" "$rev2" | {
170 if read sign rev comment; then
171 while read next_sign next_rev next_comment; do
172 handle_one_commit
173 sign="$next_sign"
174 rev="$next_rev"
175 comment="$next_comment"
176 done
177 [ "$rangeidx" != "$rangecnt" ] || islast=1
178 handle_one_commit
181 test $? -eq 0
182 done
184 # vim:noet