Linus Torvalds | 303e5f4 | 2005-06-21 09:47:37 -0700 | [diff] [blame] | 1 | #!/bin/sh |
Linus Torvalds | b33e966 | 2005-07-08 10:57:21 -0700 | [diff] [blame] | 2 | |
Junio C Hamano | 1be0659 | 2006-01-12 14:04:36 -0800 | [diff] [blame] | 3 | USAGE='[-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]' |
Junio C Hamano | 104f3e0 | 2005-12-22 22:37:50 -0800 | [diff] [blame] | 4 | SUBDIRECTORY_OK=Sometimes |
freku045@student.liu.se | 806f36d | 2005-12-13 23:30:31 +0100 | [diff] [blame] | 5 | . git-sh-setup |
Chris Shoemaker | b0bafe0 | 2005-10-29 17:46:41 -0400 | [diff] [blame] | 6 | |
Shawn Pearce | 969d326 | 2006-05-19 05:17:16 -0400 | [diff] [blame] | 7 | old_name=HEAD |
Shawn Pearce | 5a03e7f | 2006-09-25 01:24:38 -0400 | [diff] [blame] | 8 | old=$(git-rev-parse --verify $old_name 2>/dev/null) |
Linus Torvalds | e8b1174 | 2005-06-21 11:03:11 -0700 | [diff] [blame] | 9 | new= |
Shawn Pearce | 969d326 | 2006-05-19 05:17:16 -0400 | [diff] [blame] | 10 | new_name= |
Linus Torvalds | a79944d | 2005-06-21 09:59:26 -0700 | [diff] [blame] | 11 | force= |
Linus Torvalds | e8b1174 | 2005-06-21 11:03:11 -0700 | [diff] [blame] | 12 | branch= |
Linus Torvalds | 91dcdfd | 2005-07-11 20:44:20 -0700 | [diff] [blame] | 13 | newbranch= |
Shawn Pearce | 969d326 | 2006-05-19 05:17:16 -0400 | [diff] [blame] | 14 | newbranch_log= |
Junio C Hamano | 1be0659 | 2006-01-12 14:04:36 -0800 | [diff] [blame] | 15 | merge= |
Linus Torvalds | e8b1174 | 2005-06-21 11:03:11 -0700 | [diff] [blame] | 16 | while [ "$#" != "0" ]; do |
| 17 | arg="$1" |
| 18 | shift |
| 19 | case "$arg" in |
Linus Torvalds | 91dcdfd | 2005-07-11 20:44:20 -0700 | [diff] [blame] | 20 | "-b") |
| 21 | newbranch="$1" |
| 22 | shift |
| 23 | [ -z "$newbranch" ] && |
| 24 | die "git checkout: -b needs a branch name" |
Linus Torvalds | 305e22c | 2006-09-15 14:56:55 -0700 | [diff] [blame] | 25 | git-show-ref --verify --quiet -- "refs/heads/$newbranch" && |
Linus Torvalds | 91dcdfd | 2005-07-11 20:44:20 -0700 | [diff] [blame] | 26 | die "git checkout: branch $newbranch already exists" |
Junio C Hamano | 03feddd | 2005-10-13 18:57:39 -0700 | [diff] [blame] | 27 | git-check-ref-format "heads/$newbranch" || |
Josef Weidendorfer | babfaf8 | 2006-02-15 20:22:11 +0100 | [diff] [blame] | 28 | die "git checkout: we do not like '$newbranch' as a branch name." |
Linus Torvalds | 91dcdfd | 2005-07-11 20:44:20 -0700 | [diff] [blame] | 29 | ;; |
Shawn Pearce | 969d326 | 2006-05-19 05:17:16 -0400 | [diff] [blame] | 30 | "-l") |
| 31 | newbranch_log=1 |
| 32 | ;; |
Linus Torvalds | 303e5f4 | 2005-06-21 09:47:37 -0700 | [diff] [blame] | 33 | "-f") |
Linus Torvalds | e8b1174 | 2005-06-21 11:03:11 -0700 | [diff] [blame] | 34 | force=1 |
Linus Torvalds | 303e5f4 | 2005-06-21 09:47:37 -0700 | [diff] [blame] | 35 | ;; |
Junio C Hamano | 1be0659 | 2006-01-12 14:04:36 -0800 | [diff] [blame] | 36 | -m) |
| 37 | merge=1 |
| 38 | ;; |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 39 | --) |
| 40 | break |
| 41 | ;; |
Chris Shoemaker | b0bafe0 | 2005-10-29 17:46:41 -0400 | [diff] [blame] | 42 | -*) |
| 43 | usage |
| 44 | ;; |
Linus Torvalds | 303e5f4 | 2005-06-21 09:47:37 -0700 | [diff] [blame] | 45 | *) |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 46 | if rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null) |
| 47 | then |
| 48 | if [ -z "$rev" ]; then |
| 49 | echo "unknown flag $arg" |
| 50 | exit 1 |
| 51 | fi |
| 52 | new="$rev" |
Shawn Pearce | 969d326 | 2006-05-19 05:17:16 -0400 | [diff] [blame] | 53 | new_name="$arg^0" |
Linus Torvalds | 305e22c | 2006-09-15 14:56:55 -0700 | [diff] [blame] | 54 | if git-show-ref --verify --quiet -- "refs/heads/$arg" |
| 55 | then |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 56 | branch="$arg" |
| 57 | fi |
| 58 | elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null) |
| 59 | then |
| 60 | # checking out selected paths from a tree-ish. |
| 61 | new="$rev" |
Shawn Pearce | 969d326 | 2006-05-19 05:17:16 -0400 | [diff] [blame] | 62 | new_name="$arg^{tree}" |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 63 | branch= |
| 64 | else |
| 65 | new= |
Shawn Pearce | 969d326 | 2006-05-19 05:17:16 -0400 | [diff] [blame] | 66 | new_name= |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 67 | branch= |
| 68 | set x "$arg" "$@" |
| 69 | shift |
Linus Torvalds | e8b1174 | 2005-06-21 11:03:11 -0700 | [diff] [blame] | 70 | fi |
Junio C Hamano | 2608003 | 2006-07-31 03:07:12 -0700 | [diff] [blame] | 71 | case "$1" in |
| 72 | --) |
| 73 | shift ;; |
| 74 | esac |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 75 | break |
Linus Torvalds | e8b1174 | 2005-06-21 11:03:11 -0700 | [diff] [blame] | 76 | ;; |
Linus Torvalds | 303e5f4 | 2005-06-21 09:47:37 -0700 | [diff] [blame] | 77 | esac |
Linus Torvalds | 303e5f4 | 2005-06-21 09:47:37 -0700 | [diff] [blame] | 78 | done |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 79 | |
Junio C Hamano | 897643c | 2006-11-15 10:46:10 -0800 | [diff] [blame] | 80 | case "$force$merge" in |
| 81 | 11) |
| 82 | die "git checkout: -f and -m are incompatible" |
| 83 | esac |
| 84 | |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 85 | # The behaviour of the command with and without explicit path |
| 86 | # parameters is quite different. |
| 87 | # |
| 88 | # Without paths, we are checking out everything in the work tree, |
| 89 | # possibly switching branches. This is the traditional behaviour. |
| 90 | # |
| 91 | # With paths, we are _never_ switching branch, but checking out |
| 92 | # the named paths from either index (when no rev is given), |
| 93 | # or the named tree-ish (when rev is given). |
| 94 | |
| 95 | if test "$#" -ge 1 |
| 96 | then |
Josef Weidendorfer | babfaf8 | 2006-02-15 20:22:11 +0100 | [diff] [blame] | 97 | hint= |
| 98 | if test "$#" -eq 1 |
| 99 | then |
| 100 | hint=" |
| 101 | Did you intend to checkout '$@' which can not be resolved as commit?" |
| 102 | fi |
Junio C Hamano | 1be0659 | 2006-01-12 14:04:36 -0800 | [diff] [blame] | 103 | if test '' != "$newbranch$force$merge" |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 104 | then |
Josef Weidendorfer | babfaf8 | 2006-02-15 20:22:11 +0100 | [diff] [blame] | 105 | die "git checkout: updating paths is incompatible with switching branches/forcing$hint" |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 106 | fi |
| 107 | if test '' != "$new" |
| 108 | then |
| 109 | # from a specific tree-ish; note that this is for |
| 110 | # rescuing paths and is never meant to remove what |
| 111 | # is not in the named tree-ish. |
Junio C Hamano | d0d14cf | 2005-12-23 14:10:16 -0800 | [diff] [blame] | 112 | git-ls-tree --full-name -r "$new" "$@" | |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 113 | git-update-index --index-info || exit $? |
| 114 | fi |
Junio C Hamano | bf7e147 | 2006-11-15 10:54:10 -0800 | [diff] [blame] | 115 | |
| 116 | # Make sure the request is about existing paths. |
| 117 | git-ls-files --error-unmatch -- "$@" >/dev/null || exit |
| 118 | git-ls-files -- "$@" | |
| 119 | git-checkout-index -f -u --stdin |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 120 | exit $? |
| 121 | else |
| 122 | # Make sure we did not fall back on $arg^{tree} codepath |
| 123 | # since we are not checking out from an arbitrary tree-ish, |
| 124 | # but switching branches. |
| 125 | if test '' != "$new" |
| 126 | then |
| 127 | git-rev-parse --verify "$new^{commit}" >/dev/null 2>&1 || |
| 128 | die "Cannot switch branch to a non-commit." |
| 129 | fi |
| 130 | fi |
| 131 | |
Junio C Hamano | 104f3e0 | 2005-12-22 22:37:50 -0800 | [diff] [blame] | 132 | # We are switching branches and checking out trees, so |
| 133 | # we *NEED* to be at the toplevel. |
| 134 | cdup=$(git-rev-parse --show-cdup) |
| 135 | if test ! -z "$cdup" |
| 136 | then |
| 137 | cd "$cdup" |
| 138 | fi |
| 139 | |
Shawn Pearce | 969d326 | 2006-05-19 05:17:16 -0400 | [diff] [blame] | 140 | [ -z "$new" ] && new=$old && new_name="$old_name" |
Linus Torvalds | 303e5f4 | 2005-06-21 09:47:37 -0700 | [diff] [blame] | 141 | |
Linus Torvalds | 91dcdfd | 2005-07-11 20:44:20 -0700 | [diff] [blame] | 142 | # If we don't have an old branch that we're switching to, |
| 143 | # and we don't have a new branch name for the target we |
| 144 | # are switching to, then we'd better just be checking out |
| 145 | # what we already had |
Junio C Hamano | 4aaa702 | 2005-10-18 01:29:27 -0700 | [diff] [blame] | 146 | |
Linus Torvalds | 91dcdfd | 2005-07-11 20:44:20 -0700 | [diff] [blame] | 147 | [ -z "$branch$newbranch" ] && |
| 148 | [ "$new" != "$old" ] && |
Josef Weidendorfer | babfaf8 | 2006-02-15 20:22:11 +0100 | [diff] [blame] | 149 | die "git checkout: to checkout the requested commit you need to specify |
| 150 | a name for a new branch which is created and switched to" |
Linus Torvalds | 91dcdfd | 2005-07-11 20:44:20 -0700 | [diff] [blame] | 151 | |
Shawn Pearce | 5a03e7f | 2006-09-25 01:24:38 -0400 | [diff] [blame] | 152 | if [ "X$old" = X ] |
| 153 | then |
| 154 | echo "warning: You do not appear to currently be on a branch." >&2 |
| 155 | echo "warning: Forcing checkout of $new_name." >&2 |
| 156 | force=1 |
| 157 | fi |
| 158 | |
Linus Torvalds | a79944d | 2005-06-21 09:59:26 -0700 | [diff] [blame] | 159 | if [ "$force" ] |
Linus Torvalds | 303e5f4 | 2005-06-21 09:47:37 -0700 | [diff] [blame] | 160 | then |
Junio C Hamano | 4170af8 | 2006-06-20 02:47:14 -0700 | [diff] [blame] | 161 | git-read-tree --reset -u $new |
Linus Torvalds | 303e5f4 | 2005-06-21 09:47:37 -0700 | [diff] [blame] | 162 | else |
Junio C Hamano | 7f88c84 | 2005-09-11 14:12:08 -0700 | [diff] [blame] | 163 | git-update-index --refresh >/dev/null |
Junio C Hamano | 1be0659 | 2006-01-12 14:04:36 -0800 | [diff] [blame] | 164 | merge_error=$(git-read-tree -m -u $old $new 2>&1) || ( |
| 165 | case "$merge" in |
| 166 | '') |
| 167 | echo >&2 "$merge_error" |
| 168 | exit 1 ;; |
Junio C Hamano | 19205ac | 2006-01-11 23:07:27 -0800 | [diff] [blame] | 169 | esac |
| 170 | |
Junio C Hamano | 1be0659 | 2006-01-12 14:04:36 -0800 | [diff] [blame] | 171 | # Match the index to the working tree, and do a three-way. |
| 172 | git diff-files --name-only | git update-index --remove --stdin && |
Junio C Hamano | 19205ac | 2006-01-11 23:07:27 -0800 | [diff] [blame] | 173 | work=`git write-tree` && |
Junio C Hamano | abc0267 | 2006-06-28 11:47:28 -0700 | [diff] [blame] | 174 | git read-tree --reset -u $new && |
Junio C Hamano | 8d7a397 | 2006-05-09 19:23:23 -0700 | [diff] [blame] | 175 | git read-tree -m -u --aggressive $old $new $work || exit |
Junio C Hamano | 1be0659 | 2006-01-12 14:04:36 -0800 | [diff] [blame] | 176 | |
Junio C Hamano | 19205ac | 2006-01-11 23:07:27 -0800 | [diff] [blame] | 177 | if result=`git write-tree 2>/dev/null` |
| 178 | then |
Junio C Hamano | 1be0659 | 2006-01-12 14:04:36 -0800 | [diff] [blame] | 179 | echo >&2 "Trivially automerged." |
| 180 | else |
| 181 | git merge-index -o git-merge-one-file -a |
Junio C Hamano | 19205ac | 2006-01-11 23:07:27 -0800 | [diff] [blame] | 182 | fi |
Junio C Hamano | 1be0659 | 2006-01-12 14:04:36 -0800 | [diff] [blame] | 183 | |
| 184 | # Do not register the cleanly merged paths in the index yet. |
| 185 | # this is not a real merge before committing, but just carrying |
| 186 | # the working tree changes along. |
| 187 | unmerged=`git ls-files -u` |
| 188 | git read-tree --reset $new |
| 189 | case "$unmerged" in |
| 190 | '') ;; |
| 191 | *) |
| 192 | ( |
| 193 | z40=0000000000000000000000000000000000000000 |
| 194 | echo "$unmerged" | |
| 195 | sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" |
| 196 | echo "$unmerged" |
| 197 | ) | git update-index --index-info |
| 198 | ;; |
| 199 | esac |
| 200 | exit 0 |
Junio C Hamano | 19205ac | 2006-01-11 23:07:27 -0800 | [diff] [blame] | 201 | ) |
Junio C Hamano | 980d8ce | 2006-01-14 12:31:18 -0800 | [diff] [blame] | 202 | saved_err=$? |
Junio C Hamano | 504fe71 | 2006-02-14 16:05:57 -0800 | [diff] [blame] | 203 | if test "$saved_err" = 0 |
| 204 | then |
| 205 | test "$new" = "$old" || git diff-index --name-status "$new" |
| 206 | fi |
Junio C Hamano | 980d8ce | 2006-01-14 12:31:18 -0800 | [diff] [blame] | 207 | (exit $saved_err) |
Linus Torvalds | ef0bfa2 | 2005-06-21 15:40:00 -0700 | [diff] [blame] | 208 | fi |
| 209 | |
| 210 | # |
Junio C Hamano | 01385e2 | 2005-12-16 23:12:33 -0800 | [diff] [blame] | 211 | # Switch the HEAD pointer to the new branch if we |
Linus Torvalds | ef0bfa2 | 2005-06-21 15:40:00 -0700 | [diff] [blame] | 212 | # checked out a branch head, and remove any potential |
| 213 | # old MERGE_HEAD's (subsequent commits will clearly not |
| 214 | # be based on them, since we re-set the index) |
| 215 | # |
| 216 | if [ "$?" -eq 0 ]; then |
Linus Torvalds | 91dcdfd | 2005-07-11 20:44:20 -0700 | [diff] [blame] | 217 | if [ "$newbranch" ]; then |
Shawn Pearce | 969d326 | 2006-05-19 05:17:16 -0400 | [diff] [blame] | 218 | if [ "$newbranch_log" ]; then |
Shawn Pearce | d7fb7a3 | 2006-05-24 23:34:04 -0400 | [diff] [blame] | 219 | mkdir -p $(dirname "$GIT_DIR/logs/refs/heads/$newbranch") |
| 220 | touch "$GIT_DIR/logs/refs/heads/$newbranch" |
Shawn Pearce | 969d326 | 2006-05-19 05:17:16 -0400 | [diff] [blame] | 221 | fi |
| 222 | git-update-ref -m "checkout: Created from $new_name" "refs/heads/$newbranch" $new || exit |
Linus Torvalds | 91dcdfd | 2005-07-11 20:44:20 -0700 | [diff] [blame] | 223 | branch="$newbranch" |
| 224 | fi |
Junio C Hamano | 8098a17 | 2005-09-30 14:26:57 -0700 | [diff] [blame] | 225 | [ "$branch" ] && |
| 226 | GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch" |
Linus Torvalds | ef0bfa2 | 2005-06-21 15:40:00 -0700 | [diff] [blame] | 227 | rm -f "$GIT_DIR/MERGE_HEAD" |
tony.luck@intel.com | ab22707 | 2005-08-23 14:03:14 -0700 | [diff] [blame] | 228 | else |
| 229 | exit 1 |
Linus Torvalds | ef0bfa2 | 2005-06-21 15:40:00 -0700 | [diff] [blame] | 230 | fi |