tg: make sure we're really working with commits
[topgit/pro.git] / tg-import.sh
blobeb7bbf90abb539cbb30e48eda66f6e6e55320df3
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
39 ## Perform import
41 get_commit_msg()
43 commit="$1"
44 headers=""
45 ! header="$(git config topgit.to)" || headers="$headers%nTo: $header"
46 ! header="$(git config topgit.cc)" || headers="$headers%nCc: $header"
47 ! header="$(git config topgit.bcc)" || headers="$headers%nBcc: $header"
48 git log -1 --pretty=format:"From: %an <%ae>$headers%nSubject: [PATCH] %s%n%n%b" "$commit"
51 get_branch_name()
53 # nice sed script from git-format-patch.sh
54 commit="$1"
55 titleScript='
56 s/[^-a-z.A-Z_0-9]/-/g
57 s/\.\.\.*/\./g
58 s/\.*$//
59 s/--*/-/g
60 s/^-//
61 s/-$//
64 git log -1 --pretty=format:"%s" "$commit" | sed -e "$titleScript"
67 origbasedep="$basedep"
68 isfirst=1
69 lasthead=
70 lastsymref=
72 process_commit()
74 commit="$1"
75 branch_name="$2"
76 info "---- Importing $commit to $branch_name"
77 lastsymref="$(git symbolic-ref --quiet HEAD || :)"
78 lasthead="$(git rev-parse --verify --quiet HEAD -- 2>/dev/null || :)"
79 $tg create --no-edit "$branch_name" $basedep
80 basedep=
81 get_commit_msg "$commit" > .topmsg
82 git add -f .topmsg .topdeps
83 if [ -n "$tgnosequester" ]; then
84 info "topgit.sequester is set to false, unadvisedly skipping sequester commit"
85 else
86 git commit -m "tg import create $branch_name"
88 if ! git cherry-pick --no-commit "$commit"; then
89 info "The commit will also finish the import of this patch."
90 return 2
92 git -c topgit.sequester=false commit -C "$commit"
93 info "++++ Importing $commit finished"
94 isfirst=
97 if [ -n "$single" ]; then
98 process_commit $ranges "$single"
99 exit
102 handle_pick_failure()
104 # The import got stuck! Let the user fix it up.
105 info "You are in a subshell."
106 info "Please commit the cherry-pick resolution and then \`exit\`"
107 info "If you want to abort the cherry-pick,"
108 info "use \`exit 1\` to abort the tg import process at this point."
109 info "Use \`exit 2\` to skip importing this commit and continue."
110 if ! "${SHELL:-@SHELL_PATH@}" -i </dev/tty; then
111 ret=$?
112 if [ $ret -eq 2 ]; then
113 info "Ok, I will try to continue without importing this commit."
114 if [ -n "$tgnosequester" ]; then
115 git reset --hard HEAD
116 else
117 git reset --hard HEAD^
119 [ -z "$isfirst" ] || basedep="$(origbasedep)"
120 [ -z "$lasthead" ] || git update-ref --no-deref HEAD "$lasthead"
121 [ -z "$lastsymref" ] || git symbolic-ref HEAD "$lastsymref"
122 git update-ref -d "refs/top-bases/$branch_name" || :
123 git update-ref -d "refs/heads/$branch_name" || :
124 git reset --hard HEAD
125 return 0
126 else
127 info "Ok, you aborted the import operation at this point. Now, you just need"
128 info "to switch back to some sane branch using \`git$gitcdopt checkout\`."
129 exit 3
134 handle_one_commit()
136 case "$sign" in
137 '-')
138 info "Merged already: $comment"
141 if ! process_commit "$rev" "$branch_prefix$(get_branch_name "$rev")"; then
142 ret=$?
143 [ -z "$islast" ] || return $ret
144 handle_pick_failure
147 esac
150 # nice arg verification stolen from git-format-patch.sh
151 rangeidx=0
152 islast=
153 for revpair in $ranges; do
154 rangeidx=$(( $rangeidx + 1 ))
155 case "$revpair" in
156 ?*..?*)
157 rev1=`expr "z$revpair" : 'z\(.*\)\.\.'`
158 rev2=`expr "z$revpair" : 'z.*\.\.\(.*\)'`
161 die "Unknown range spec $revpair"
163 esac
164 git rev-parse --verify "$rev1^0" -- >/dev/null 2>&1 ||
165 die "Not a valid rev $rev1 ($revpair)"
166 git rev-parse --verify "$rev2^0" -- >/dev/null 2>&1 ||
167 die "Not a valid rev $rev2 ($revpair)"
168 git cherry -v "$rev1" "$rev2" | {
169 if read sign rev comment; then
170 while read next_sign next_rev next_comment; do
171 handle_one_commit
172 sign="$next_sign"
173 rev="$next_rev"
174 comment="$next_comment"
175 done
176 [ "$rangeidx" != "$rangecnt" ] || islast=1
177 handle_one_commit
180 done
182 # vim:noet