]>
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 () { |
0d330673 | 376 | assert test $# = 2 -o $# = 3 |
f10d31cf PB |
377 | b="$1" |
378 | sq="$2" | |
0d330673 PB |
379 | repository="" |
380 | if test "$#" = 3 | |
381 | then | |
382 | repository="$3" | |
383 | fi | |
384 | fail_msg="fatal: could not rev-parse split hash $b from commit $sq" | |
385 | if ! sub="$(git rev-parse --verify --quiet "$b^{commit}")" | |
386 | then | |
387 | # if 'repository' was given, try to fetch the 'git-subtree-split' hash | |
388 | # before 'rev-parse'-ing it again, as it might be a tag that we do not have locally | |
389 | if test -n "${repository}" | |
390 | then | |
391 | git fetch "$repository" "$b" | |
392 | sub="$(git rev-parse --verify --quiet "$b^{commit}")" || | |
393 | die "$fail_msg" | |
394 | else | |
395 | hint1=$(printf "hint: hash might be a tag, try fetching it from the subtree repository:") | |
396 | hint2=$(printf "hint: git fetch <subtree-repository> $b") | |
397 | fail_msg=$(printf "$fail_msg\n$hint1\n$hint2") | |
398 | die "$fail_msg" | |
399 | fi | |
400 | fi | |
f10d31cf PB |
401 | } |
402 | ||
0d330673 | 403 | # Usage: find_latest_squash DIR [REPOSITORY] |
d7fd792e | 404 | find_latest_squash () { |
0d330673 | 405 | assert test $# = 1 -o $# = 2 |
34ab458c | 406 | dir="$1" |
0d330673 PB |
407 | repository="" |
408 | if test "$#" = 2 | |
409 | then | |
410 | repository="$2" | |
411 | fi | |
412 | debug "Looking for latest squash (dir=$dir, repository=$repository)..." | |
e9525a8a LS |
413 | local indent=$(($indent + 1)) |
414 | ||
d713e2d8 AP |
415 | sq= |
416 | main= | |
417 | sub= | |
6f2012cd | 418 | git log --grep="^git-subtree-dir: $dir/*\$" \ |
8841b522 | 419 | --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' HEAD | |
6ae6a233 DA |
420 | while read a b junk |
421 | do | |
d713e2d8 AP |
422 | debug "$a $b $junk" |
423 | debug "{{$sq/$main/$sub}}" | |
1cc2cfff | 424 | case "$a" in |
6ae6a233 DA |
425 | START) |
426 | sq="$b" | |
427 | ;; | |
428 | git-subtree-mainline:) | |
429 | main="$b" | |
430 | ;; | |
431 | git-subtree-split:) | |
0d330673 | 432 | process_subtree_split_trailer "$b" "$sq" "$repository" |
6ae6a233 DA |
433 | ;; |
434 | END) | |
435 | if test -n "$sub" | |
436 | then | |
437 | if test -n "$main" | |
438 | then | |
439 | # a rejoin commit? | |
440 | # Pretend its sub was a squash. | |
cb655144 LS |
441 | sq=$(git rev-parse --verify "$sq^2") || |
442 | die | |
1cc2cfff | 443 | fi |
6ae6a233 DA |
444 | debug "Squash found: $sq $sub" |
445 | echo "$sq" "$sub" | |
446 | break | |
447 | fi | |
448 | sq= | |
449 | main= | |
450 | sub= | |
451 | ;; | |
1cc2cfff | 452 | esac |
d2f0f819 | 453 | done || exit $? |
1cc2cfff AP |
454 | } |
455 | ||
1762382a | 456 | # Usage: find_existing_splits DIR REV [REPOSITORY] |
d7fd792e | 457 | find_existing_splits () { |
1762382a | 458 | assert test $# = 2 -o $# = 3 |
8b4a77f2 | 459 | debug "Looking for prior splits..." |
e9525a8a LS |
460 | local indent=$(($indent + 1)) |
461 | ||
8b4a77f2 | 462 | dir="$1" |
5cdae0f6 | 463 | rev="$2" |
1762382a PB |
464 | repository="" |
465 | if test "$#" = 3 | |
466 | then | |
467 | repository="$3" | |
468 | fi | |
d713e2d8 AP |
469 | main= |
470 | sub= | |
dd21d43b | 471 | local grep_format="^git-subtree-dir: $dir/*\$" |
e2b11e42 | 472 | if test -n "$arg_split_ignore_joins" |
dd21d43b SR |
473 | then |
474 | grep_format="^Add '$dir/' from commit '" | |
475 | fi | |
476 | git log --grep="$grep_format" \ | |
5cdae0f6 | 477 | --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' "$rev" | |
6ae6a233 DA |
478 | while read a b junk |
479 | do | |
8b4a77f2 | 480 | case "$a" in |
6ae6a233 DA |
481 | START) |
482 | sq="$b" | |
483 | ;; | |
484 | git-subtree-mainline:) | |
485 | main="$b" | |
486 | ;; | |
487 | git-subtree-split:) | |
1762382a | 488 | process_subtree_split_trailer "$b" "$sq" "$repository" |
6ae6a233 DA |
489 | ;; |
490 | END) | |
e9525a8a | 491 | debug "Main is: '$main'" |
6ae6a233 DA |
492 | if test -z "$main" -a -n "$sub" |
493 | then | |
494 | # squash commits refer to a subtree | |
495 | debug " Squash: $sq from $sub" | |
496 | cache_set "$sq" "$sub" | |
497 | fi | |
498 | if test -n "$main" -a -n "$sub" | |
499 | then | |
500 | debug " Prior: $main -> $sub" | |
501 | cache_set $main $sub | |
502 | cache_set $sub $sub | |
503 | try_remove_previous "$main" | |
504 | try_remove_previous "$sub" | |
505 | fi | |
506 | main= | |
507 | sub= | |
508 | ;; | |
8b4a77f2 | 509 | esac |
d2f0f819 | 510 | done || exit $? |
8b4a77f2 AP |
511 | } |
512 | ||
5cdae0f6 | 513 | # Usage: copy_commit REV TREE FLAGS_STR |
d7fd792e | 514 | copy_commit () { |
5cdae0f6 | 515 | assert test $# = 3 |
f96bc790 | 516 | # We're going to set some environment vars here, so |
fd9500ee | 517 | # do it in a subshell to get rid of them safely later |
a64f3a72 | 518 | debug copy_commit "{$1}" "{$2}" "{$3}" |
8841b522 | 519 | git log -1 --no-show-signature --pretty=format:'%an%n%ae%n%aD%n%cn%n%ce%n%cD%n%B' "$1" | |
fd9500ee AP |
520 | ( |
521 | read GIT_AUTHOR_NAME | |
522 | read GIT_AUTHOR_EMAIL | |
523 | read GIT_AUTHOR_DATE | |
524 | read GIT_COMMITTER_NAME | |
525 | read GIT_COMMITTER_EMAIL | |
526 | read GIT_COMMITTER_DATE | |
b77172f8 AP |
527 | export GIT_AUTHOR_NAME \ |
528 | GIT_AUTHOR_EMAIL \ | |
529 | GIT_AUTHOR_DATE \ | |
530 | GIT_COMMITTER_NAME \ | |
531 | GIT_COMMITTER_EMAIL \ | |
532 | GIT_COMMITTER_DATE | |
6ae6a233 | 533 | ( |
e2b11e42 | 534 | printf "%s" "$arg_split_annotate" |
6ae6a233 DA |
535 | cat |
536 | ) | | |
fd9500ee | 537 | git commit-tree "$2" $3 # reads the rest of stdin |
5626a9e2 | 538 | ) || die "fatal: can't copy commit $1" |
fd9500ee AP |
539 | } |
540 | ||
5cdae0f6 | 541 | # Usage: add_msg DIR LATEST_OLD LATEST_NEW |
d7fd792e | 542 | add_msg () { |
5cdae0f6 | 543 | assert test $# = 3 |
eb7b590c AP |
544 | dir="$1" |
545 | latest_old="$2" | |
546 | latest_new="$3" | |
e2b11e42 | 547 | if test -n "$arg_addmerge_message" |
6ae6a233 | 548 | then |
e2b11e42 | 549 | commit_message="$arg_addmerge_message" |
2da0969a JS |
550 | else |
551 | commit_message="Add '$dir/' from commit '$latest_new'" | |
552 | fi | |
cb655144 LS |
553 | if test -n "$arg_split_rejoin" |
554 | then | |
555 | # If this is from a --rejoin, then rejoin_msg has | |
556 | # already inserted the `git-subtree-xxx:` tags | |
557 | echo "$commit_message" | |
558 | return | |
559 | fi | |
eb7b590c | 560 | cat <<-EOF |
2da0969a | 561 | $commit_message |
6ae6a233 | 562 | |
eb7b590c AP |
563 | git-subtree-dir: $dir |
564 | git-subtree-mainline: $latest_old | |
565 | git-subtree-split: $latest_new | |
566 | EOF | |
567 | } | |
568 | ||
5cdae0f6 | 569 | # Usage: add_squashed_msg REV DIR |
d7fd792e | 570 | add_squashed_msg () { |
5cdae0f6 | 571 | assert test $# = 2 |
e2b11e42 | 572 | if test -n "$arg_addmerge_message" |
6ae6a233 | 573 | then |
e2b11e42 | 574 | echo "$arg_addmerge_message" |
2da0969a JS |
575 | else |
576 | echo "Merge commit '$1' as '$2'" | |
577 | fi | |
578 | } | |
579 | ||
5cdae0f6 | 580 | # Usage: rejoin_msg DIR LATEST_OLD LATEST_NEW |
d7fd792e | 581 | rejoin_msg () { |
5cdae0f6 | 582 | assert test $# = 3 |
b77172f8 AP |
583 | dir="$1" |
584 | latest_old="$2" | |
585 | latest_new="$3" | |
e2b11e42 | 586 | if test -n "$arg_addmerge_message" |
6ae6a233 | 587 | then |
e2b11e42 | 588 | commit_message="$arg_addmerge_message" |
2da0969a JS |
589 | else |
590 | commit_message="Split '$dir/' into commit '$latest_new'" | |
591 | fi | |
b77172f8 | 592 | cat <<-EOF |
12629161 | 593 | $commit_message |
6ae6a233 | 594 | |
b77172f8 | 595 | git-subtree-dir: $dir |
8b4a77f2 AP |
596 | git-subtree-mainline: $latest_old |
597 | git-subtree-split: $latest_new | |
b77172f8 AP |
598 | EOF |
599 | } | |
600 | ||
5cdae0f6 | 601 | # Usage: squash_msg DIR OLD_SUBTREE_COMMIT NEW_SUBTREE_COMMIT |
d7fd792e | 602 | squash_msg () { |
5cdae0f6 | 603 | assert test $# = 3 |
1cc2cfff AP |
604 | dir="$1" |
605 | oldsub="$2" | |
606 | newsub="$3" | |
1cc2cfff | 607 | newsub_short=$(git rev-parse --short "$newsub") |
6ae6a233 DA |
608 | |
609 | if test -n "$oldsub" | |
610 | then | |
d713e2d8 AP |
611 | oldsub_short=$(git rev-parse --short "$oldsub") |
612 | echo "Squashed '$dir/' changes from $oldsub_short..$newsub_short" | |
613 | echo | |
8841b522 SG |
614 | git log --no-show-signature --pretty=tformat:'%h %s' "$oldsub..$newsub" |
615 | git log --no-show-signature --pretty=tformat:'REVERT: %h %s' "$newsub..$oldsub" | |
d713e2d8 AP |
616 | else |
617 | echo "Squashed '$dir/' content from commit $newsub_short" | |
618 | fi | |
6ae6a233 | 619 | |
d713e2d8 AP |
620 | echo |
621 | echo "git-subtree-dir: $dir" | |
622 | echo "git-subtree-split: $newsub" | |
1cc2cfff AP |
623 | } |
624 | ||
5cdae0f6 | 625 | # Usage: toptree_for_commit COMMIT |
d7fd792e | 626 | toptree_for_commit () { |
5cdae0f6 | 627 | assert test $# = 1 |
210d0839 | 628 | commit="$1" |
8841b522 | 629 | git rev-parse --verify "$commit^{tree}" || exit $? |
210d0839 AP |
630 | } |
631 | ||
5cdae0f6 | 632 | # Usage: subtree_for_commit COMMIT DIR |
d7fd792e | 633 | subtree_for_commit () { |
5cdae0f6 | 634 | assert test $# = 2 |
210d0839 AP |
635 | commit="$1" |
636 | dir="$2" | |
637 | git ls-tree "$commit" -- "$dir" | | |
6ae6a233 DA |
638 | while read mode type tree name |
639 | do | |
640 | assert test "$name" = "$dir" | |
641 | assert test "$type" = "tree" -o "$type" = "commit" | |
642 | test "$type" = "commit" && continue # ignore submodules | |
768d6d10 AP |
643 | echo $tree |
644 | break | |
d2f0f819 | 645 | done || exit $? |
768d6d10 AP |
646 | } |
647 | ||
5cdae0f6 | 648 | # Usage: tree_changed TREE [PARENTS...] |
d7fd792e | 649 | tree_changed () { |
5cdae0f6 | 650 | assert test $# -gt 0 |
768d6d10 AP |
651 | tree=$1 |
652 | shift | |
6ae6a233 DA |
653 | if test $# -ne 1 |
654 | then | |
768d6d10 AP |
655 | return 0 # weird parents, consider it changed |
656 | else | |
d2f0f819 | 657 | ptree=$(toptree_for_commit $1) || exit $? |
6ae6a233 DA |
658 | if test "$ptree" != "$tree" |
659 | then | |
768d6d10 AP |
660 | return 0 # changed |
661 | else | |
662 | return 1 # not changed | |
663 | fi | |
664 | fi | |
665 | } | |
666 | ||
5cdae0f6 | 667 | # Usage: new_squash_commit OLD_SQUASHED_COMMIT OLD_NONSQUASHED_COMMIT NEW_NONSQUASHED_COMMIT |
d7fd792e | 668 | new_squash_commit () { |
5cdae0f6 | 669 | assert test $# = 3 |
1cc2cfff AP |
670 | old="$1" |
671 | oldsub="$2" | |
672 | newsub="$3" | |
673 | tree=$(toptree_for_commit $newsub) || exit $? | |
6ae6a233 DA |
674 | if test -n "$old" |
675 | then | |
676 | squash_msg "$dir" "$oldsub" "$newsub" | | |
677 | git commit-tree "$tree" -p "$old" || exit $? | |
d713e2d8 AP |
678 | else |
679 | squash_msg "$dir" "" "$newsub" | | |
6ae6a233 | 680 | git commit-tree "$tree" || exit $? |
d713e2d8 | 681 | fi |
1cc2cfff AP |
682 | } |
683 | ||
5cdae0f6 | 684 | # Usage: copy_or_skip REV TREE NEWPARENTS |
d7fd792e | 685 | copy_or_skip () { |
5cdae0f6 | 686 | assert test $# = 3 |
d6912658 AP |
687 | rev="$1" |
688 | tree="$2" | |
689 | newparents="$3" | |
6ae6a233 | 690 | assert test -n "$tree" |
d6912658 | 691 | |
96db2c04 | 692 | identical= |
49cf8228 | 693 | nonidentical= |
96db2c04 | 694 | p= |
a64f3a72 | 695 | gotparents= |
68f8ff81 | 696 | copycommit= |
6ae6a233 DA |
697 | for parent in $newparents |
698 | do | |
d6912658 | 699 | ptree=$(toptree_for_commit $parent) || exit $? |
6ae6a233 DA |
700 | test -z "$ptree" && continue |
701 | if test "$ptree" = "$tree" | |
702 | then | |
96db2c04 | 703 | # an identical parent could be used in place of this rev. |
68f8ff81 SR |
704 | if test -n "$identical" |
705 | then | |
706 | # if a previous identical parent was found, check whether | |
707 | # one is already an ancestor of the other | |
708 | mergebase=$(git merge-base $identical $parent) | |
709 | if test "$identical" = "$mergebase" | |
710 | then | |
711 | # current identical commit is an ancestor of parent | |
712 | identical="$parent" | |
713 | elif test "$parent" != "$mergebase" | |
714 | then | |
715 | # no common history; commit must be copied | |
716 | copycommit=1 | |
717 | fi | |
718 | else | |
719 | # first identical parent detected | |
720 | identical="$parent" | |
721 | fi | |
49cf8228 AP |
722 | else |
723 | nonidentical="$parent" | |
96db2c04 | 724 | fi |
6ae6a233 | 725 | |
a64f3a72 AP |
726 | # sometimes both old parents map to the same newparent; |
727 | # eliminate duplicates | |
728 | is_new=1 | |
6ae6a233 DA |
729 | for gp in $gotparents |
730 | do | |
731 | if test "$gp" = "$parent" | |
732 | then | |
a64f3a72 AP |
733 | is_new= |
734 | break | |
735 | fi | |
736 | done | |
6ae6a233 DA |
737 | if test -n "$is_new" |
738 | then | |
a64f3a72 | 739 | gotparents="$gotparents $parent" |
d6912658 AP |
740 | p="$p -p $parent" |
741 | fi | |
742 | done | |
933cfeb9 | 743 | |
6ae6a233 DA |
744 | if test -n "$identical" && test -n "$nonidentical" |
745 | then | |
933cfeb9 | 746 | extras=$(git rev-list --count $identical..$nonidentical) |
6ae6a233 DA |
747 | if test "$extras" -ne 0 |
748 | then | |
933cfeb9 DW |
749 | # we need to preserve history along the other branch |
750 | copycommit=1 | |
751 | fi | |
752 | fi | |
6ae6a233 DA |
753 | if test -n "$identical" && test -z "$copycommit" |
754 | then | |
96db2c04 AP |
755 | echo $identical |
756 | else | |
6ae6a233 | 757 | copy_commit "$rev" "$tree" "$p" || exit $? |
96db2c04 | 758 | fi |
d6912658 AP |
759 | } |
760 | ||
5cdae0f6 | 761 | # Usage: ensure_clean |
d7fd792e | 762 | ensure_clean () { |
5cdae0f6 | 763 | assert test $# = 0 |
6ae6a233 DA |
764 | if ! git diff-index HEAD --exit-code --quiet 2>&1 |
765 | then | |
5626a9e2 | 766 | die "fatal: working tree has modifications. Cannot add." |
eb7b590c | 767 | fi |
6ae6a233 DA |
768 | if ! git diff-index --cached HEAD --exit-code --quiet 2>&1 |
769 | then | |
5626a9e2 | 770 | die "fatal: index has modifications. Cannot add." |
eb7b590c | 771 | fi |
13648af5 AP |
772 | } |
773 | ||
5cdae0f6 | 774 | # Usage: ensure_valid_ref_format REF |
d7fd792e | 775 | ensure_valid_ref_format () { |
5cdae0f6 | 776 | assert test $# = 1 |
1c3e0f00 | 777 | git check-ref-format "refs/heads/$1" || |
5626a9e2 | 778 | die "fatal: '$1' does not look like a ref" |
1c3e0f00 AB |
779 | } |
780 | ||
e9525a8a | 781 | # Usage: process_split_commit REV PARENTS |
565e4b79 | 782 | process_split_commit () { |
e9525a8a | 783 | assert test $# = 2 |
565e4b79 SR |
784 | local rev="$1" |
785 | local parents="$2" | |
315a84f9 SR |
786 | |
787 | if test $indent -eq 0 | |
788 | then | |
789 | revcount=$(($revcount + 1)) | |
790 | else | |
791 | # processing commit without normal parent information; | |
792 | # fetch from repo | |
19ad68d9 | 793 | parents=$(git rev-parse "$rev^@") |
315a84f9 SR |
794 | extracount=$(($extracount + 1)) |
795 | fi | |
796 | ||
797 | progress "$revcount/$revmax ($createcount) [$extracount]" | |
798 | ||
565e4b79 | 799 | debug "Processing commit: $rev" |
e9525a8a | 800 | local indent=$(($indent + 1)) |
d2f0f819 | 801 | exists=$(cache_get "$rev") || exit $? |
565e4b79 SR |
802 | if test -n "$exists" |
803 | then | |
e9525a8a | 804 | debug "prior: $exists" |
565e4b79 SR |
805 | return |
806 | fi | |
807 | createcount=$(($createcount + 1)) | |
e9525a8a | 808 | debug "parents: $parents" |
3ce8888f | 809 | check_parents $parents |
d2f0f819 | 810 | newparents=$(cache_get $parents) || exit $? |
e9525a8a | 811 | debug "newparents: $newparents" |
565e4b79 | 812 | |
d2f0f819 | 813 | tree=$(subtree_for_commit "$rev" "$dir") || exit $? |
e9525a8a | 814 | debug "tree is: $tree" |
565e4b79 | 815 | |
565e4b79 SR |
816 | # ugly. is there no better way to tell if this is a subtree |
817 | # vs. a mainline commit? Does it matter? | |
818 | if test -z "$tree" | |
819 | then | |
820 | set_notree "$rev" | |
821 | if test -n "$newparents" | |
822 | then | |
823 | cache_set "$rev" "$rev" | |
824 | fi | |
825 | return | |
826 | fi | |
827 | ||
828 | newrev=$(copy_or_skip "$rev" "$tree" "$newparents") || exit $? | |
e9525a8a | 829 | debug "newrev is: $newrev" |
565e4b79 SR |
830 | cache_set "$rev" "$newrev" |
831 | cache_set latest_new "$newrev" | |
832 | cache_set latest_old "$rev" | |
833 | } | |
834 | ||
5cdae0f6 LS |
835 | # Usage: cmd_add REV |
836 | # Or: cmd_add REPOSITORY REF | |
d7fd792e | 837 | cmd_add () { |
c00d1d11 | 838 | |
13648af5 | 839 | ensure_clean |
6ae6a233 DA |
840 | |
841 | if test $# -eq 1 | |
842 | then | |
843 | git rev-parse -q --verify "$1^{commit}" >/dev/null || | |
5626a9e2 | 844 | die "fatal: '$1' does not refer to a commit" |
6ae6a233 DA |
845 | |
846 | cmd_add_commit "$@" | |
847 | ||
848 | elif test $# -eq 2 | |
849 | then | |
850 | # Technically we could accept a refspec here but we're | |
851 | # just going to turn around and add FETCH_HEAD under the | |
852 | # specified directory. Allowing a refspec might be | |
853 | # misleading because we won't do anything with any other | |
854 | # branches fetched via the refspec. | |
855 | ensure_valid_ref_format "$2" | |
856 | ||
857 | cmd_add_repository "$@" | |
c00d1d11 | 858 | else |
5626a9e2 | 859 | say >&2 "fatal: parameters were '$*'" |
6ae6a233 | 860 | die "Provide either a commit or a repository and commit." |
eb7b590c | 861 | fi |
c00d1d11 WW |
862 | } |
863 | ||
5cdae0f6 | 864 | # Usage: cmd_add_repository REPOSITORY REFSPEC |
d7fd792e | 865 | cmd_add_repository () { |
5cdae0f6 | 866 | assert test $# = 2 |
c00d1d11 WW |
867 | echo "git fetch" "$@" |
868 | repository=$1 | |
869 | refspec=$2 | |
870 | git fetch "$@" || exit $? | |
e4f8baa8 | 871 | cmd_add_commit FETCH_HEAD |
c00d1d11 WW |
872 | } |
873 | ||
5cdae0f6 | 874 | # Usage: cmd_add_commit REV |
d7fd792e | 875 | cmd_add_commit () { |
e4f8baa8 LS |
876 | # The rev has already been validated by cmd_add(), we just |
877 | # need to normalize it. | |
5cdae0f6 | 878 | assert test $# = 1 |
e4f8baa8 | 879 | rev=$(git rev-parse --verify "$1^{commit}") || exit $? |
6ae6a233 | 880 | |
eb7b590c | 881 | debug "Adding $dir as '$rev'..." |
cb655144 LS |
882 | if test -z "$arg_split_rejoin" |
883 | then | |
884 | # Only bother doing this if this is a genuine 'add', | |
885 | # not a synthetic 'add' from '--rejoin'. | |
886 | git read-tree --prefix="$dir" $rev || exit $? | |
887 | fi | |
227f7811 | 888 | git checkout -- "$dir" || exit $? |
eb7b590c | 889 | tree=$(git write-tree) || exit $? |
6ae6a233 | 890 | |
a50fcc13 | 891 | headrev=$(git rev-parse --verify HEAD) || exit $? |
6ae6a233 DA |
892 | if test -n "$headrev" && test "$headrev" != "$rev" |
893 | then | |
eb7b590c AP |
894 | headp="-p $headrev" |
895 | else | |
896 | headp= | |
897 | fi | |
6ae6a233 | 898 | |
e2b11e42 | 899 | if test -n "$arg_addmerge_squash" |
6ae6a233 | 900 | then |
d713e2d8 | 901 | rev=$(new_squash_commit "" "" "$rev") || exit $? |
2da0969a | 902 | commit=$(add_squashed_msg "$rev" "$dir" | |
6ae6a233 | 903 | git commit-tree "$tree" $headp -p "$rev") || exit $? |
d713e2d8 | 904 | else |
d2f0f819 | 905 | revp=$(peel_committish "$rev") || exit $? |
6ae6a233 DA |
906 | commit=$(add_msg "$dir" $headrev "$rev" | |
907 | git commit-tree "$tree" $headp -p "$revp") || exit $? | |
d713e2d8 | 908 | fi |
eb7b590c | 909 | git reset "$commit" || exit $? |
6ae6a233 | 910 | |
6d43585a | 911 | say >&2 "Added dir '$dir'" |
eb7b590c AP |
912 | } |
913 | ||
1762382a | 914 | # Usage: cmd_split [REV] [REPOSITORY] |
d7fd792e | 915 | cmd_split () { |
e4f8baa8 LS |
916 | if test $# -eq 0 |
917 | then | |
918 | rev=$(git rev-parse HEAD) | |
1762382a | 919 | elif test $# -eq 1 -o $# -eq 2 |
e4f8baa8 LS |
920 | then |
921 | rev=$(git rev-parse -q --verify "$1^{commit}") || | |
5626a9e2 | 922 | die "fatal: '$1' does not refer to a commit" |
e4f8baa8 | 923 | else |
1762382a PB |
924 | die "fatal: you must provide exactly one revision, and optionnally a repository. Got: '$*'" |
925 | fi | |
926 | repository="" | |
927 | if test "$#" = 2 | |
928 | then | |
929 | repository="$2" | |
e4f8baa8 LS |
930 | fi |
931 | ||
cb655144 LS |
932 | if test -n "$arg_split_rejoin" |
933 | then | |
934 | ensure_clean | |
935 | fi | |
936 | ||
0ca71b37 AP |
937 | debug "Splitting $dir..." |
938 | cache_setup || exit $? | |
6ae6a233 | 939 | |
e2b11e42 | 940 | if test -n "$arg_split_onto" |
6ae6a233 | 941 | then |
e2b11e42 LS |
942 | debug "Reading history for --onto=$arg_split_onto..." |
943 | git rev-list $arg_split_onto | | |
6ae6a233 DA |
944 | while read rev |
945 | do | |
33ff583a AP |
946 | # the 'onto' history is already just the subdir, so |
947 | # any parent we find there can be used verbatim | |
e9525a8a | 948 | debug "cache: $rev" |
6ae6a233 | 949 | cache_set "$rev" "$rev" |
d2f0f819 | 950 | done || exit $? |
33ff583a | 951 | fi |
6ae6a233 | 952 | |
1762382a | 953 | unrevs="$(find_existing_splits "$dir" "$rev" "$repository")" || exit $? |
6ae6a233 | 954 | |
1f73862f AP |
955 | # We can't restrict rev-list to only $dir here, because some of our |
956 | # parents have the $dir contents the root, and those won't match. | |
957 | # (and rev-list --follow doesn't seem to solve this) | |
e4f8baa8 | 958 | grl='git rev-list --topo-order --reverse --parents $rev $unrevs' |
942dce55 AP |
959 | revmax=$(eval "$grl" | wc -l) |
960 | revcount=0 | |
961 | createcount=0 | |
315a84f9 | 962 | extracount=0 |
942dce55 | 963 | eval "$grl" | |
6ae6a233 DA |
964 | while read rev parents |
965 | do | |
e9525a8a | 966 | process_split_commit "$rev" "$parents" |
2573354e | 967 | done || exit $? |
6ae6a233 | 968 | |
d2f0f819 | 969 | latest_new=$(cache_get latest_new) || exit $? |
6ae6a233 DA |
970 | if test -z "$latest_new" |
971 | then | |
5626a9e2 | 972 | die "fatal: no new revisions were found" |
e25a6bf8 | 973 | fi |
6ae6a233 | 974 | |
e2b11e42 | 975 | if test -n "$arg_split_rejoin" |
6ae6a233 | 976 | then |
b77172f8 | 977 | debug "Merging split branch into HEAD..." |
d2f0f819 | 978 | latest_old=$(cache_get latest_old) || exit $? |
cb655144 LS |
979 | arg_addmerge_message="$(rejoin_msg "$dir" "$latest_old" "$latest_new")" || exit $? |
980 | if test -z "$(find_latest_squash "$dir")" | |
981 | then | |
982 | cmd_add "$latest_new" >&2 || exit $? | |
983 | else | |
984 | cmd_merge "$latest_new" >&2 || exit $? | |
985 | fi | |
6ae6a233 | 986 | fi |
e2b11e42 | 987 | if test -n "$arg_split_branch" |
6ae6a233 | 988 | then |
e2b11e42 | 989 | if rev_exists "refs/heads/$arg_split_branch" |
6ae6a233 | 990 | then |
e2b11e42 | 991 | if ! git merge-base --is-ancestor "$arg_split_branch" "$latest_new" |
6ae6a233 | 992 | then |
5626a9e2 | 993 | die "fatal: branch '$arg_split_branch' is not an ancestor of commit '$latest_new'." |
0a562948 JS |
994 | fi |
995 | action='Updated' | |
996 | else | |
997 | action='Created' | |
998 | fi | |
6ae6a233 | 999 | git update-ref -m 'subtree split' \ |
e2b11e42 LS |
1000 | "refs/heads/$arg_split_branch" "$latest_new" || exit $? |
1001 | say >&2 "$action branch '$arg_split_branch'" | |
43a39512 | 1002 | fi |
6ae6a233 | 1003 | echo "$latest_new" |
0ca71b37 AP |
1004 | exit 0 |
1005 | } | |
1006 | ||
0d330673 | 1007 | # Usage: cmd_merge REV [REPOSITORY] |
d7fd792e | 1008 | cmd_merge () { |
0d330673 PB |
1009 | test $# -eq 1 -o $# -eq 2 || |
1010 | die "fatal: you must provide exactly one revision, and optionally a repository. Got: '$*'" | |
e4f8baa8 | 1011 | rev=$(git rev-parse -q --verify "$1^{commit}") || |
5626a9e2 | 1012 | die "fatal: '$1' does not refer to a commit" |
0d330673 PB |
1013 | repository="" |
1014 | if test "$#" = 2 | |
1015 | then | |
1016 | repository="$2" | |
1017 | fi | |
13648af5 | 1018 | ensure_clean |
6ae6a233 | 1019 | |
e2b11e42 | 1020 | if test -n "$arg_addmerge_squash" |
6ae6a233 | 1021 | then |
0d330673 | 1022 | first_split="$(find_latest_squash "$dir" "$repository")" || exit $? |
6ae6a233 DA |
1023 | if test -z "$first_split" |
1024 | then | |
5626a9e2 | 1025 | die "fatal: can't squash-merge: '$dir' was never added." |
1cc2cfff AP |
1026 | fi |
1027 | set $first_split | |
1028 | old=$1 | |
1029 | sub=$2 | |
6ae6a233 DA |
1030 | if test "$sub" = "$rev" |
1031 | then | |
6d43585a | 1032 | say >&2 "Subtree is already at commit $rev." |
eb4fb910 AP |
1033 | exit 0 |
1034 | fi | |
1cc2cfff AP |
1035 | new=$(new_squash_commit "$old" "$sub" "$rev") || exit $? |
1036 | debug "New squash commit: $new" | |
1037 | rev="$new" | |
1038 | fi | |
448e71e2 | 1039 | |
e2b11e42 | 1040 | if test -n "$arg_addmerge_message" |
6ae6a233 | 1041 | then |
9158a356 | 1042 | git merge --no-ff -Xsubtree="$arg_prefix" \ |
e2b11e42 | 1043 | --message="$arg_addmerge_message" "$rev" |
349a70d5 | 1044 | else |
9158a356 | 1045 | git merge --no-ff -Xsubtree="$arg_prefix" $rev |
349a70d5 | 1046 | fi |
13648af5 AP |
1047 | } |
1048 | ||
5cdae0f6 | 1049 | # Usage: cmd_pull REPOSITORY REMOTEREF |
d7fd792e | 1050 | cmd_pull () { |
6ae6a233 DA |
1051 | if test $# -ne 2 |
1052 | then | |
5626a9e2 | 1053 | die "fatal: you must provide <repository> <ref>" |
1c3e0f00 | 1054 | fi |
7990142e PB |
1055 | repository="$1" |
1056 | ref="$2" | |
13648af5 | 1057 | ensure_clean |
7990142e PB |
1058 | ensure_valid_ref_format "$ref" |
1059 | git fetch "$repository" "$ref" || exit $? | |
0d330673 | 1060 | cmd_merge FETCH_HEAD "$repository" |
c00d1d11 WW |
1061 | } |
1062 | ||
49470cd4 | 1063 | # Usage: cmd_push REPOSITORY [+][LOCALREV:]REMOTEREF |
d7fd792e | 1064 | cmd_push () { |
6ae6a233 DA |
1065 | if test $# -ne 2 |
1066 | then | |
5626a9e2 | 1067 | die "fatal: you must provide <repository> <refspec>" |
c00d1d11 | 1068 | fi |
6ae6a233 DA |
1069 | if test -e "$dir" |
1070 | then | |
1071 | repository=$1 | |
49470cd4 LS |
1072 | refspec=${2#+} |
1073 | remoteref=${refspec#*:} | |
1074 | if test "$remoteref" = "$refspec" | |
1075 | then | |
1076 | localrevname_presplit=HEAD | |
1077 | else | |
1078 | localrevname_presplit=${refspec%%:*} | |
1079 | fi | |
1080 | ensure_valid_ref_format "$remoteref" | |
1081 | localrev_presplit=$(git rev-parse -q --verify "$localrevname_presplit^{commit}") || | |
5626a9e2 | 1082 | die "fatal: '$localrevname_presplit' does not refer to a commit" |
49470cd4 | 1083 | |
6ae6a233 | 1084 | echo "git push using: " "$repository" "$refspec" |
1762382a | 1085 | localrev=$(cmd_split "$localrev_presplit" "$repository") || die |
49470cd4 | 1086 | git push "$repository" "$localrev":"refs/heads/$remoteref" |
c00d1d11 | 1087 | else |
5626a9e2 | 1088 | die "fatal: '$dir' must already exist. Try 'git subtree add'." |
c00d1d11 | 1089 | fi |
0ca71b37 AP |
1090 | } |
1091 | ||
5a356977 | 1092 | main "$@" |