]> git.ipfire.org Git - thirdparty/git.git/blame - git-checkout.sh
autoconf: Add tests for memmem, strtoumax and mkdtemp functions
[thirdparty/git.git] / git-checkout.sh
CommitLineData
303e5f4c 1#!/bin/sh
b33e9666 2
00df3bed
PH
3OPTIONS_KEEPDASHDASH=t
4OPTIONS_SPEC="\
5git-branch [options] [<branch>] [<paths>...]
6--
7b= create a new branch started at <branch>
8l create the new branchs reflog
9track tells if the new branch should track the remote branch
10f proceed even if the index or working tree is not HEAD
11m performa three-way merge on local modifications if needed
12q,quiet be quiet
13"
104f3e03 14SUBDIRECTORY_OK=Sometimes
806f36d4 15. git-sh-setup
7eff28a9 16require_work_tree
b0bafe03 17
969d326d 18old_name=HEAD
5be60078
JH
19old=$(git rev-parse --verify $old_name 2>/dev/null)
20oldbranch=$(git symbolic-ref $old_name 2>/dev/null)
e8b11749 21new=
969d326d 22new_name=
a79944d7 23force=
e8b11749 24branch=
0746d19a 25track=
91dcdfd3 26newbranch=
969d326d 27newbranch_log=
1be0659e 28merge=
6124aee5 29quiet=
4c474b6f 30v=-v
ead80606
JH
31LF='
32'
00df3bed
PH
33
34while test $# != 0; do
35 case "$1" in
36 -b)
91dcdfd3 37 shift
00df3bed 38 newbranch="$1"
91dcdfd3
LT
39 [ -z "$newbranch" ] &&
40 die "git checkout: -b needs a branch name"
5be60078 41 git show-ref --verify --quiet -- "refs/heads/$newbranch" &&
91dcdfd3 42 die "git checkout: branch $newbranch already exists"
5be60078 43 git check-ref-format "heads/$newbranch" ||
babfaf8d 44 die "git checkout: we do not like '$newbranch' as a branch name."
91dcdfd3 45 ;;
00df3bed 46 -l)
0746d19a
PB
47 newbranch_log=-l
48 ;;
00df3bed
PH
49 --track|--no-track)
50 track="$1"
969d326d 51 ;;
00df3bed 52 -f)
e8b11749 53 force=1
303e5f4c 54 ;;
1be0659e
JH
55 -m)
56 merge=1
57 ;;
00df3bed 58 -q|--quiet)
6124aee5 59 quiet=1
4c474b6f 60 v=
6124aee5 61 ;;
4aaa7027 62 --)
00df3bed 63 shift
4aaa7027
JH
64 break
65 ;;
303e5f4c 66 *)
00df3bed 67 usage
e8b11749 68 ;;
00df3bed
PH
69 esac
70 shift
303e5f4c
LT
71done
72
00df3bed
PH
73arg="$1"
74if rev=$(git rev-parse --verify "$arg^0" 2>/dev/null)
75then
76 [ -z "$rev" ] && die "unknown flag $arg"
77 new_name="$arg"
78 if git show-ref --verify --quiet -- "refs/heads/$arg"
79 then
80 rev=$(git rev-parse --verify "refs/heads/$arg^0")
81 branch="$arg"
82 fi
83 new="$rev"
84 shift
85elif rev=$(git rev-parse --verify "$arg^{tree}" 2>/dev/null)
86then
87 # checking out selected paths from a tree-ish.
88 new="$rev"
89 new_name="$arg^{tree}"
90 shift
91fi
92[ "$1" = "--" ] && shift
93
9debc324 94case "$newbranch,$track" in
0746d19a
PB
95,--*)
96 die "git checkout: --track and --no-track require -b"
97esac
98
897643cc
JH
99case "$force$merge" in
10011)
101 die "git checkout: -f and -m are incompatible"
102esac
103
4aaa7027
JH
104# The behaviour of the command with and without explicit path
105# parameters is quite different.
106#
107# Without paths, we are checking out everything in the work tree,
108# possibly switching branches. This is the traditional behaviour.
91dcdfd3 109#
4aaa7027
JH
110# With paths, we are _never_ switching branch, but checking out
111# the named paths from either index (when no rev is given),
112# or the named tree-ish (when rev is given).
113
114if test "$#" -ge 1
115then
babfaf8d
JW
116 hint=
117 if test "$#" -eq 1
118 then
119 hint="
120Did you intend to checkout '$@' which can not be resolved as commit?"
121 fi
1be0659e 122 if test '' != "$newbranch$force$merge"
4aaa7027 123 then
babfaf8d 124 die "git checkout: updating paths is incompatible with switching branches/forcing$hint"
4aaa7027
JH
125 fi
126 if test '' != "$new"
127 then
128 # from a specific tree-ish; note that this is for
129 # rescuing paths and is never meant to remove what
130 # is not in the named tree-ish.
5be60078
JH
131 git ls-tree --full-name -r "$new" "$@" |
132 git update-index --index-info || exit $?
4aaa7027 133 fi
bf7e1472
JH
134
135 # Make sure the request is about existing paths.
4307234a
DS
136 git ls-files --full-name --error-unmatch -- "$@" >/dev/null || exit
137 git ls-files --full-name -- "$@" |
138 (cd_to_toplevel && git checkout-index -f -u --stdin)
1abbe475 139
00df3bed
PH
140 # Run a post-checkout hook -- the HEAD does not change so the
141 # current HEAD is passed in for both args
1abbe475
JE
142 if test -x "$GIT_DIR"/hooks/post-checkout; then
143 "$GIT_DIR"/hooks/post-checkout $old $old 0
144 fi
145
4aaa7027
JH
146 exit $?
147else
148 # Make sure we did not fall back on $arg^{tree} codepath
149 # since we are not checking out from an arbitrary tree-ish,
150 # but switching branches.
151 if test '' != "$new"
152 then
5be60078 153 git rev-parse --verify "$new^{commit}" >/dev/null 2>&1 ||
4aaa7027
JH
154 die "Cannot switch branch to a non-commit."
155 fi
156fi
157
104f3e03
JH
158# We are switching branches and checking out trees, so
159# we *NEED* to be at the toplevel.
514c09fd 160cd_to_toplevel
104f3e03 161
969d326d 162[ -z "$new" ] && new=$old && new_name="$old_name"
4aaa7027 163
73c838e4 164# If we don't have an existing branch that we're switching to,
91dcdfd3 165# and we don't have a new branch name for the target we
73c838e4
JH
166# are switching to, then we are detaching our HEAD from any
167# branch. However, if "git checkout HEAD" detaches the HEAD
168# from the current branch, even though that may be logically
169# correct, it feels somewhat funny. More importantly, we do not
170# want "git checkout" nor "git checkout -f" to detach HEAD.
4aaa7027 171
bfbbb8f8
JH
172detached=
173detach_warn=
174
abba9dbb
JH
175describe_detached_head () {
176 test -n "$quiet" || {
177 printf >&2 "$1 "
178 GIT_PAGER= git log >&2 -1 --pretty=oneline --abbrev-commit "$2"
179 }
180}
181
3e0318a3 182if test -z "$branch$newbranch" && test "$new_name" != "$old_name"
c847f537 183then
bfbbb8f8 184 detached="$new"
6124aee5 185 if test -n "$oldbranch" && test -z "$quiet"
64886104 186 then
92cf9569 187 detach_warn="Note: moving to \"$new_name\" which isn't a local branch
d117452a
NP
188If you want to create a new branch from this checkout, you may do so
189(now or later) by using -b with the checkout command again. Example:
eb3204df 190 git checkout -b <new_branch_name>"
64886104 191 fi
3e0318a3 192elif test -z "$oldbranch" && test "$new" != "$old"
ead80606 193then
abba9dbb 194 describe_detached_head 'Previous HEAD position was' "$old"
c847f537 195fi
91dcdfd3 196
5a03e7f2
SP
197if [ "X$old" = X ]
198then
6124aee5
NP
199 if test -z "$quiet"
200 then
201 echo >&2 "warning: You appear to be on a branch yet to be born."
202 echo >&2 "warning: Forcing checkout of $new_name."
203 fi
5a03e7f2
SP
204 force=1
205fi
206
a79944d7 207if [ "$force" ]
303e5f4c 208then
5be60078 209 git read-tree $v --reset -u $new
303e5f4c 210else
5be60078
JH
211 git update-index --refresh >/dev/null
212 merge_error=$(git read-tree -m -u --exclude-per-directory=.gitignore $old $new 2>&1) || (
1be0659e
JH
213 case "$merge" in
214 '')
215 echo >&2 "$merge_error"
216 exit 1 ;;
19205acf
JH
217 esac
218
1be0659e 219 # Match the index to the working tree, and do a three-way.
a6080a0a 220 git diff-files --name-only | git update-index --remove --stdin &&
19205acf 221 work=`git write-tree` &&
4c474b6f 222 git read-tree $v --reset -u $new || exit
1be0659e 223
41f5d733 224 eval GITHEAD_$new='${new_name:-${branch:-$new}}' &&
d7ebd53d
JH
225 eval GITHEAD_$work=local &&
226 export GITHEAD_$new GITHEAD_$work &&
227 git merge-recursive $old -- $new $work
1be0659e
JH
228
229 # Do not register the cleanly merged paths in the index yet.
230 # this is not a real merge before committing, but just carrying
231 # the working tree changes along.
232 unmerged=`git ls-files -u`
4c474b6f 233 git read-tree $v --reset $new
1be0659e
JH
234 case "$unmerged" in
235 '') ;;
236 *)
237 (
238 z40=0000000000000000000000000000000000000000
239 echo "$unmerged" |
240 sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /"
241 echo "$unmerged"
242 ) | git update-index --index-info
243 ;;
244 esac
245 exit 0
19205acf 246 )
980d8ce5 247 saved_err=$?
6124aee5 248 if test "$saved_err" = 0 && test -z "$quiet"
504fe714 249 then
e4b0e4ab 250 git diff-index --name-status "$new"
504fe714 251 fi
980d8ce5 252 (exit $saved_err)
ef0bfa25
LT
253fi
254
a6080a0a 255#
01385e27 256# Switch the HEAD pointer to the new branch if we
ef0bfa25
LT
257# checked out a branch head, and remove any potential
258# old MERGE_HEAD's (subsequent commits will clearly not
259# be based on them, since we re-set the index)
260#
261if [ "$?" -eq 0 ]; then
91dcdfd3 262 if [ "$newbranch" ]; then
5be60078 263 git branch $track $newbranch_log "$newbranch" "$new_name" || exit
91dcdfd3
LT
264 branch="$newbranch"
265 fi
bfbbb8f8
JH
266 if test -n "$branch"
267 then
49aba0bb
SE
268 old_branch_name=`expr "z$oldbranch" : 'zrefs/heads/\(.*\)'`
269 GIT_DIR="$GIT_DIR" git symbolic-ref -m "checkout: moving from $old_branch_name to $branch" HEAD "refs/heads/$branch"
57216856 270 if test -n "$quiet"
e4b0e4ab 271 then
57216856
NP
272 true # nothing
273 elif test "refs/heads/$branch" = "$oldbranch"
274 then
275 echo >&2 "Already on branch \"$branch\""
276 else
6124aee5 277 echo >&2 "Switched to${newbranch:+ a new} branch \"$branch\""
e4b0e4ab 278 fi
bfbbb8f8
JH
279 elif test -n "$detached"
280 then
5be60078 281 git update-ref --no-deref -m "checkout: moving to $arg" HEAD "$detached" ||
bfbbb8f8
JH
282 die "Cannot detach HEAD"
283 if test -n "$detach_warn"
284 then
285 echo >&2 "$detach_warn"
286 fi
abba9dbb 287 describe_detached_head 'HEAD is now at' HEAD
bfbbb8f8 288 fi
ef0bfa25 289 rm -f "$GIT_DIR/MERGE_HEAD"
ab22707f
TL
290else
291 exit 1
ef0bfa25 292fi
1abbe475
JE
293
294# Run a post-checkout hook
295if test -x "$GIT_DIR"/hooks/post-checkout; then
00df3bed 296 "$GIT_DIR"/hooks/post-checkout $old $new 1
1abbe475 297fi