Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | # |
| 3 | # git-subtree.sh: split/join git repositories in subdirectories of this one |
| 4 | # |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 5 | # Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com> |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 6 | # |
Avery Pennarun | 96db2c0 | 2009-04-24 22:36:06 -0400 | [diff] [blame] | 7 | if [ $# -eq 0 ]; then |
| 8 | set -- -h |
| 9 | fi |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 10 | OPTS_SPEC="\ |
Avery Pennarun | f4f2955 | 2009-05-30 01:10:14 -0400 | [diff] [blame] | 11 | git subtree add --prefix=<prefix> <commit> |
Avery Pennarun | 13648af | 2009-04-24 23:41:19 -0400 | [diff] [blame] | 12 | git subtree merge --prefix=<prefix> <commit> |
| 13 | git subtree pull --prefix=<prefix> <repository> <refspec...> |
Wayne Walter | c00d1d1 | 2010-02-13 14:32:21 -0500 | [diff] [blame] | 14 | git subtree push --prefix=<prefix> <repository> <refspec...> |
Avery Pennarun | f4f2955 | 2009-05-30 01:10:14 -0400 | [diff] [blame] | 15 | git subtree split --prefix=<prefix> <commit...> |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 16 | -- |
Avery Pennarun | 96db2c0 | 2009-04-24 22:36:06 -0400 | [diff] [blame] | 17 | h,help show the help |
| 18 | q quiet |
Avery Pennarun | 942dce5 | 2009-04-26 18:06:08 -0400 | [diff] [blame] | 19 | d show debug messages |
Jakub Suder | 6e25f79 | 2010-01-12 22:38:21 +0100 | [diff] [blame] | 20 | P,prefix= the name of the subdir to split out |
Jakub Suder | 2da0969 | 2010-01-09 19:55:35 +0100 | [diff] [blame] | 21 | m,message= use the given message as the commit message for the merge commit |
Avery Pennarun | 13648af | 2009-04-24 23:41:19 -0400 | [diff] [blame] | 22 | options for 'split' |
Avery Pennarun | d0eb1b1 | 2009-04-26 08:59:12 -0400 | [diff] [blame] | 23 | annotate= add a prefix to commit message of new commits |
Avery Pennarun | 43a3951 | 2009-05-30 01:05:43 -0400 | [diff] [blame] | 24 | b,branch= create a new branch from the split subtree |
| 25 | ignore-joins ignore prior --rejoin commits |
Avery Pennarun | 96db2c0 | 2009-04-24 22:36:06 -0400 | [diff] [blame] | 26 | onto= try connecting new tree to an existing one |
| 27 | rejoin merge the new branch back into HEAD |
Wayne Walter | c00d1d1 | 2010-02-13 14:32:21 -0500 | [diff] [blame] | 28 | options for 'add', 'merge', 'pull' and 'push' |
Avery Pennarun | 8e79043 | 2009-05-30 00:48:07 -0400 | [diff] [blame] | 29 | squash merge subtree changes as a single commit |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 30 | " |
Cole Stanfield | 11f1511 | 2010-09-13 13:16:57 -0600 | [diff] [blame] | 31 | eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)" |
Avery Pennarun | 9c632ea | 2010-06-24 01:53:05 -0400 | [diff] [blame] | 32 | |
Avery Pennarun | df2302d | 2010-06-24 16:57:58 -0400 | [diff] [blame] | 33 | PATH=$PATH:$(git --exec-path) |
Avery Pennarun | 33aaa69 | 2009-08-26 10:41:03 -0400 | [diff] [blame] | 34 | . git-sh-setup |
Avery Pennarun | 9c632ea | 2010-06-24 01:53:05 -0400 | [diff] [blame] | 35 | |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 36 | require_work_tree |
| 37 | |
| 38 | quiet= |
Avery Pennarun | 43a3951 | 2009-05-30 01:05:43 -0400 | [diff] [blame] | 39 | branch= |
Avery Pennarun | 942dce5 | 2009-04-26 18:06:08 -0400 | [diff] [blame] | 40 | debug= |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 41 | command= |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 42 | onto= |
| 43 | rejoin= |
Avery Pennarun | 96db2c0 | 2009-04-24 22:36:06 -0400 | [diff] [blame] | 44 | ignore_joins= |
Avery Pennarun | d0eb1b1 | 2009-04-26 08:59:12 -0400 | [diff] [blame] | 45 | annotate= |
Avery Pennarun | 8e79043 | 2009-05-30 00:48:07 -0400 | [diff] [blame] | 46 | squash= |
Jakub Suder | 2da0969 | 2010-01-09 19:55:35 +0100 | [diff] [blame] | 47 | message= |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 48 | |
| 49 | debug() |
| 50 | { |
Avery Pennarun | 942dce5 | 2009-04-26 18:06:08 -0400 | [diff] [blame] | 51 | if [ -n "$debug" ]; then |
| 52 | echo "$@" >&2 |
| 53 | fi |
| 54 | } |
| 55 | |
| 56 | say() |
| 57 | { |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 58 | if [ -z "$quiet" ]; then |
| 59 | echo "$@" >&2 |
| 60 | fi |
| 61 | } |
| 62 | |
Avery Pennarun | 2573354 | 2009-04-24 14:24:38 -0400 | [diff] [blame] | 63 | assert() |
| 64 | { |
| 65 | if "$@"; then |
| 66 | : |
| 67 | else |
| 68 | die "assertion failed: " "$@" |
| 69 | fi |
| 70 | } |
| 71 | |
| 72 | |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 73 | #echo "Options: $*" |
| 74 | |
| 75 | while [ $# -gt 0 ]; do |
| 76 | opt="$1" |
| 77 | shift |
| 78 | case "$opt" in |
| 79 | -q) quiet=1 ;; |
Avery Pennarun | 942dce5 | 2009-04-26 18:06:08 -0400 | [diff] [blame] | 80 | -d) debug=1 ;; |
Avery Pennarun | d0eb1b1 | 2009-04-26 08:59:12 -0400 | [diff] [blame] | 81 | --annotate) annotate="$1"; shift ;; |
| 82 | --no-annotate) annotate= ;; |
Avery Pennarun | 43a3951 | 2009-05-30 01:05:43 -0400 | [diff] [blame] | 83 | -b) branch="$1"; shift ;; |
Jakub Suder | 6e25f79 | 2010-01-12 22:38:21 +0100 | [diff] [blame] | 84 | -P) prefix="$1"; shift ;; |
Jakub Suder | 2da0969 | 2010-01-09 19:55:35 +0100 | [diff] [blame] | 85 | -m) message="$1"; shift ;; |
Avery Pennarun | 9a8821f | 2009-04-24 22:57:14 -0400 | [diff] [blame] | 86 | --no-prefix) prefix= ;; |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 87 | --onto) onto="$1"; shift ;; |
Avery Pennarun | 96db2c0 | 2009-04-24 22:36:06 -0400 | [diff] [blame] | 88 | --no-onto) onto= ;; |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 89 | --rejoin) rejoin=1 ;; |
Avery Pennarun | 96db2c0 | 2009-04-24 22:36:06 -0400 | [diff] [blame] | 90 | --no-rejoin) rejoin= ;; |
| 91 | --ignore-joins) ignore_joins=1 ;; |
| 92 | --no-ignore-joins) ignore_joins= ;; |
Avery Pennarun | 8e79043 | 2009-05-30 00:48:07 -0400 | [diff] [blame] | 93 | --squash) squash=1 ;; |
| 94 | --no-squash) squash= ;; |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 95 | --) break ;; |
Avery Pennarun | 43a3951 | 2009-05-30 01:05:43 -0400 | [diff] [blame] | 96 | *) die "Unexpected option: $opt" ;; |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 97 | esac |
| 98 | done |
| 99 | |
| 100 | command="$1" |
| 101 | shift |
| 102 | case "$command" in |
Avery Pennarun | 13648af | 2009-04-24 23:41:19 -0400 | [diff] [blame] | 103 | add|merge|pull) default= ;; |
Wayne Walter | c00d1d1 | 2010-02-13 14:32:21 -0500 | [diff] [blame] | 104 | split|push) default="--default HEAD" ;; |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 105 | *) die "Unknown command '$command'" ;; |
| 106 | esac |
| 107 | |
Avery Pennarun | 9a8821f | 2009-04-24 22:57:14 -0400 | [diff] [blame] | 108 | if [ -z "$prefix" ]; then |
| 109 | die "You must provide the --prefix option." |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 110 | fi |
Win Treese | ec54f0d | 2010-02-05 22:02:43 -0500 | [diff] [blame] | 111 | |
Avery Pennarun | 77ba305 | 2010-02-08 15:00:42 -0500 | [diff] [blame] | 112 | case "$command" in |
| 113 | add) [ -e "$prefix" ] && |
| 114 | die "prefix '$prefix' already exists." ;; |
| 115 | *) [ -e "$prefix" ] || |
| 116 | die "'$prefix' does not exist; use 'git subtree add'" ;; |
| 117 | esac |
Win Treese | ec54f0d | 2010-02-05 22:02:43 -0500 | [diff] [blame] | 118 | |
Avery Pennarun | 6f2012c | 2009-10-02 15:22:15 -0400 | [diff] [blame] | 119 | dir="$(dirname "$prefix/.")" |
Avery Pennarun | 9a8821f | 2009-04-24 22:57:14 -0400 | [diff] [blame] | 120 | |
Wayne Walter | c00d1d1 | 2010-02-13 14:32:21 -0500 | [diff] [blame] | 121 | if [ "$command" != "pull" -a "$command" != "add" -a "$command" != "push" ]; then |
Avery Pennarun | 13648af | 2009-04-24 23:41:19 -0400 | [diff] [blame] | 122 | revs=$(git rev-parse $default --revs-only "$@") || exit $? |
| 123 | dirs="$(git rev-parse --no-revs --no-flags "$@")" || exit $? |
| 124 | if [ -n "$dirs" ]; then |
| 125 | die "Error: Use --prefix instead of bare filenames." |
| 126 | fi |
Avery Pennarun | 9a8821f | 2009-04-24 22:57:14 -0400 | [diff] [blame] | 127 | fi |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 128 | |
| 129 | debug "command: {$command}" |
| 130 | debug "quiet: {$quiet}" |
| 131 | debug "revs: {$revs}" |
| 132 | debug "dir: {$dir}" |
Avery Pennarun | 13648af | 2009-04-24 23:41:19 -0400 | [diff] [blame] | 133 | debug "opts: {$*}" |
Avery Pennarun | eb7b590 | 2009-04-24 23:28:30 -0400 | [diff] [blame] | 134 | debug |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 135 | |
| 136 | cache_setup() |
| 137 | { |
Avery Pennarun | 2573354 | 2009-04-24 14:24:38 -0400 | [diff] [blame] | 138 | cachedir="$GIT_DIR/subtree-cache/$$" |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 139 | rm -rf "$cachedir" || die "Can't delete old cachedir: $cachedir" |
| 140 | mkdir -p "$cachedir" || die "Can't create new cachedir: $cachedir" |
Jesse Greenwald | 915b989 | 2010-11-09 22:18:36 -0600 | [diff] [blame^] | 141 | mkdir -p "$cachedir/notree" || die "Can't create new cachedir: $cachedir/notree" |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 142 | debug "Using cachedir: $cachedir" >&2 |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | cache_get() |
| 146 | { |
| 147 | for oldrev in $*; do |
| 148 | if [ -r "$cachedir/$oldrev" ]; then |
| 149 | read newrev <"$cachedir/$oldrev" |
| 150 | echo $newrev |
| 151 | fi |
| 152 | done |
| 153 | } |
| 154 | |
Jesse Greenwald | 915b989 | 2010-11-09 22:18:36 -0600 | [diff] [blame^] | 155 | cache_miss() |
| 156 | { |
| 157 | for oldrev in $*; do |
| 158 | if [ ! -r "$cachedir/$oldrev" ]; then |
| 159 | echo $oldrev |
| 160 | fi |
| 161 | done |
| 162 | } |
| 163 | |
| 164 | check_parents() |
| 165 | { |
| 166 | missed=$(cache_miss $*) |
| 167 | for miss in $missed; do |
| 168 | if [ ! -r "$cachedir/notree/$miss" ]; then |
| 169 | debug " incorrect order: $miss" |
| 170 | fi |
| 171 | done |
| 172 | } |
| 173 | |
| 174 | set_notree() |
| 175 | { |
| 176 | echo "1" > "$cachedir/notree/$1" |
| 177 | } |
| 178 | |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 179 | cache_set() |
| 180 | { |
| 181 | oldrev="$1" |
| 182 | newrev="$2" |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 183 | if [ "$oldrev" != "latest_old" \ |
| 184 | -a "$oldrev" != "latest_new" \ |
| 185 | -a -e "$cachedir/$oldrev" ]; then |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 186 | die "cache for $oldrev already exists!" |
| 187 | fi |
| 188 | echo "$newrev" >"$cachedir/$oldrev" |
| 189 | } |
| 190 | |
Avery Pennarun | 43a3951 | 2009-05-30 01:05:43 -0400 | [diff] [blame] | 191 | rev_exists() |
| 192 | { |
| 193 | if git rev-parse "$1" >/dev/null 2>&1; then |
| 194 | return 0 |
| 195 | else |
| 196 | return 1 |
| 197 | fi |
| 198 | } |
| 199 | |
Jakub Suder | 0a56294 | 2010-01-09 19:56:05 +0100 | [diff] [blame] | 200 | rev_is_descendant_of_branch() |
| 201 | { |
| 202 | newrev="$1" |
| 203 | branch="$2" |
| 204 | branch_hash=$(git rev-parse $branch) |
Jakub Suder | 6bd910a | 2010-01-12 23:34:52 +0100 | [diff] [blame] | 205 | match=$(git rev-list -1 $branch_hash ^$newrev) |
Jakub Suder | 0a56294 | 2010-01-09 19:56:05 +0100 | [diff] [blame] | 206 | |
Jakub Suder | 6bd910a | 2010-01-12 23:34:52 +0100 | [diff] [blame] | 207 | if [ -z "$match" ]; then |
Jakub Suder | 0a56294 | 2010-01-09 19:56:05 +0100 | [diff] [blame] | 208 | return 0 |
| 209 | else |
| 210 | return 1 |
| 211 | fi |
| 212 | } |
| 213 | |
Avery Pennarun | b9de535 | 2009-04-25 00:06:45 -0400 | [diff] [blame] | 214 | # if a commit doesn't have a parent, this might not work. But we only want |
| 215 | # to remove the parent from the rev-list, and since it doesn't exist, it won't |
| 216 | # be there anyway, so do nothing in that case. |
| 217 | try_remove_previous() |
| 218 | { |
Avery Pennarun | 43a3951 | 2009-05-30 01:05:43 -0400 | [diff] [blame] | 219 | if rev_exists "$1^"; then |
Avery Pennarun | b9de535 | 2009-04-25 00:06:45 -0400 | [diff] [blame] | 220 | echo "^$1^" |
| 221 | fi |
| 222 | } |
| 223 | |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 224 | find_latest_squash() |
| 225 | { |
Avery Pennarun | d713e2d | 2009-05-30 04:11:43 -0400 | [diff] [blame] | 226 | debug "Looking for latest squash ($dir)..." |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 227 | dir="$1" |
Avery Pennarun | d713e2d | 2009-05-30 04:11:43 -0400 | [diff] [blame] | 228 | sq= |
| 229 | main= |
| 230 | sub= |
Avery Pennarun | 6f2012c | 2009-10-02 15:22:15 -0400 | [diff] [blame] | 231 | git log --grep="^git-subtree-dir: $dir/*\$" \ |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 232 | --pretty=format:'START %H%n%s%n%n%b%nEND%n' HEAD | |
| 233 | while read a b junk; do |
Avery Pennarun | d713e2d | 2009-05-30 04:11:43 -0400 | [diff] [blame] | 234 | debug "$a $b $junk" |
| 235 | debug "{{$sq/$main/$sub}}" |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 236 | case "$a" in |
| 237 | START) sq="$b" ;; |
| 238 | git-subtree-mainline:) main="$b" ;; |
| 239 | git-subtree-split:) sub="$b" ;; |
| 240 | END) |
| 241 | if [ -n "$sub" ]; then |
| 242 | if [ -n "$main" ]; then |
| 243 | # a rejoin commit? |
| 244 | # Pretend its sub was a squash. |
| 245 | sq="$sub" |
| 246 | fi |
| 247 | debug "Squash found: $sq $sub" |
| 248 | echo "$sq" "$sub" |
| 249 | break |
| 250 | fi |
| 251 | sq= |
| 252 | main= |
| 253 | sub= |
| 254 | ;; |
| 255 | esac |
| 256 | done |
| 257 | } |
| 258 | |
Avery Pennarun | 8b4a77f | 2009-04-24 16:48:08 -0400 | [diff] [blame] | 259 | find_existing_splits() |
| 260 | { |
| 261 | debug "Looking for prior splits..." |
| 262 | dir="$1" |
| 263 | revs="$2" |
Avery Pennarun | d713e2d | 2009-05-30 04:11:43 -0400 | [diff] [blame] | 264 | main= |
| 265 | sub= |
Avery Pennarun | 6f2012c | 2009-10-02 15:22:15 -0400 | [diff] [blame] | 266 | git log --grep="^git-subtree-dir: $dir/*\$" \ |
Avery Pennarun | 1a8c36d | 2009-05-30 03:33:39 -0400 | [diff] [blame] | 267 | --pretty=format:'START %H%n%s%n%n%b%nEND%n' $revs | |
Avery Pennarun | 8b4a77f | 2009-04-24 16:48:08 -0400 | [diff] [blame] | 268 | while read a b junk; do |
| 269 | case "$a" in |
Avery Pennarun | 2275f70 | 2009-10-02 16:09:09 -0400 | [diff] [blame] | 270 | START) sq="$b" ;; |
Avery Pennarun | 8b4a77f | 2009-04-24 16:48:08 -0400 | [diff] [blame] | 271 | git-subtree-mainline:) main="$b" ;; |
| 272 | git-subtree-split:) sub="$b" ;; |
Avery Pennarun | 7ee9eef | 2009-05-30 01:28:20 -0400 | [diff] [blame] | 273 | END) |
Avery Pennarun | 2275f70 | 2009-10-02 16:09:09 -0400 | [diff] [blame] | 274 | debug " Main is: '$main'" |
Avery Pennarun | 1a8c36d | 2009-05-30 03:33:39 -0400 | [diff] [blame] | 275 | if [ -z "$main" -a -n "$sub" ]; then |
| 276 | # squash commits refer to a subtree |
Avery Pennarun | 2275f70 | 2009-10-02 16:09:09 -0400 | [diff] [blame] | 277 | debug " Squash: $sq from $sub" |
Avery Pennarun | 1a8c36d | 2009-05-30 03:33:39 -0400 | [diff] [blame] | 278 | cache_set "$sq" "$sub" |
| 279 | fi |
Avery Pennarun | 8b4a77f | 2009-04-24 16:48:08 -0400 | [diff] [blame] | 280 | if [ -n "$main" -a -n "$sub" ]; then |
| 281 | debug " Prior: $main -> $sub" |
| 282 | cache_set $main $sub |
Pelle Wessman | 39f5fff | 2010-05-20 22:40:09 +0200 | [diff] [blame] | 283 | cache_set $sub $sub |
Avery Pennarun | b9de535 | 2009-04-25 00:06:45 -0400 | [diff] [blame] | 284 | try_remove_previous "$main" |
| 285 | try_remove_previous "$sub" |
Avery Pennarun | 8b4a77f | 2009-04-24 16:48:08 -0400 | [diff] [blame] | 286 | fi |
Avery Pennarun | 7ee9eef | 2009-05-30 01:28:20 -0400 | [diff] [blame] | 287 | main= |
| 288 | sub= |
Avery Pennarun | 8b4a77f | 2009-04-24 16:48:08 -0400 | [diff] [blame] | 289 | ;; |
| 290 | esac |
| 291 | done |
| 292 | } |
| 293 | |
Avery Pennarun | fd9500e | 2009-04-24 14:45:02 -0400 | [diff] [blame] | 294 | copy_commit() |
| 295 | { |
Avery Pennarun | f96bc79 | 2009-05-30 00:47:59 -0400 | [diff] [blame] | 296 | # We're going to set some environment vars here, so |
Avery Pennarun | fd9500e | 2009-04-24 14:45:02 -0400 | [diff] [blame] | 297 | # do it in a subshell to get rid of them safely later |
Avery Pennarun | a64f3a7 | 2009-04-26 16:53:57 -0400 | [diff] [blame] | 298 | debug copy_commit "{$1}" "{$2}" "{$3}" |
Avery Pennarun | fd9500e | 2009-04-24 14:45:02 -0400 | [diff] [blame] | 299 | git log -1 --pretty=format:'%an%n%ae%n%ad%n%cn%n%ce%n%cd%n%s%n%n%b' "$1" | |
| 300 | ( |
| 301 | read GIT_AUTHOR_NAME |
| 302 | read GIT_AUTHOR_EMAIL |
| 303 | read GIT_AUTHOR_DATE |
| 304 | read GIT_COMMITTER_NAME |
| 305 | read GIT_COMMITTER_EMAIL |
| 306 | read GIT_COMMITTER_DATE |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 307 | export GIT_AUTHOR_NAME \ |
| 308 | GIT_AUTHOR_EMAIL \ |
| 309 | GIT_AUTHOR_DATE \ |
| 310 | GIT_COMMITTER_NAME \ |
| 311 | GIT_COMMITTER_EMAIL \ |
| 312 | GIT_COMMITTER_DATE |
Avery Pennarun | d0eb1b1 | 2009-04-26 08:59:12 -0400 | [diff] [blame] | 313 | (echo -n "$annotate"; cat ) | |
Avery Pennarun | fd9500e | 2009-04-24 14:45:02 -0400 | [diff] [blame] | 314 | git commit-tree "$2" $3 # reads the rest of stdin |
| 315 | ) || die "Can't copy commit $1" |
| 316 | } |
| 317 | |
Avery Pennarun | eb7b590 | 2009-04-24 23:28:30 -0400 | [diff] [blame] | 318 | add_msg() |
| 319 | { |
| 320 | dir="$1" |
| 321 | latest_old="$2" |
| 322 | latest_new="$3" |
Jakub Suder | 2da0969 | 2010-01-09 19:55:35 +0100 | [diff] [blame] | 323 | if [ -n "$message" ]; then |
| 324 | commit_message="$message" |
| 325 | else |
| 326 | commit_message="Add '$dir/' from commit '$latest_new'" |
| 327 | fi |
Avery Pennarun | eb7b590 | 2009-04-24 23:28:30 -0400 | [diff] [blame] | 328 | cat <<-EOF |
Jakub Suder | 2da0969 | 2010-01-09 19:55:35 +0100 | [diff] [blame] | 329 | $commit_message |
Avery Pennarun | eb7b590 | 2009-04-24 23:28:30 -0400 | [diff] [blame] | 330 | |
| 331 | git-subtree-dir: $dir |
| 332 | git-subtree-mainline: $latest_old |
| 333 | git-subtree-split: $latest_new |
| 334 | EOF |
| 335 | } |
| 336 | |
Jakub Suder | 2da0969 | 2010-01-09 19:55:35 +0100 | [diff] [blame] | 337 | add_squashed_msg() |
| 338 | { |
| 339 | if [ -n "$message" ]; then |
| 340 | echo "$message" |
| 341 | else |
| 342 | echo "Merge commit '$1' as '$2'" |
| 343 | fi |
| 344 | } |
| 345 | |
Avery Pennarun | 7ee9eef | 2009-05-30 01:28:20 -0400 | [diff] [blame] | 346 | rejoin_msg() |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 347 | { |
| 348 | dir="$1" |
| 349 | latest_old="$2" |
| 350 | latest_new="$3" |
Jakub Suder | 2da0969 | 2010-01-09 19:55:35 +0100 | [diff] [blame] | 351 | if [ -n "$message" ]; then |
| 352 | commit_message="$message" |
| 353 | else |
| 354 | commit_message="Split '$dir/' into commit '$latest_new'" |
| 355 | fi |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 356 | cat <<-EOF |
Jakub Suder | 1262916 | 2010-01-12 22:38:34 +0100 | [diff] [blame] | 357 | $commit_message |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 358 | |
| 359 | git-subtree-dir: $dir |
Avery Pennarun | 8b4a77f | 2009-04-24 16:48:08 -0400 | [diff] [blame] | 360 | git-subtree-mainline: $latest_old |
| 361 | git-subtree-split: $latest_new |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 362 | EOF |
| 363 | } |
| 364 | |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 365 | squash_msg() |
| 366 | { |
| 367 | dir="$1" |
| 368 | oldsub="$2" |
| 369 | newsub="$3" |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 370 | newsub_short=$(git rev-parse --short "$newsub") |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 371 | |
Avery Pennarun | d713e2d | 2009-05-30 04:11:43 -0400 | [diff] [blame] | 372 | if [ -n "$oldsub" ]; then |
| 373 | oldsub_short=$(git rev-parse --short "$oldsub") |
| 374 | echo "Squashed '$dir/' changes from $oldsub_short..$newsub_short" |
| 375 | echo |
| 376 | git log --pretty=tformat:'%h %s' "$oldsub..$newsub" |
| 377 | git log --pretty=tformat:'REVERT: %h %s' "$newsub..$oldsub" |
| 378 | else |
| 379 | echo "Squashed '$dir/' content from commit $newsub_short" |
| 380 | fi |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 381 | |
Avery Pennarun | d713e2d | 2009-05-30 04:11:43 -0400 | [diff] [blame] | 382 | echo |
| 383 | echo "git-subtree-dir: $dir" |
| 384 | echo "git-subtree-split: $newsub" |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 385 | } |
| 386 | |
Avery Pennarun | 210d083 | 2009-04-24 21:49:19 -0400 | [diff] [blame] | 387 | toptree_for_commit() |
Avery Pennarun | 768d6d1 | 2009-04-24 17:53:10 -0400 | [diff] [blame] | 388 | { |
Avery Pennarun | 210d083 | 2009-04-24 21:49:19 -0400 | [diff] [blame] | 389 | commit="$1" |
| 390 | git log -1 --pretty=format:'%T' "$commit" -- || exit $? |
| 391 | } |
| 392 | |
| 393 | subtree_for_commit() |
| 394 | { |
| 395 | commit="$1" |
| 396 | dir="$2" |
| 397 | git ls-tree "$commit" -- "$dir" | |
Avery Pennarun | 768d6d1 | 2009-04-24 17:53:10 -0400 | [diff] [blame] | 398 | while read mode type tree name; do |
| 399 | assert [ "$name" = "$dir" ] |
Pelle Wessman | 8ac5eca | 2009-09-30 14:29:42 +0200 | [diff] [blame] | 400 | assert [ "$type" = "tree" ] |
Avery Pennarun | 768d6d1 | 2009-04-24 17:53:10 -0400 | [diff] [blame] | 401 | echo $tree |
| 402 | break |
| 403 | done |
| 404 | } |
| 405 | |
| 406 | tree_changed() |
| 407 | { |
| 408 | tree=$1 |
| 409 | shift |
| 410 | if [ $# -ne 1 ]; then |
| 411 | return 0 # weird parents, consider it changed |
| 412 | else |
Avery Pennarun | 210d083 | 2009-04-24 21:49:19 -0400 | [diff] [blame] | 413 | ptree=$(toptree_for_commit $1) |
Avery Pennarun | 768d6d1 | 2009-04-24 17:53:10 -0400 | [diff] [blame] | 414 | if [ "$ptree" != "$tree" ]; then |
| 415 | return 0 # changed |
| 416 | else |
| 417 | return 1 # not changed |
| 418 | fi |
| 419 | fi |
| 420 | } |
| 421 | |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 422 | new_squash_commit() |
| 423 | { |
| 424 | old="$1" |
| 425 | oldsub="$2" |
| 426 | newsub="$3" |
| 427 | tree=$(toptree_for_commit $newsub) || exit $? |
Avery Pennarun | d713e2d | 2009-05-30 04:11:43 -0400 | [diff] [blame] | 428 | if [ -n "$old" ]; then |
| 429 | squash_msg "$dir" "$oldsub" "$newsub" | |
| 430 | git commit-tree "$tree" -p "$old" || exit $? |
| 431 | else |
| 432 | squash_msg "$dir" "" "$newsub" | |
| 433 | git commit-tree "$tree" || exit $? |
| 434 | fi |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 435 | } |
| 436 | |
Avery Pennarun | d691265 | 2009-04-24 22:05:30 -0400 | [diff] [blame] | 437 | copy_or_skip() |
| 438 | { |
| 439 | rev="$1" |
| 440 | tree="$2" |
| 441 | newparents="$3" |
| 442 | assert [ -n "$tree" ] |
| 443 | |
Avery Pennarun | 96db2c0 | 2009-04-24 22:36:06 -0400 | [diff] [blame] | 444 | identical= |
Avery Pennarun | 49cf822 | 2009-04-26 17:07:16 -0400 | [diff] [blame] | 445 | nonidentical= |
Avery Pennarun | 96db2c0 | 2009-04-24 22:36:06 -0400 | [diff] [blame] | 446 | p= |
Avery Pennarun | a64f3a7 | 2009-04-26 16:53:57 -0400 | [diff] [blame] | 447 | gotparents= |
Avery Pennarun | d691265 | 2009-04-24 22:05:30 -0400 | [diff] [blame] | 448 | for parent in $newparents; do |
| 449 | ptree=$(toptree_for_commit $parent) || exit $? |
Avery Pennarun | a64f3a7 | 2009-04-26 16:53:57 -0400 | [diff] [blame] | 450 | [ -z "$ptree" ] && continue |
Avery Pennarun | d691265 | 2009-04-24 22:05:30 -0400 | [diff] [blame] | 451 | if [ "$ptree" = "$tree" ]; then |
Avery Pennarun | 96db2c0 | 2009-04-24 22:36:06 -0400 | [diff] [blame] | 452 | # an identical parent could be used in place of this rev. |
| 453 | identical="$parent" |
Avery Pennarun | 49cf822 | 2009-04-26 17:07:16 -0400 | [diff] [blame] | 454 | else |
| 455 | nonidentical="$parent" |
Avery Pennarun | 96db2c0 | 2009-04-24 22:36:06 -0400 | [diff] [blame] | 456 | fi |
Avery Pennarun | a64f3a7 | 2009-04-26 16:53:57 -0400 | [diff] [blame] | 457 | |
| 458 | # sometimes both old parents map to the same newparent; |
| 459 | # eliminate duplicates |
| 460 | is_new=1 |
| 461 | for gp in $gotparents; do |
| 462 | if [ "$gp" = "$parent" ]; then |
| 463 | is_new= |
| 464 | break |
| 465 | fi |
| 466 | done |
| 467 | if [ -n "$is_new" ]; then |
| 468 | gotparents="$gotparents $parent" |
Avery Pennarun | d691265 | 2009-04-24 22:05:30 -0400 | [diff] [blame] | 469 | p="$p -p $parent" |
| 470 | fi |
| 471 | done |
| 472 | |
Avery Pennarun | 795e730 | 2009-04-26 17:44:18 -0400 | [diff] [blame] | 473 | if [ -n "$identical" ]; then |
Avery Pennarun | 96db2c0 | 2009-04-24 22:36:06 -0400 | [diff] [blame] | 474 | echo $identical |
| 475 | else |
| 476 | copy_commit $rev $tree "$p" || exit $? |
| 477 | fi |
Avery Pennarun | d691265 | 2009-04-24 22:05:30 -0400 | [diff] [blame] | 478 | } |
| 479 | |
Avery Pennarun | 13648af | 2009-04-24 23:41:19 -0400 | [diff] [blame] | 480 | ensure_clean() |
Avery Pennarun | eb7b590 | 2009-04-24 23:28:30 -0400 | [diff] [blame] | 481 | { |
Wayne Walter | c00d1d1 | 2010-02-13 14:32:21 -0500 | [diff] [blame] | 482 | if ! git diff-index HEAD --exit-code --quiet 2>&1; then |
Avery Pennarun | eb7b590 | 2009-04-24 23:28:30 -0400 | [diff] [blame] | 483 | die "Working tree has modifications. Cannot add." |
| 484 | fi |
Wayne Walter | c00d1d1 | 2010-02-13 14:32:21 -0500 | [diff] [blame] | 485 | if ! git diff-index --cached HEAD --exit-code --quiet 2>&1; then |
Avery Pennarun | eb7b590 | 2009-04-24 23:28:30 -0400 | [diff] [blame] | 486 | die "Index has modifications. Cannot add." |
| 487 | fi |
Avery Pennarun | 13648af | 2009-04-24 23:41:19 -0400 | [diff] [blame] | 488 | } |
| 489 | |
| 490 | cmd_add() |
| 491 | { |
| 492 | if [ -e "$dir" ]; then |
| 493 | die "'$dir' already exists. Cannot add." |
| 494 | fi |
Wayne Walter | c00d1d1 | 2010-02-13 14:32:21 -0500 | [diff] [blame] | 495 | |
Avery Pennarun | 13648af | 2009-04-24 23:41:19 -0400 | [diff] [blame] | 496 | ensure_clean |
| 497 | |
Wayne Walter | c00d1d1 | 2010-02-13 14:32:21 -0500 | [diff] [blame] | 498 | if [ $# -eq 1 ]; then |
| 499 | "cmd_add_commit" "$@" |
| 500 | elif [ $# -eq 2 ]; then |
| 501 | "cmd_add_repository" "$@" |
| 502 | else |
| 503 | say "error: parameters were '$@'" |
| 504 | die "Provide either a refspec or a repository and refspec." |
Avery Pennarun | eb7b590 | 2009-04-24 23:28:30 -0400 | [diff] [blame] | 505 | fi |
Wayne Walter | c00d1d1 | 2010-02-13 14:32:21 -0500 | [diff] [blame] | 506 | } |
| 507 | |
| 508 | cmd_add_repository() |
| 509 | { |
| 510 | echo "git fetch" "$@" |
| 511 | repository=$1 |
| 512 | refspec=$2 |
| 513 | git fetch "$@" || exit $? |
| 514 | revs=FETCH_HEAD |
| 515 | set -- $revs |
| 516 | cmd_add_commit "$@" |
| 517 | } |
| 518 | |
| 519 | cmd_add_commit() |
| 520 | { |
| 521 | revs=$(git rev-parse $default --revs-only "$@") || exit $? |
| 522 | set -- $revs |
Avery Pennarun | eb7b590 | 2009-04-24 23:28:30 -0400 | [diff] [blame] | 523 | rev="$1" |
| 524 | |
| 525 | debug "Adding $dir as '$rev'..." |
| 526 | git read-tree --prefix="$dir" $rev || exit $? |
Avery Pennarun | 227f781 | 2009-08-26 10:43:43 -0400 | [diff] [blame] | 527 | git checkout -- "$dir" || exit $? |
Avery Pennarun | eb7b590 | 2009-04-24 23:28:30 -0400 | [diff] [blame] | 528 | tree=$(git write-tree) || exit $? |
| 529 | |
| 530 | headrev=$(git rev-parse HEAD) || exit $? |
| 531 | if [ -n "$headrev" -a "$headrev" != "$rev" ]; then |
| 532 | headp="-p $headrev" |
| 533 | else |
| 534 | headp= |
| 535 | fi |
Avery Pennarun | d713e2d | 2009-05-30 04:11:43 -0400 | [diff] [blame] | 536 | |
| 537 | if [ -n "$squash" ]; then |
| 538 | rev=$(new_squash_commit "" "" "$rev") || exit $? |
Jakub Suder | 2da0969 | 2010-01-09 19:55:35 +0100 | [diff] [blame] | 539 | commit=$(add_squashed_msg "$rev" "$dir" | |
Avery Pennarun | d713e2d | 2009-05-30 04:11:43 -0400 | [diff] [blame] | 540 | git commit-tree $tree $headp -p "$rev") || exit $? |
| 541 | else |
| 542 | commit=$(add_msg "$dir" "$headrev" "$rev" | |
| 543 | git commit-tree $tree $headp -p "$rev") || exit $? |
| 544 | fi |
Avery Pennarun | eb7b590 | 2009-04-24 23:28:30 -0400 | [diff] [blame] | 545 | git reset "$commit" || exit $? |
Avery Pennarun | d713e2d | 2009-05-30 04:11:43 -0400 | [diff] [blame] | 546 | |
| 547 | say "Added dir '$dir'" |
Avery Pennarun | eb7b590 | 2009-04-24 23:28:30 -0400 | [diff] [blame] | 548 | } |
| 549 | |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 550 | cmd_split() |
| 551 | { |
| 552 | debug "Splitting $dir..." |
| 553 | cache_setup || exit $? |
| 554 | |
Avery Pennarun | 33ff583 | 2009-04-24 17:05:14 -0400 | [diff] [blame] | 555 | if [ -n "$onto" ]; then |
Avery Pennarun | 847e868 | 2009-04-24 21:35:50 -0400 | [diff] [blame] | 556 | debug "Reading history for --onto=$onto..." |
Avery Pennarun | 33ff583 | 2009-04-24 17:05:14 -0400 | [diff] [blame] | 557 | git rev-list $onto | |
| 558 | while read rev; do |
| 559 | # the 'onto' history is already just the subdir, so |
| 560 | # any parent we find there can be used verbatim |
Avery Pennarun | 2c71b7c | 2009-04-24 17:42:33 -0400 | [diff] [blame] | 561 | debug " cache: $rev" |
Avery Pennarun | 33ff583 | 2009-04-24 17:05:14 -0400 | [diff] [blame] | 562 | cache_set $rev $rev |
| 563 | done |
| 564 | fi |
| 565 | |
Avery Pennarun | 96db2c0 | 2009-04-24 22:36:06 -0400 | [diff] [blame] | 566 | if [ -n "$ignore_joins" ]; then |
| 567 | unrevs= |
| 568 | else |
| 569 | unrevs="$(find_existing_splits "$dir" "$revs")" |
| 570 | fi |
Avery Pennarun | 8b4a77f | 2009-04-24 16:48:08 -0400 | [diff] [blame] | 571 | |
Avery Pennarun | 1f73862 | 2009-04-26 15:54:42 -0400 | [diff] [blame] | 572 | # We can't restrict rev-list to only $dir here, because some of our |
| 573 | # parents have the $dir contents the root, and those won't match. |
| 574 | # (and rev-list --follow doesn't seem to solve this) |
Jesse Greenwald | 6f4f84f | 2010-11-09 08:34:49 -0600 | [diff] [blame] | 575 | grl='git rev-list --topo-order --reverse --parents $revs $unrevs' |
Avery Pennarun | 942dce5 | 2009-04-26 18:06:08 -0400 | [diff] [blame] | 576 | revmax=$(eval "$grl" | wc -l) |
| 577 | revcount=0 |
| 578 | createcount=0 |
| 579 | eval "$grl" | |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 580 | while read rev parents; do |
Avery Pennarun | 942dce5 | 2009-04-26 18:06:08 -0400 | [diff] [blame] | 581 | revcount=$(($revcount + 1)) |
Avery Pennarun | e2d0a45 | 2010-02-02 10:30:11 -0500 | [diff] [blame] | 582 | say -n "$revcount/$revmax ($createcount)
" |
Avery Pennarun | 2c71b7c | 2009-04-24 17:42:33 -0400 | [diff] [blame] | 583 | debug "Processing commit: $rev" |
| 584 | exists=$(cache_get $rev) |
Avery Pennarun | 8b4a77f | 2009-04-24 16:48:08 -0400 | [diff] [blame] | 585 | if [ -n "$exists" ]; then |
| 586 | debug " prior: $exists" |
| 587 | continue |
| 588 | fi |
Avery Pennarun | 942dce5 | 2009-04-26 18:06:08 -0400 | [diff] [blame] | 589 | createcount=$(($createcount + 1)) |
Avery Pennarun | 2c71b7c | 2009-04-24 17:42:33 -0400 | [diff] [blame] | 590 | debug " parents: $parents" |
| 591 | newparents=$(cache_get $parents) |
| 592 | debug " newparents: $newparents" |
Avery Pennarun | 8b4a77f | 2009-04-24 16:48:08 -0400 | [diff] [blame] | 593 | |
Avery Pennarun | 210d083 | 2009-04-24 21:49:19 -0400 | [diff] [blame] | 594 | tree=$(subtree_for_commit $rev "$dir") |
Avery Pennarun | 768d6d1 | 2009-04-24 17:53:10 -0400 | [diff] [blame] | 595 | debug " tree is: $tree" |
Jesse Greenwald | 915b989 | 2010-11-09 22:18:36 -0600 | [diff] [blame^] | 596 | |
| 597 | check_parents $parents |
Avery Pennarun | 7ee9eef | 2009-05-30 01:28:20 -0400 | [diff] [blame] | 598 | |
| 599 | # ugly. is there no better way to tell if this is a subtree |
| 600 | # vs. a mainline commit? Does it matter? |
Jakub Suder | da949cc | 2010-01-09 23:01:39 +0100 | [diff] [blame] | 601 | if [ -z $tree ]; then |
Jesse Greenwald | 915b989 | 2010-11-09 22:18:36 -0600 | [diff] [blame^] | 602 | set_notree $rev |
Pelle Wessman | 39f5fff | 2010-05-20 22:40:09 +0200 | [diff] [blame] | 603 | if [ -n "$newparents" ]; then |
| 604 | cache_set $rev $rev |
| 605 | fi |
Jakub Suder | da949cc | 2010-01-09 23:01:39 +0100 | [diff] [blame] | 606 | continue |
| 607 | fi |
Avery Pennarun | 768d6d1 | 2009-04-24 17:53:10 -0400 | [diff] [blame] | 608 | |
Avery Pennarun | d691265 | 2009-04-24 22:05:30 -0400 | [diff] [blame] | 609 | newrev=$(copy_or_skip "$rev" "$tree" "$newparents") || exit $? |
Avery Pennarun | 768d6d1 | 2009-04-24 17:53:10 -0400 | [diff] [blame] | 610 | debug " newrev is: $newrev" |
| 611 | cache_set $rev $newrev |
| 612 | cache_set latest_new $newrev |
| 613 | cache_set latest_old $rev |
Avery Pennarun | 2573354 | 2009-04-24 14:24:38 -0400 | [diff] [blame] | 614 | done || exit $? |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 615 | latest_new=$(cache_get latest_new) |
| 616 | if [ -z "$latest_new" ]; then |
Avery Pennarun | e25a6bf | 2009-04-24 14:52:27 -0400 | [diff] [blame] | 617 | die "No new revisions were found" |
| 618 | fi |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 619 | |
| 620 | if [ -n "$rejoin" ]; then |
| 621 | debug "Merging split branch into HEAD..." |
| 622 | latest_old=$(cache_get latest_old) |
| 623 | git merge -s ours \ |
Avery Pennarun | 7ee9eef | 2009-05-30 01:28:20 -0400 | [diff] [blame] | 624 | -m "$(rejoin_msg $dir $latest_old $latest_new)" \ |
Avery Pennarun | ea28d67 | 2009-04-30 21:57:32 -0400 | [diff] [blame] | 625 | $latest_new >&2 || exit $? |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 626 | fi |
Avery Pennarun | 43a3951 | 2009-05-30 01:05:43 -0400 | [diff] [blame] | 627 | if [ -n "$branch" ]; then |
Jakub Suder | 0a56294 | 2010-01-09 19:56:05 +0100 | [diff] [blame] | 628 | if rev_exists "refs/heads/$branch"; then |
| 629 | if ! rev_is_descendant_of_branch $latest_new $branch; then |
| 630 | die "Branch '$branch' is not an ancestor of commit '$latest_new'." |
| 631 | fi |
| 632 | action='Updated' |
| 633 | else |
| 634 | action='Created' |
| 635 | fi |
| 636 | git update-ref -m 'subtree split' "refs/heads/$branch" $latest_new || exit $? |
| 637 | say "$action branch '$branch'" |
Avery Pennarun | 43a3951 | 2009-05-30 01:05:43 -0400 | [diff] [blame] | 638 | fi |
Avery Pennarun | b77172f | 2009-04-24 15:48:41 -0400 | [diff] [blame] | 639 | echo $latest_new |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 640 | exit 0 |
| 641 | } |
| 642 | |
| 643 | cmd_merge() |
| 644 | { |
Wayne Walter | c00d1d1 | 2010-02-13 14:32:21 -0500 | [diff] [blame] | 645 | revs=$(git rev-parse $default --revs-only "$@") || exit $? |
Avery Pennarun | 13648af | 2009-04-24 23:41:19 -0400 | [diff] [blame] | 646 | ensure_clean |
| 647 | |
| 648 | set -- $revs |
| 649 | if [ $# -ne 1 ]; then |
| 650 | die "You must provide exactly one revision. Got: '$revs'" |
| 651 | fi |
| 652 | rev="$1" |
| 653 | |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 654 | if [ -n "$squash" ]; then |
| 655 | first_split="$(find_latest_squash "$dir")" |
| 656 | if [ -z "$first_split" ]; then |
| 657 | die "Can't squash-merge: '$dir' was never added." |
| 658 | fi |
| 659 | set $first_split |
| 660 | old=$1 |
| 661 | sub=$2 |
Avery Pennarun | eb4fb91 | 2009-05-30 03:33:17 -0400 | [diff] [blame] | 662 | if [ "$sub" = "$rev" ]; then |
| 663 | say "Subtree is already at commit $rev." |
| 664 | exit 0 |
| 665 | fi |
Avery Pennarun | 1cc2cff | 2009-05-30 03:18:27 -0400 | [diff] [blame] | 666 | new=$(new_squash_commit "$old" "$sub" "$rev") || exit $? |
| 667 | debug "New squash commit: $new" |
| 668 | rev="$new" |
| 669 | fi |
Pelle Wessman | 448e71e | 2010-05-07 21:21:25 +0200 | [diff] [blame] | 670 | |
| 671 | version=$(git version) |
| 672 | if [ "$version" \< "git version 1.7" ]; then |
| 673 | if [ -n "$message" ]; then |
| 674 | git merge -s subtree --message="$message" $rev |
| 675 | else |
| 676 | git merge -s subtree $rev |
| 677 | fi |
Avery Pennarun | 349a70d | 2010-02-06 15:05:17 -0500 | [diff] [blame] | 678 | else |
Pelle Wessman | 448e71e | 2010-05-07 21:21:25 +0200 | [diff] [blame] | 679 | if [ -n "$message" ]; then |
| 680 | git merge -Xsubtree="$prefix" --message="$message" $rev |
| 681 | else |
| 682 | git merge -Xsubtree="$prefix" $rev |
| 683 | fi |
Avery Pennarun | 349a70d | 2010-02-06 15:05:17 -0500 | [diff] [blame] | 684 | fi |
Avery Pennarun | 0ca71b3 | 2009-04-24 14:13:34 -0400 | [diff] [blame] | 685 | } |
| 686 | |
Avery Pennarun | 13648af | 2009-04-24 23:41:19 -0400 | [diff] [blame] | 687 | cmd_pull() |
| 688 | { |
| 689 | ensure_clean |
Avery Pennarun | e31d1e2 | 2009-10-02 18:23:54 -0400 | [diff] [blame] | 690 | git fetch "$@" || exit $? |
| 691 | revs=FETCH_HEAD |
Wayne Walter | c00d1d1 | 2010-02-13 14:32:21 -0500 | [diff] [blame] | 692 | set -- $revs |
| 693 | cmd_merge "$@" |
| 694 | } |
| 695 | |
| 696 | cmd_push() |
| 697 | { |
| 698 | if [ $# -ne 2 ]; then |
| 699 | die "You must provide <repository> <refspec>" |
| 700 | fi |
| 701 | if [ -e "$dir" ]; then |
| 702 | repository=$1 |
| 703 | refspec=$2 |
| 704 | echo "git push using: " $repository $refspec |
| 705 | git push $repository $(git subtree split --prefix=$prefix):refs/heads/$refspec |
| 706 | else |
| 707 | die "'$dir' must already exist. Try 'git subtree add'." |
| 708 | fi |
Avery Pennarun | 13648af | 2009-04-24 23:41:19 -0400 | [diff] [blame] | 709 | } |
| 710 | |
| 711 | "cmd_$command" "$@" |