]>
Commit | Line | Data |
---|---|---|
6912ea95 | 1 | #!/bin/sh |
0ca71b37 AP |
2 | # |
3 | # git-subtree.sh: split/join git repositories in subdirectories of this one | |
4 | # | |
b77172f8 | 5 | # Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com> |
0ca71b37 | 6 | # |
5a356977 | 7 | |
f7ee88f1 JS |
8 | if test -z "$GIT_EXEC_PATH" || ! test -f "$GIT_EXEC_PATH/git-sh-setup" || { |
9 | test "${PATH#"${GIT_EXEC_PATH}:"}" = "$PATH" && | |
10 | test ! "$GIT_EXEC_PATH" -ef "${PATH%%:*}" 2>/dev/null | |
11 | } | |
22d55074 | 12 | then |
77f37de3 | 13 | basename=${0##*[/\\]} |
22d55074 LS |
14 | echo >&2 'It looks like either your git installation or your' |
15 | echo >&2 'git-subtree installation is broken.' | |
16 | echo >&2 | |
17 | echo >&2 "Tips:" | |
18 | echo >&2 " - If \`git --exec-path\` does not print the correct path to" | |
19 | echo >&2 " your git install directory, then set the GIT_EXEC_PATH" | |
20 | echo >&2 " environment variable to the correct directory." | |
77f37de3 | 21 | echo >&2 " - Make sure that your \`$basename\` file is either in your" |
22d55074 | 22 | echo >&2 " PATH or in your git exec path (\`$(git --exec-path)\`)." |
77f37de3 JS |
23 | echo >&2 " - You should run git-subtree as \`git ${basename#git-}\`," |
24 | echo >&2 " not as \`$basename\`." >&2 | |
22d55074 LS |
25 | exit 126 |
26 | fi | |
27 | ||
0ca71b37 | 28 | OPTS_SPEC="\ |
f4f29557 | 29 | git subtree add --prefix=<prefix> <commit> |
1c3e0f00 | 30 | git subtree add --prefix=<prefix> <repository> <ref> |
13648af5 | 31 | git subtree merge --prefix=<prefix> <commit> |
6468784d | 32 | git subtree split --prefix=<prefix> [<commit>] |
1c3e0f00 | 33 | git subtree pull --prefix=<prefix> <repository> <ref> |
49470cd4 | 34 | git subtree push --prefix=<prefix> <repository> <refspec> |
0ca71b37 | 35 | -- |
d7165128 RS |
36 | h,help! show the help |
37 | q,quiet! quiet | |
38 | d,debug! show debug messages | |
6e25f79f | 39 | P,prefix= the name of the subdir to split out |
94389e7c | 40 | options for 'split' (also: 'push') |
d0eb1b14 | 41 | annotate= add a prefix to commit message of new commits |
d7165128 | 42 | b,branch!= create a new branch from the split subtree |
43a39512 | 43 | ignore-joins ignore prior --rejoin commits |
96db2c04 AP |
44 | onto= try connecting new tree to an existing one |
45 | rejoin merge the new branch back into HEAD | |
94389e7c | 46 | options for 'add' and 'merge' (also: 'pull', 'split --rejoin', and 'push --rejoin') |
8e79043c | 47 | squash merge subtree changes as a single commit |
d7165128 | 48 | m,message!= use the given message as the commit message for the merge commit |
0ca71b37 | 49 | " |
9c632ea2 | 50 | |
e9525a8a LS |
51 | indent=0 |
52 | ||
5b893f7d ÆAB |
53 | # Usage: say [MSG...] |
54 | say () { | |
55 | if test -z "$arg_quiet" | |
56 | then | |
57 | printf '%s\n' "$*" | |
58 | fi | |
59 | } | |
60 | ||
5cdae0f6 | 61 | # Usage: debug [MSG...] |
d7fd792e | 62 | debug () { |
e2b11e42 | 63 | if test -n "$arg_debug" |
6ae6a233 | 64 | then |
e9525a8a | 65 | printf "%$(($indent * 2))s%s\n" '' "$*" >&2 |
942dce55 AP |
66 | fi |
67 | } | |
68 | ||
5cdae0f6 | 69 | # Usage: progress [MSG...] |
d7fd792e | 70 | progress () { |
5b893f7d | 71 | if test -z "$arg_quiet" |
6ae6a233 | 72 | then |
534ff90d LS |
73 | if test -z "$arg_debug" |
74 | then | |
75 | # Debug mode is off. | |
76 | # | |
77 | # Print one progress line that we keep updating (use | |
78 | # "\r" to return to the beginning of the line, rather | |
79 | # than "\n" to start a new line). This only really | |
80 | # works when stderr is a terminal. | |
81 | printf "%s\r" "$*" >&2 | |
82 | else | |
83 | # Debug mode is on. The `debug` function is regularly | |
84 | # printing to stderr. | |
85 | # | |
86 | # Don't do the one-line-with-"\r" thing, because on a | |
87 | # terminal the debug output would overwrite and hide the | |
88 | # progress output. Add a "progress:" prefix to make the | |
89 | # progress output and the debug output easy to | |
90 | # distinguish. This ensures maximum readability whether | |
91 | # stderr is a terminal or a file. | |
92 | printf "progress: %s\n" "$*" >&2 | |
93 | fi | |
0ca71b37 AP |
94 | fi |
95 | } | |
96 | ||
5cdae0f6 | 97 | # Usage: assert CMD... |
d7fd792e | 98 | assert () { |
6ae6a233 DA |
99 | if ! "$@" |
100 | then | |
5626a9e2 | 101 | die "fatal: assertion failed: $*" |
2573354e AP |
102 | fi |
103 | } | |
104 | ||
2e94339f PB |
105 | # Usage: die_incompatible_opt OPTION COMMAND |
106 | die_incompatible_opt () { | |
107 | assert test "$#" = 2 | |
108 | opt="$1" | |
109 | arg_command="$2" | |
5626a9e2 | 110 | die "fatal: the '$opt' flag does not make sense with 'git subtree $arg_command'." |
2e94339f PB |
111 | } |
112 | ||
5a356977 LS |
113 | main () { |
114 | if test $# -eq 0 | |
115 | then | |
116 | set -- -h | |
117 | fi | |
9a3e3ca2 LS |
118 | set_args="$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)" |
119 | eval "$set_args" | |
5a356977 LS |
120 | . git-sh-setup |
121 | require_work_tree | |
6ae6a233 | 122 | |
9a3e3ca2 LS |
123 | # First figure out the command and whether we use --rejoin, so |
124 | # that we can provide more helpful validation when we do the | |
125 | # "real" flag parsing. | |
126 | arg_split_rejoin= | |
127 | allow_split= | |
128 | allow_addmerge= | |
129 | while test $# -gt 0 | |
130 | do | |
131 | opt="$1" | |
132 | shift | |
133 | case "$opt" in | |
134 | --annotate|-b|-P|-m|--onto) | |
135 | shift | |
136 | ;; | |
137 | --rejoin) | |
138 | arg_split_rejoin=1 | |
139 | ;; | |
140 | --no-rejoin) | |
141 | arg_split_rejoin= | |
142 | ;; | |
143 | --) | |
144 | break | |
145 | ;; | |
146 | esac | |
147 | done | |
148 | arg_command=$1 | |
149 | case "$arg_command" in | |
150 | add|merge|pull) | |
151 | allow_addmerge=1 | |
152 | ;; | |
153 | split|push) | |
154 | allow_split=1 | |
155 | allow_addmerge=$arg_split_rejoin | |
156 | ;; | |
157 | *) | |
5626a9e2 | 158 | die "fatal: unknown command '$arg_command'" |
9a3e3ca2 LS |
159 | ;; |
160 | esac | |
161 | # Reset the arguments array for "real" flag parsing. | |
162 | eval "$set_args" | |
163 | ||
164 | # Begin "real" flag parsing. | |
5b893f7d | 165 | arg_quiet= |
9a3e3ca2 LS |
166 | arg_debug= |
167 | arg_prefix= | |
168 | arg_split_branch= | |
169 | arg_split_onto= | |
170 | arg_split_ignore_joins= | |
171 | arg_split_annotate= | |
172 | arg_addmerge_squash= | |
173 | arg_addmerge_message= | |
5a356977 LS |
174 | while test $# -gt 0 |
175 | do | |
176 | opt="$1" | |
6ae6a233 | 177 | shift |
5a356977 LS |
178 | |
179 | case "$opt" in | |
180 | -q) | |
5b893f7d | 181 | arg_quiet=1 |
5a356977 LS |
182 | ;; |
183 | -d) | |
e2b11e42 | 184 | arg_debug=1 |
5a356977 LS |
185 | ;; |
186 | --annotate) | |
2e94339f | 187 | test -n "$allow_split" || die_incompatible_opt "$opt" "$arg_command" |
e2b11e42 | 188 | arg_split_annotate="$1" |
5a356977 LS |
189 | shift |
190 | ;; | |
191 | --no-annotate) | |
2e94339f | 192 | test -n "$allow_split" || die_incompatible_opt "$opt" "$arg_command" |
e2b11e42 | 193 | arg_split_annotate= |
5a356977 LS |
194 | ;; |
195 | -b) | |
2e94339f | 196 | test -n "$allow_split" || die_incompatible_opt "$opt" "$arg_command" |
e2b11e42 | 197 | arg_split_branch="$1" |
5a356977 LS |
198 | shift |
199 | ;; | |
200 | -P) | |
e2b11e42 | 201 | arg_prefix="${1%/}" |
5a356977 LS |
202 | shift |
203 | ;; | |
204 | -m) | |
2e94339f | 205 | test -n "$allow_addmerge" || die_incompatible_opt "$opt" "$arg_command" |
e2b11e42 | 206 | arg_addmerge_message="$1" |
5a356977 LS |
207 | shift |
208 | ;; | |
209 | --no-prefix) | |
e2b11e42 | 210 | arg_prefix= |
5a356977 LS |
211 | ;; |
212 | --onto) | |
2e94339f | 213 | test -n "$allow_split" || die_incompatible_opt "$opt" "$arg_command" |
e2b11e42 | 214 | arg_split_onto="$1" |
5a356977 LS |
215 | shift |
216 | ;; | |
217 | --no-onto) | |
2e94339f | 218 | test -n "$allow_split" || die_incompatible_opt "$opt" "$arg_command" |
e2b11e42 | 219 | arg_split_onto= |
5a356977 LS |
220 | ;; |
221 | --rejoin) | |
2e94339f | 222 | test -n "$allow_split" || die_incompatible_opt "$opt" "$arg_command" |
5a356977 LS |
223 | ;; |
224 | --no-rejoin) | |
2e94339f | 225 | test -n "$allow_split" || die_incompatible_opt "$opt" "$arg_command" |
5a356977 LS |
226 | ;; |
227 | --ignore-joins) | |
2e94339f | 228 | test -n "$allow_split" || die_incompatible_opt "$opt" "$arg_command" |
e2b11e42 | 229 | arg_split_ignore_joins=1 |
5a356977 LS |
230 | ;; |
231 | --no-ignore-joins) | |
2e94339f | 232 | test -n "$allow_split" || die_incompatible_opt "$opt" "$arg_command" |
e2b11e42 | 233 | arg_split_ignore_joins= |
5a356977 LS |
234 | ;; |
235 | --squash) | |
2e94339f | 236 | test -n "$allow_addmerge" || die_incompatible_opt "$opt" "$arg_command" |
e2b11e42 | 237 | arg_addmerge_squash=1 |
5a356977 LS |
238 | ;; |
239 | --no-squash) | |
2e94339f | 240 | test -n "$allow_addmerge" || die_incompatible_opt "$opt" "$arg_command" |
e2b11e42 | 241 | arg_addmerge_squash= |
5a356977 LS |
242 | ;; |
243 | --) | |
244 | break | |
245 | ;; | |
246 | *) | |
5626a9e2 | 247 | die "fatal: unexpected option: $opt" |
5a356977 LS |
248 | ;; |
249 | esac | |
250 | done | |
5a356977 LS |
251 | shift |
252 | ||
e2b11e42 | 253 | if test -z "$arg_prefix" |
5a356977 | 254 | then |
5626a9e2 | 255 | die "fatal: you must provide the --prefix option." |
5a356977 LS |
256 | fi |
257 | ||
e2b11e42 | 258 | case "$arg_command" in |
5a356977 | 259 | add) |
e2b11e42 | 260 | test -e "$arg_prefix" && |
5626a9e2 | 261 | die "fatal: prefix '$arg_prefix' already exists." |
6ae6a233 DA |
262 | ;; |
263 | *) | |
e2b11e42 | 264 | test -e "$arg_prefix" || |
5626a9e2 | 265 | die "fatal: '$arg_prefix' does not exist; use 'git subtree add'" |
6ae6a233 | 266 | ;; |
0ca71b37 | 267 | esac |
5a356977 | 268 | |
e2b11e42 | 269 | dir="$(dirname "$arg_prefix/.")" |
5a356977 | 270 | |
e2b11e42 | 271 | debug "command: {$arg_command}" |
5b893f7d | 272 | debug "quiet: {$arg_quiet}" |
5a356977 LS |
273 | debug "dir: {$dir}" |
274 | debug "opts: {$*}" | |
275 | debug | |
276 | ||
e2b11e42 | 277 | "cmd_$arg_command" "$@" |
5a356977 | 278 | } |
0ca71b37 | 279 | |
5cdae0f6 | 280 | # Usage: cache_setup |
d7fd792e | 281 | cache_setup () { |
5cdae0f6 | 282 | assert test $# = 0 |
2573354e | 283 | cachedir="$GIT_DIR/subtree-cache/$$" |
6ae6a233 | 284 | rm -rf "$cachedir" || |
5626a9e2 | 285 | die "fatal: can't delete old cachedir: $cachedir" |
6ae6a233 | 286 | mkdir -p "$cachedir" || |
5626a9e2 | 287 | die "fatal: can't create new cachedir: $cachedir" |
6ae6a233 | 288 | mkdir -p "$cachedir/notree" || |
5626a9e2 | 289 | die "fatal: can't create new cachedir: $cachedir/notree" |
0ca71b37 | 290 | debug "Using cachedir: $cachedir" >&2 |
0ca71b37 AP |
291 | } |
292 | ||
5cdae0f6 | 293 | # Usage: cache_get [REVS...] |
d7fd792e | 294 | cache_get () { |
6ae6a233 DA |
295 | for oldrev in "$@" |
296 | do | |
297 | if test -r "$cachedir/$oldrev" | |
298 | then | |
0ca71b37 AP |
299 | read newrev <"$cachedir/$oldrev" |
300 | echo $newrev | |
301 | fi | |
302 | done | |
303 | } | |
304 | ||
5cdae0f6 | 305 | # Usage: cache_miss [REVS...] |
d7fd792e | 306 | cache_miss () { |
6ae6a233 DA |
307 | for oldrev in "$@" |
308 | do | |
309 | if ! test -r "$cachedir/$oldrev" | |
310 | then | |
915b9894 JG |
311 | echo $oldrev |
312 | fi | |
313 | done | |
314 | } | |
315 | ||
3ce8888f | 316 | # Usage: check_parents [REVS...] |
d7fd792e | 317 | check_parents () { |
3ce8888f | 318 | missed=$(cache_miss "$@") || exit $? |
e9525a8a | 319 | local indent=$(($indent + 1)) |
6ae6a233 DA |
320 | for miss in $missed |
321 | do | |
322 | if ! test -r "$cachedir/notree/$miss" | |
323 | then | |
e9525a8a LS |
324 | debug "incorrect order: $miss" |
325 | process_split_commit "$miss" "" | |
915b9894 JG |
326 | fi |
327 | done | |
328 | } | |
329 | ||
5cdae0f6 | 330 | # Usage: set_notree REV |
d7fd792e | 331 | set_notree () { |
5cdae0f6 | 332 | assert test $# = 1 |
915b9894 JG |
333 | echo "1" > "$cachedir/notree/$1" |
334 | } | |
335 | ||
5cdae0f6 | 336 | # Usage: cache_set OLDREV NEWREV |
d7fd792e | 337 | cache_set () { |
5cdae0f6 | 338 | assert test $# = 2 |
0ca71b37 AP |
339 | oldrev="$1" |
340 | newrev="$2" | |
6ae6a233 DA |
341 | if test "$oldrev" != "latest_old" && |
342 | test "$oldrev" != "latest_new" && | |
343 | test -e "$cachedir/$oldrev" | |
344 | then | |
5626a9e2 | 345 | die "fatal: cache for $oldrev already exists!" |
0ca71b37 AP |
346 | fi |
347 | echo "$newrev" >"$cachedir/$oldrev" | |
348 | } | |
349 | ||
5cdae0f6 | 350 | # Usage: rev_exists REV |
d7fd792e | 351 | rev_exists () { |
5cdae0f6 | 352 | assert test $# = 1 |
6ae6a233 DA |
353 | if git rev-parse "$1" >/dev/null 2>&1 |
354 | then | |
43a39512 AP |
355 | return 0 |
356 | else | |
357 | return 1 | |
358 | fi | |
359 | } | |
360 | ||
5cdae0f6 LS |
361 | # Usage: try_remove_previous REV |
362 | # | |
363 | # If a commit doesn't have a parent, this might not work. But we only want | |
b9de5353 AP |
364 | # to remove the parent from the rev-list, and since it doesn't exist, it won't |
365 | # be there anyway, so do nothing in that case. | |
d7fd792e | 366 | try_remove_previous () { |
5cdae0f6 | 367 | assert test $# = 1 |
6ae6a233 DA |
368 | if rev_exists "$1^" |
369 | then | |
b9de5353 AP |
370 | echo "^$1^" |
371 | fi | |
372 | } | |
373 | ||
0d330673 | 374 | # Usage: process_subtree_split_trailer SPLIT_HASH MAIN_HASH [REPOSITORY] |
f10d31cf | 375 | process_subtree_split_trailer () { |
88983946 PS |
376 | assert test $# -ge 2 |
377 | assert test $# -le 3 | |
f10d31cf PB |
378 | b="$1" |
379 | sq="$2" | |
0d330673 PB |
380 | repository="" |
381 | if test "$#" = 3 | |
382 | then | |
383 | repository="$3" | |
384 | fi | |
385 | fail_msg="fatal: could not rev-parse split hash $b from commit $sq" | |
386 | if ! sub="$(git rev-parse --verify --quiet "$b^{commit}")" | |
387 | then | |
388 | # if 'repository' was given, try to fetch the 'git-subtree-split' hash | |
389 | # before 'rev-parse'-ing it again, as it might be a tag that we do not have locally | |
390 | if test -n "${repository}" | |
391 | then | |
392 | git fetch "$repository" "$b" | |
393 | sub="$(git rev-parse --verify --quiet "$b^{commit}")" || | |
394 | die "$fail_msg" | |
395 | else | |
396 | hint1=$(printf "hint: hash might be a tag, try fetching it from the subtree repository:") | |
397 | hint2=$(printf "hint: git fetch <subtree-repository> $b") | |
398 | fail_msg=$(printf "$fail_msg\n$hint1\n$hint2") | |
399 | die "$fail_msg" | |
400 | fi | |
401 | fi | |
f10d31cf PB |
402 | } |
403 | ||
0d330673 | 404 | # Usage: find_latest_squash DIR [REPOSITORY] |
d7fd792e | 405 | find_latest_squash () { |
88983946 PS |
406 | assert test $# -ge 1 |
407 | assert test $# -le 2 | |
34ab458c | 408 | dir="$1" |
0d330673 PB |
409 | repository="" |
410 | if test "$#" = 2 | |
411 | then | |
412 | repository="$2" | |
413 | fi | |
414 | debug "Looking for latest squash (dir=$dir, repository=$repository)..." | |
e9525a8a LS |
415 | local indent=$(($indent + 1)) |
416 | ||
d713e2d8 AP |
417 | sq= |
418 | main= | |
419 | sub= | |
6f2012cd | 420 | git log --grep="^git-subtree-dir: $dir/*\$" \ |
8841b522 | 421 | --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' HEAD | |
6ae6a233 DA |
422 | while read a b junk |
423 | do | |
d713e2d8 AP |
424 | debug "$a $b $junk" |
425 | debug "{{$sq/$main/$sub}}" | |
1cc2cfff | 426 | case "$a" in |
6ae6a233 DA |
427 | START) |
428 | sq="$b" | |
429 | ;; | |
430 | git-subtree-mainline:) | |
431 | main="$b" | |
432 | ;; | |
433 | git-subtree-split:) | |
0d330673 | 434 | process_subtree_split_trailer "$b" "$sq" "$repository" |
6ae6a233 DA |
435 | ;; |
436 | END) | |
437 | if test -n "$sub" | |
438 | then | |
439 | if test -n "$main" | |
440 | then | |
441 | # a rejoin commit? | |
442 | # Pretend its sub was a squash. | |
cb655144 LS |
443 | sq=$(git rev-parse --verify "$sq^2") || |
444 | die | |
1cc2cfff | 445 | fi |
6ae6a233 DA |
446 | debug "Squash found: $sq $sub" |
447 | echo "$sq" "$sub" | |
448 | break | |
449 | fi | |
450 | sq= | |
451 | main= | |
452 | sub= | |
453 | ;; | |
1cc2cfff | 454 | esac |
d2f0f819 | 455 | done || exit $? |
1cc2cfff AP |
456 | } |
457 | ||
1762382a | 458 | # Usage: find_existing_splits DIR REV [REPOSITORY] |
d7fd792e | 459 | find_existing_splits () { |
88983946 PS |
460 | assert test $# -ge 2 |
461 | assert test $# -le 3 | |
8b4a77f2 | 462 | debug "Looking for prior splits..." |
e9525a8a LS |
463 | local indent=$(($indent + 1)) |
464 | ||
8b4a77f2 | 465 | dir="$1" |
5cdae0f6 | 466 | rev="$2" |
1762382a PB |
467 | repository="" |
468 | if test "$#" = 3 | |
469 | then | |
470 | repository="$3" | |
471 | fi | |
d713e2d8 AP |
472 | main= |
473 | sub= | |
dd21d43b | 474 | local grep_format="^git-subtree-dir: $dir/*\$" |
e2b11e42 | 475 | if test -n "$arg_split_ignore_joins" |
dd21d43b SR |
476 | then |
477 | grep_format="^Add '$dir/' from commit '" | |
478 | fi | |
479 | git log --grep="$grep_format" \ | |
5cdae0f6 | 480 | --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' "$rev" | |
6ae6a233 DA |
481 | while read a b junk |
482 | do | |
8b4a77f2 | 483 | case "$a" in |
6ae6a233 DA |
484 | START) |
485 | sq="$b" | |
486 | ;; | |
487 | git-subtree-mainline:) | |
488 | main="$b" | |
489 | ;; | |
490 | git-subtree-split:) | |
1762382a | 491 | process_subtree_split_trailer "$b" "$sq" "$repository" |
6ae6a233 DA |
492 | ;; |
493 | END) | |
e9525a8a | 494 | debug "Main is: '$main'" |
13420028 | 495 | if test -z "$main" && test -n "$sub" |
6ae6a233 DA |
496 | then |
497 | # squash commits refer to a subtree | |
498 | debug " Squash: $sq from $sub" | |
499 | cache_set "$sq" "$sub" | |
500 | fi | |
13420028 | 501 | if test -n "$main" && test -n "$sub" |
6ae6a233 DA |
502 | then |
503 | debug " Prior: $main -> $sub" | |
504 | cache_set $main $sub | |
505 | cache_set $sub $sub | |
506 | try_remove_previous "$main" | |
507 | try_remove_previous "$sub" | |
508 | fi | |
509 | main= | |
510 | sub= | |
511 | ;; | |
8b4a77f2 | 512 | esac |
d2f0f819 | 513 | done || exit $? |
8b4a77f2 AP |
514 | } |
515 | ||
5cdae0f6 | 516 | # Usage: copy_commit REV TREE FLAGS_STR |
d7fd792e | 517 | copy_commit () { |
5cdae0f6 | 518 | assert test $# = 3 |
f96bc790 | 519 | # We're going to set some environment vars here, so |
fd9500ee | 520 | # do it in a subshell to get rid of them safely later |
a64f3a72 | 521 | debug copy_commit "{$1}" "{$2}" "{$3}" |
8841b522 | 522 | git log -1 --no-show-signature --pretty=format:'%an%n%ae%n%aD%n%cn%n%ce%n%cD%n%B' "$1" | |
fd9500ee AP |
523 | ( |
524 | read GIT_AUTHOR_NAME | |
525 | read GIT_AUTHOR_EMAIL | |
526 | read GIT_AUTHOR_DATE | |
527 | read GIT_COMMITTER_NAME | |
528 | read GIT_COMMITTER_EMAIL | |
529 | read GIT_COMMITTER_DATE | |
b77172f8 AP |
530 | export GIT_AUTHOR_NAME \ |
531 | GIT_AUTHOR_EMAIL \ | |
532 | GIT_AUTHOR_DATE \ | |
533 | GIT_COMMITTER_NAME \ | |
534 | GIT_COMMITTER_EMAIL \ | |
535 | GIT_COMMITTER_DATE | |
6ae6a233 | 536 | ( |
e2b11e42 | 537 | printf "%s" "$arg_split_annotate" |
6ae6a233 DA |
538 | cat |
539 | ) | | |
fd9500ee | 540 | git commit-tree "$2" $3 # reads the rest of stdin |
5626a9e2 | 541 | ) || die "fatal: can't copy commit $1" |
fd9500ee AP |
542 | } |
543 | ||
5cdae0f6 | 544 | # Usage: add_msg DIR LATEST_OLD LATEST_NEW |
d7fd792e | 545 | add_msg () { |
5cdae0f6 | 546 | assert test $# = 3 |
eb7b590c AP |
547 | dir="$1" |
548 | latest_old="$2" | |
549 | latest_new="$3" | |
e2b11e42 | 550 | if test -n "$arg_addmerge_message" |
6ae6a233 | 551 | then |
e2b11e42 | 552 | commit_message="$arg_addmerge_message" |
2da0969a JS |
553 | else |
554 | commit_message="Add '$dir/' from commit '$latest_new'" | |
555 | fi | |
cb655144 LS |
556 | if test -n "$arg_split_rejoin" |
557 | then | |
558 | # If this is from a --rejoin, then rejoin_msg has | |
559 | # already inserted the `git-subtree-xxx:` tags | |
560 | echo "$commit_message" | |
561 | return | |
562 | fi | |
eb7b590c | 563 | cat <<-EOF |
2da0969a | 564 | $commit_message |
6ae6a233 | 565 | |
eb7b590c AP |
566 | git-subtree-dir: $dir |
567 | git-subtree-mainline: $latest_old | |
568 | git-subtree-split: $latest_new | |
569 | EOF | |
570 | } | |
571 | ||
5cdae0f6 | 572 | # Usage: add_squashed_msg REV DIR |
d7fd792e | 573 | add_squashed_msg () { |
5cdae0f6 | 574 | assert test $# = 2 |
e2b11e42 | 575 | if test -n "$arg_addmerge_message" |
6ae6a233 | 576 | then |
e2b11e42 | 577 | echo "$arg_addmerge_message" |
2da0969a JS |
578 | else |
579 | echo "Merge commit '$1' as '$2'" | |
580 | fi | |
581 | } | |
582 | ||
5cdae0f6 | 583 | # Usage: rejoin_msg DIR LATEST_OLD LATEST_NEW |
d7fd792e | 584 | rejoin_msg () { |
5cdae0f6 | 585 | assert test $# = 3 |
b77172f8 AP |
586 | dir="$1" |
587 | latest_old="$2" | |
588 | latest_new="$3" | |
e2b11e42 | 589 | if test -n "$arg_addmerge_message" |
6ae6a233 | 590 | then |
e2b11e42 | 591 | commit_message="$arg_addmerge_message" |
2da0969a JS |
592 | else |
593 | commit_message="Split '$dir/' into commit '$latest_new'" | |
594 | fi | |
b77172f8 | 595 | cat <<-EOF |
12629161 | 596 | $commit_message |
6ae6a233 | 597 | |
b77172f8 | 598 | git-subtree-dir: $dir |
8b4a77f2 AP |
599 | git-subtree-mainline: $latest_old |
600 | git-subtree-split: $latest_new | |
b77172f8 AP |
601 | EOF |
602 | } | |
603 | ||
5cdae0f6 | 604 | # Usage: squash_msg DIR OLD_SUBTREE_COMMIT NEW_SUBTREE_COMMIT |
d7fd792e | 605 | squash_msg () { |
5cdae0f6 | 606 | assert test $# = 3 |
1cc2cfff AP |
607 | dir="$1" |
608 | oldsub="$2" | |
609 | newsub="$3" | |
1cc2cfff | 610 | newsub_short=$(git rev-parse --short "$newsub") |
6ae6a233 DA |
611 | |
612 | if test -n "$oldsub" | |
613 | then | |
d713e2d8 AP |
614 | oldsub_short=$(git rev-parse --short "$oldsub") |
615 | echo "Squashed '$dir/' changes from $oldsub_short..$newsub_short" | |
616 | echo | |
8841b522 SG |
617 | git log --no-show-signature --pretty=tformat:'%h %s' "$oldsub..$newsub" |
618 | git log --no-show-signature --pretty=tformat:'REVERT: %h %s' "$newsub..$oldsub" | |
d713e2d8 AP |
619 | else |
620 | echo "Squashed '$dir/' content from commit $newsub_short" | |
621 | fi | |
6ae6a233 | 622 | |
d713e2d8 AP |
623 | echo |
624 | echo "git-subtree-dir: $dir" | |
625 | echo "git-subtree-split: $newsub" | |
1cc2cfff AP |
626 | } |
627 | ||
5cdae0f6 | 628 | # Usage: toptree_for_commit COMMIT |
d7fd792e | 629 | toptree_for_commit () { |
5cdae0f6 | 630 | assert test $# = 1 |
210d0839 | 631 | commit="$1" |
8841b522 | 632 | git rev-parse --verify "$commit^{tree}" || exit $? |
210d0839 AP |
633 | } |
634 | ||
5cdae0f6 | 635 | # Usage: subtree_for_commit COMMIT DIR |
d7fd792e | 636 | subtree_for_commit () { |
5cdae0f6 | 637 | assert test $# = 2 |
210d0839 AP |
638 | commit="$1" |
639 | dir="$2" | |
640 | git ls-tree "$commit" -- "$dir" | | |
6ae6a233 DA |
641 | while read mode type tree name |
642 | do | |
643 | assert test "$name" = "$dir" | |
47c39c28 PS |
644 | |
645 | case "$type" in | |
646 | commit) | |
647 | continue;; # ignore submodules | |
648 | tree) | |
649 | echo $tree | |
650 | break;; | |
651 | *) | |
652 | die "fatal: tree entry is of type ${type}, expected tree or commit";; | |
653 | esac | |
d2f0f819 | 654 | done || exit $? |
768d6d10 AP |
655 | } |
656 | ||
5cdae0f6 | 657 | # Usage: tree_changed TREE [PARENTS...] |
d7fd792e | 658 | tree_changed () { |
5cdae0f6 | 659 | assert test $# -gt 0 |
768d6d10 AP |
660 | tree=$1 |
661 | shift | |
6ae6a233 DA |
662 | if test $# -ne 1 |
663 | then | |
768d6d10 AP |
664 | return 0 # weird parents, consider it changed |
665 | else | |
d2f0f819 | 666 | ptree=$(toptree_for_commit $1) || exit $? |
6ae6a233 DA |
667 | if test "$ptree" != "$tree" |
668 | then | |
768d6d10 AP |
669 | return 0 # changed |
670 | else | |
671 | return 1 # not changed | |
672 | fi | |
673 | fi | |
674 | } | |
675 | ||
5cdae0f6 | 676 | # Usage: new_squash_commit OLD_SQUASHED_COMMIT OLD_NONSQUASHED_COMMIT NEW_NONSQUASHED_COMMIT |
d7fd792e | 677 | new_squash_commit () { |
5cdae0f6 | 678 | assert test $# = 3 |
1cc2cfff AP |
679 | old="$1" |
680 | oldsub="$2" | |
681 | newsub="$3" | |
682 | tree=$(toptree_for_commit $newsub) || exit $? | |
6ae6a233 DA |
683 | if test -n "$old" |
684 | then | |
685 | squash_msg "$dir" "$oldsub" "$newsub" | | |
686 | git commit-tree "$tree" -p "$old" || exit $? | |
d713e2d8 AP |
687 | else |
688 | squash_msg "$dir" "" "$newsub" | | |
6ae6a233 | 689 | git commit-tree "$tree" || exit $? |
d713e2d8 | 690 | fi |
1cc2cfff AP |
691 | } |
692 | ||
5cdae0f6 | 693 | # Usage: copy_or_skip REV TREE NEWPARENTS |
d7fd792e | 694 | copy_or_skip () { |
5cdae0f6 | 695 | assert test $# = 3 |
d6912658 AP |
696 | rev="$1" |
697 | tree="$2" | |
698 | newparents="$3" | |
6ae6a233 | 699 | assert test -n "$tree" |
d6912658 | 700 | |
96db2c04 | 701 | identical= |
49cf8228 | 702 | nonidentical= |
96db2c04 | 703 | p= |
a64f3a72 | 704 | gotparents= |
68f8ff81 | 705 | copycommit= |
6ae6a233 DA |
706 | for parent in $newparents |
707 | do | |
d6912658 | 708 | ptree=$(toptree_for_commit $parent) || exit $? |
6ae6a233 DA |
709 | test -z "$ptree" && continue |
710 | if test "$ptree" = "$tree" | |
711 | then | |
96db2c04 | 712 | # an identical parent could be used in place of this rev. |
68f8ff81 SR |
713 | if test -n "$identical" |
714 | then | |
715 | # if a previous identical parent was found, check whether | |
716 | # one is already an ancestor of the other | |
717 | mergebase=$(git merge-base $identical $parent) | |
718 | if test "$identical" = "$mergebase" | |
719 | then | |
720 | # current identical commit is an ancestor of parent | |
721 | identical="$parent" | |
722 | elif test "$parent" != "$mergebase" | |
723 | then | |
724 | # no common history; commit must be copied | |
725 | copycommit=1 | |
726 | fi | |
727 | else | |
728 | # first identical parent detected | |
729 | identical="$parent" | |
730 | fi | |
49cf8228 AP |
731 | else |
732 | nonidentical="$parent" | |
96db2c04 | 733 | fi |
6ae6a233 | 734 | |
a64f3a72 AP |
735 | # sometimes both old parents map to the same newparent; |
736 | # eliminate duplicates | |
737 | is_new=1 | |
6ae6a233 DA |
738 | for gp in $gotparents |
739 | do | |
740 | if test "$gp" = "$parent" | |
741 | then | |
a64f3a72 AP |
742 | is_new= |
743 | break | |
744 | fi | |
745 | done | |
6ae6a233 DA |
746 | if test -n "$is_new" |
747 | then | |
a64f3a72 | 748 | gotparents="$gotparents $parent" |
d6912658 AP |
749 | p="$p -p $parent" |
750 | fi | |
751 | done | |
933cfeb9 | 752 | |
6ae6a233 DA |
753 | if test -n "$identical" && test -n "$nonidentical" |
754 | then | |
933cfeb9 | 755 | extras=$(git rev-list --count $identical..$nonidentical) |
6ae6a233 DA |
756 | if test "$extras" -ne 0 |
757 | then | |
933cfeb9 DW |
758 | # we need to preserve history along the other branch |
759 | copycommit=1 | |
760 | fi | |
761 | fi | |
6ae6a233 DA |
762 | if test -n "$identical" && test -z "$copycommit" |
763 | then | |
96db2c04 AP |
764 | echo $identical |
765 | else | |
6ae6a233 | 766 | copy_commit "$rev" "$tree" "$p" || exit $? |
96db2c04 | 767 | fi |
d6912658 AP |
768 | } |
769 | ||
5cdae0f6 | 770 | # Usage: ensure_clean |
d7fd792e | 771 | ensure_clean () { |
5cdae0f6 | 772 | assert test $# = 0 |
6ae6a233 DA |
773 | if ! git diff-index HEAD --exit-code --quiet 2>&1 |
774 | then | |
5626a9e2 | 775 | die "fatal: working tree has modifications. Cannot add." |
eb7b590c | 776 | fi |
6ae6a233 DA |
777 | if ! git diff-index --cached HEAD --exit-code --quiet 2>&1 |
778 | then | |
5626a9e2 | 779 | die "fatal: index has modifications. Cannot add." |
eb7b590c | 780 | fi |
13648af5 AP |
781 | } |
782 | ||
5cdae0f6 | 783 | # Usage: ensure_valid_ref_format REF |
d7fd792e | 784 | ensure_valid_ref_format () { |
5cdae0f6 | 785 | assert test $# = 1 |
1c3e0f00 | 786 | git check-ref-format "refs/heads/$1" || |
5626a9e2 | 787 | die "fatal: '$1' does not look like a ref" |
1c3e0f00 AB |
788 | } |
789 | ||
e9525a8a | 790 | # Usage: process_split_commit REV PARENTS |
565e4b79 | 791 | process_split_commit () { |
e9525a8a | 792 | assert test $# = 2 |
565e4b79 SR |
793 | local rev="$1" |
794 | local parents="$2" | |
315a84f9 SR |
795 | |
796 | if test $indent -eq 0 | |
797 | then | |
798 | revcount=$(($revcount + 1)) | |
799 | else | |
800 | # processing commit without normal parent information; | |
801 | # fetch from repo | |
19ad68d9 | 802 | parents=$(git rev-parse "$rev^@") |
315a84f9 SR |
803 | extracount=$(($extracount + 1)) |
804 | fi | |
805 | ||
806 | progress "$revcount/$revmax ($createcount) [$extracount]" | |
807 | ||
565e4b79 | 808 | debug "Processing commit: $rev" |
e9525a8a | 809 | local indent=$(($indent + 1)) |
d2f0f819 | 810 | exists=$(cache_get "$rev") || exit $? |
565e4b79 SR |
811 | if test -n "$exists" |
812 | then | |
e9525a8a | 813 | debug "prior: $exists" |
565e4b79 SR |
814 | return |
815 | fi | |
816 | createcount=$(($createcount + 1)) | |
e9525a8a | 817 | debug "parents: $parents" |
3ce8888f | 818 | check_parents $parents |
d2f0f819 | 819 | newparents=$(cache_get $parents) || exit $? |
e9525a8a | 820 | debug "newparents: $newparents" |
565e4b79 | 821 | |
d2f0f819 | 822 | tree=$(subtree_for_commit "$rev" "$dir") || exit $? |
e9525a8a | 823 | debug "tree is: $tree" |
565e4b79 | 824 | |
565e4b79 SR |
825 | # ugly. is there no better way to tell if this is a subtree |
826 | # vs. a mainline commit? Does it matter? | |
827 | if test -z "$tree" | |
828 | then | |
829 | set_notree "$rev" | |
830 | if test -n "$newparents" | |
831 | then | |
832 | cache_set "$rev" "$rev" | |
833 | fi | |
834 | return | |
835 | fi | |
836 | ||
837 | newrev=$(copy_or_skip "$rev" "$tree" "$newparents") || exit $? | |
e9525a8a | 838 | debug "newrev is: $newrev" |
565e4b79 SR |
839 | cache_set "$rev" "$newrev" |
840 | cache_set latest_new "$newrev" | |
841 | cache_set latest_old "$rev" | |
842 | } | |
843 | ||
5cdae0f6 LS |
844 | # Usage: cmd_add REV |
845 | # Or: cmd_add REPOSITORY REF | |
d7fd792e | 846 | cmd_add () { |
c00d1d11 | 847 | |
13648af5 | 848 | ensure_clean |
6ae6a233 DA |
849 | |
850 | if test $# -eq 1 | |
851 | then | |
852 | git rev-parse -q --verify "$1^{commit}" >/dev/null || | |
5626a9e2 | 853 | die "fatal: '$1' does not refer to a commit" |
6ae6a233 DA |
854 | |
855 | cmd_add_commit "$@" | |
856 | ||
857 | elif test $# -eq 2 | |
858 | then | |
859 | # Technically we could accept a refspec here but we're | |
860 | # just going to turn around and add FETCH_HEAD under the | |
861 | # specified directory. Allowing a refspec might be | |
862 | # misleading because we won't do anything with any other | |
863 | # branches fetched via the refspec. | |
864 | ensure_valid_ref_format "$2" | |
865 | ||
866 | cmd_add_repository "$@" | |
c00d1d11 | 867 | else |
5626a9e2 | 868 | say >&2 "fatal: parameters were '$*'" |
6ae6a233 | 869 | die "Provide either a commit or a repository and commit." |
eb7b590c | 870 | fi |
c00d1d11 WW |
871 | } |
872 | ||
5cdae0f6 | 873 | # Usage: cmd_add_repository REPOSITORY REFSPEC |
d7fd792e | 874 | cmd_add_repository () { |
5cdae0f6 | 875 | assert test $# = 2 |
c00d1d11 WW |
876 | echo "git fetch" "$@" |
877 | repository=$1 | |
878 | refspec=$2 | |
879 | git fetch "$@" || exit $? | |
e4f8baa8 | 880 | cmd_add_commit FETCH_HEAD |
c00d1d11 WW |
881 | } |
882 | ||
5cdae0f6 | 883 | # Usage: cmd_add_commit REV |
d7fd792e | 884 | cmd_add_commit () { |
e4f8baa8 LS |
885 | # The rev has already been validated by cmd_add(), we just |
886 | # need to normalize it. | |
5cdae0f6 | 887 | assert test $# = 1 |
e4f8baa8 | 888 | rev=$(git rev-parse --verify "$1^{commit}") || exit $? |
6ae6a233 | 889 | |
eb7b590c | 890 | debug "Adding $dir as '$rev'..." |
cb655144 LS |
891 | if test -z "$arg_split_rejoin" |
892 | then | |
893 | # Only bother doing this if this is a genuine 'add', | |
894 | # not a synthetic 'add' from '--rejoin'. | |
895 | git read-tree --prefix="$dir" $rev || exit $? | |
896 | fi | |
227f7811 | 897 | git checkout -- "$dir" || exit $? |
eb7b590c | 898 | tree=$(git write-tree) || exit $? |
6ae6a233 | 899 | |
a50fcc13 | 900 | headrev=$(git rev-parse --verify HEAD) || exit $? |
6ae6a233 DA |
901 | if test -n "$headrev" && test "$headrev" != "$rev" |
902 | then | |
eb7b590c AP |
903 | headp="-p $headrev" |
904 | else | |
905 | headp= | |
906 | fi | |
6ae6a233 | 907 | |
e2b11e42 | 908 | if test -n "$arg_addmerge_squash" |
6ae6a233 | 909 | then |
d713e2d8 | 910 | rev=$(new_squash_commit "" "" "$rev") || exit $? |
2da0969a | 911 | commit=$(add_squashed_msg "$rev" "$dir" | |
6ae6a233 | 912 | git commit-tree "$tree" $headp -p "$rev") || exit $? |
d713e2d8 | 913 | else |
d2f0f819 | 914 | revp=$(peel_committish "$rev") || exit $? |
6ae6a233 DA |
915 | commit=$(add_msg "$dir" $headrev "$rev" | |
916 | git commit-tree "$tree" $headp -p "$revp") || exit $? | |
d713e2d8 | 917 | fi |
eb7b590c | 918 | git reset "$commit" || exit $? |
6ae6a233 | 919 | |
6d43585a | 920 | say >&2 "Added dir '$dir'" |
eb7b590c AP |
921 | } |
922 | ||
1762382a | 923 | # Usage: cmd_split [REV] [REPOSITORY] |
d7fd792e | 924 | cmd_split () { |
e4f8baa8 LS |
925 | if test $# -eq 0 |
926 | then | |
927 | rev=$(git rev-parse HEAD) | |
88983946 | 928 | elif test $# -eq 1 || test $# -eq 2 |
e4f8baa8 LS |
929 | then |
930 | rev=$(git rev-parse -q --verify "$1^{commit}") || | |
5626a9e2 | 931 | die "fatal: '$1' does not refer to a commit" |
e4f8baa8 | 932 | else |
1762382a PB |
933 | die "fatal: you must provide exactly one revision, and optionnally a repository. Got: '$*'" |
934 | fi | |
935 | repository="" | |
936 | if test "$#" = 2 | |
937 | then | |
938 | repository="$2" | |
e4f8baa8 LS |
939 | fi |
940 | ||
cb655144 LS |
941 | if test -n "$arg_split_rejoin" |
942 | then | |
943 | ensure_clean | |
944 | fi | |
945 | ||
0ca71b37 AP |
946 | debug "Splitting $dir..." |
947 | cache_setup || exit $? | |
6ae6a233 | 948 | |
e2b11e42 | 949 | if test -n "$arg_split_onto" |
6ae6a233 | 950 | then |
e2b11e42 LS |
951 | debug "Reading history for --onto=$arg_split_onto..." |
952 | git rev-list $arg_split_onto | | |
6ae6a233 DA |
953 | while read rev |
954 | do | |
33ff583a AP |
955 | # the 'onto' history is already just the subdir, so |
956 | # any parent we find there can be used verbatim | |
e9525a8a | 957 | debug "cache: $rev" |
6ae6a233 | 958 | cache_set "$rev" "$rev" |
d2f0f819 | 959 | done || exit $? |
33ff583a | 960 | fi |
6ae6a233 | 961 | |
1762382a | 962 | unrevs="$(find_existing_splits "$dir" "$rev" "$repository")" || exit $? |
6ae6a233 | 963 | |
1f73862f AP |
964 | # We can't restrict rev-list to only $dir here, because some of our |
965 | # parents have the $dir contents the root, and those won't match. | |
966 | # (and rev-list --follow doesn't seem to solve this) | |
e4f8baa8 | 967 | grl='git rev-list --topo-order --reverse --parents $rev $unrevs' |
942dce55 AP |
968 | revmax=$(eval "$grl" | wc -l) |
969 | revcount=0 | |
970 | createcount=0 | |
315a84f9 | 971 | extracount=0 |
942dce55 | 972 | eval "$grl" | |
6ae6a233 DA |
973 | while read rev parents |
974 | do | |
e9525a8a | 975 | process_split_commit "$rev" "$parents" |
2573354e | 976 | done || exit $? |
6ae6a233 | 977 | |
d2f0f819 | 978 | latest_new=$(cache_get latest_new) || exit $? |
6ae6a233 DA |
979 | if test -z "$latest_new" |
980 | then | |
5626a9e2 | 981 | die "fatal: no new revisions were found" |
e25a6bf8 | 982 | fi |
6ae6a233 | 983 | |
e2b11e42 | 984 | if test -n "$arg_split_rejoin" |
6ae6a233 | 985 | then |
b77172f8 | 986 | debug "Merging split branch into HEAD..." |
d2f0f819 | 987 | latest_old=$(cache_get latest_old) || exit $? |
cb655144 LS |
988 | arg_addmerge_message="$(rejoin_msg "$dir" "$latest_old" "$latest_new")" || exit $? |
989 | if test -z "$(find_latest_squash "$dir")" | |
990 | then | |
991 | cmd_add "$latest_new" >&2 || exit $? | |
992 | else | |
993 | cmd_merge "$latest_new" >&2 || exit $? | |
994 | fi | |
6ae6a233 | 995 | fi |
e2b11e42 | 996 | if test -n "$arg_split_branch" |
6ae6a233 | 997 | then |
e2b11e42 | 998 | if rev_exists "refs/heads/$arg_split_branch" |
6ae6a233 | 999 | then |
e2b11e42 | 1000 | if ! git merge-base --is-ancestor "$arg_split_branch" "$latest_new" |
6ae6a233 | 1001 | then |
5626a9e2 | 1002 | die "fatal: branch '$arg_split_branch' is not an ancestor of commit '$latest_new'." |
0a562948 JS |
1003 | fi |
1004 | action='Updated' | |
1005 | else | |
1006 | action='Created' | |
1007 | fi | |
6ae6a233 | 1008 | git update-ref -m 'subtree split' \ |
e2b11e42 LS |
1009 | "refs/heads/$arg_split_branch" "$latest_new" || exit $? |
1010 | say >&2 "$action branch '$arg_split_branch'" | |
43a39512 | 1011 | fi |
6ae6a233 | 1012 | echo "$latest_new" |
0ca71b37 AP |
1013 | exit 0 |
1014 | } | |
1015 | ||
0d330673 | 1016 | # Usage: cmd_merge REV [REPOSITORY] |
d7fd792e | 1017 | cmd_merge () { |
88983946 PS |
1018 | if test $# -lt 1 || test $# -gt 2 |
1019 | then | |
0d330673 | 1020 | die "fatal: you must provide exactly one revision, and optionally a repository. Got: '$*'" |
88983946 PS |
1021 | fi |
1022 | ||
e4f8baa8 | 1023 | rev=$(git rev-parse -q --verify "$1^{commit}") || |
5626a9e2 | 1024 | die "fatal: '$1' does not refer to a commit" |
0d330673 PB |
1025 | repository="" |
1026 | if test "$#" = 2 | |
1027 | then | |
1028 | repository="$2" | |
1029 | fi | |
13648af5 | 1030 | ensure_clean |
6ae6a233 | 1031 | |
e2b11e42 | 1032 | if test -n "$arg_addmerge_squash" |
6ae6a233 | 1033 | then |
0d330673 | 1034 | first_split="$(find_latest_squash "$dir" "$repository")" || exit $? |
6ae6a233 DA |
1035 | if test -z "$first_split" |
1036 | then | |
5626a9e2 | 1037 | die "fatal: can't squash-merge: '$dir' was never added." |
1cc2cfff AP |
1038 | fi |
1039 | set $first_split | |
1040 | old=$1 | |
1041 | sub=$2 | |
6ae6a233 DA |
1042 | if test "$sub" = "$rev" |
1043 | then | |
6d43585a | 1044 | say >&2 "Subtree is already at commit $rev." |
eb4fb910 AP |
1045 | exit 0 |
1046 | fi | |
1cc2cfff AP |
1047 | new=$(new_squash_commit "$old" "$sub" "$rev") || exit $? |
1048 | debug "New squash commit: $new" | |
1049 | rev="$new" | |
1050 | fi | |
448e71e2 | 1051 | |
e2b11e42 | 1052 | if test -n "$arg_addmerge_message" |
6ae6a233 | 1053 | then |
9158a356 | 1054 | git merge --no-ff -Xsubtree="$arg_prefix" \ |
e2b11e42 | 1055 | --message="$arg_addmerge_message" "$rev" |
349a70d5 | 1056 | else |
9158a356 | 1057 | git merge --no-ff -Xsubtree="$arg_prefix" $rev |
349a70d5 | 1058 | fi |
13648af5 AP |
1059 | } |
1060 | ||
5cdae0f6 | 1061 | # Usage: cmd_pull REPOSITORY REMOTEREF |
d7fd792e | 1062 | cmd_pull () { |
6ae6a233 DA |
1063 | if test $# -ne 2 |
1064 | then | |
5626a9e2 | 1065 | die "fatal: you must provide <repository> <ref>" |
1c3e0f00 | 1066 | fi |
7990142e PB |
1067 | repository="$1" |
1068 | ref="$2" | |
13648af5 | 1069 | ensure_clean |
7990142e PB |
1070 | ensure_valid_ref_format "$ref" |
1071 | git fetch "$repository" "$ref" || exit $? | |
0d330673 | 1072 | cmd_merge FETCH_HEAD "$repository" |
c00d1d11 WW |
1073 | } |
1074 | ||
49470cd4 | 1075 | # Usage: cmd_push REPOSITORY [+][LOCALREV:]REMOTEREF |
d7fd792e | 1076 | cmd_push () { |
6ae6a233 DA |
1077 | if test $# -ne 2 |
1078 | then | |
5626a9e2 | 1079 | die "fatal: you must provide <repository> <refspec>" |
c00d1d11 | 1080 | fi |
6ae6a233 DA |
1081 | if test -e "$dir" |
1082 | then | |
1083 | repository=$1 | |
49470cd4 LS |
1084 | refspec=${2#+} |
1085 | remoteref=${refspec#*:} | |
1086 | if test "$remoteref" = "$refspec" | |
1087 | then | |
1088 | localrevname_presplit=HEAD | |
1089 | else | |
1090 | localrevname_presplit=${refspec%%:*} | |
1091 | fi | |
1092 | ensure_valid_ref_format "$remoteref" | |
1093 | localrev_presplit=$(git rev-parse -q --verify "$localrevname_presplit^{commit}") || | |
5626a9e2 | 1094 | die "fatal: '$localrevname_presplit' does not refer to a commit" |
49470cd4 | 1095 | |
6ae6a233 | 1096 | echo "git push using: " "$repository" "$refspec" |
1762382a | 1097 | localrev=$(cmd_split "$localrev_presplit" "$repository") || die |
49470cd4 | 1098 | git push "$repository" "$localrev":"refs/heads/$remoteref" |
c00d1d11 | 1099 | else |
5626a9e2 | 1100 | die "fatal: '$dir' must already exist. Try 'git subtree add'." |
c00d1d11 | 1101 | fi |
0ca71b37 AP |
1102 | } |
1103 | ||
5a356977 | 1104 | main "$@" |