#!/bin/sh
-USAGE='[-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
+USAGE='[-q] [-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
SUBDIRECTORY_OK=Sometimes
. git-sh-setup
require_work_tree
new_name=
force=
branch=
+track=
newbranch=
newbranch_log=
merge=
+quiet=
+v=-v
LF='
'
while [ "$#" != "0" ]; do
die "git checkout: we do not like '$newbranch' as a branch name."
;;
"-l")
- newbranch_log=1
+ newbranch_log=-l
+ ;;
+ "--track"|"--no-track")
+ track="$arg"
;;
"-f")
force=1
-m)
merge=1
;;
+ "-q")
+ quiet=1
+ v=
+ ;;
--)
break
;;
esac
done
+case "$newbranch,$track" in
+,--*)
+ die "git checkout: --track and --no-track require -b"
+esac
+
case "$force$merge" in
11)
die "git checkout: -f and -m are incompatible"
detached=
detach_warn=
-if test -z "$branch$newbranch" && test "$new" != "$old"
+describe_detached_head () {
+ test -n "$quiet" || {
+ printf >&2 "$1 "
+ GIT_PAGER= git log >&2 -1 --pretty=oneline --abbrev-commit "$2"
+ }
+}
+
+if test -z "$branch$newbranch" && test "$new_name" != "$old_name"
then
detached="$new"
- if test -n "$oldbranch"
+ if test -n "$oldbranch" && test -z "$quiet"
then
- detach_warn="warning: you are not on ANY branch anymore.
-If you meant to create a new branch from the commit, you need -b to
-associate a new branch with the wanted checkout. Example:
- git checkout -b <new_branch_name> $arg"
+ detach_warn="Note: moving to \"$new_name\" which isn't a local branch
+If you want to create a new branch from this checkout, you may do so
+(now or later) by using -b with the checkout command again. Example:
+ git checkout -b <new_branch_name>"
fi
-elif test -z "$oldbranch" && test -n "$branch"
+elif test -z "$oldbranch" && test "$new" != "$old"
then
- # Coming back...
- if test -z "$force"
- then
- git show-ref -d -s | grep "$old" >/dev/null || {
- echo >&2 \
-"You are not on any branch and switching to branch '$new_name'
-may lose your changes. At this point, you can do one of two things:
- (1) Decide it is Ok and say 'git checkout -f $new_name';
- (2) Start a new branch from the current commit, by saying
- 'git checkout -b <branch-name>'.
-Leaving your HEAD detached; not switching to branch '$new_name'."
- exit 1;
- }
- fi
+ describe_detached_head 'Previous HEAD position was' "$old"
fi
if [ "X$old" = X ]
then
- echo >&2 "warning: You appear to be on a branch yet to be born."
- echo >&2 "warning: Forcing checkout of $new_name."
+ if test -z "$quiet"
+ then
+ echo >&2 "warning: You appear to be on a branch yet to be born."
+ echo >&2 "warning: Forcing checkout of $new_name."
+ fi
force=1
fi
if [ "$force" ]
then
- git-read-tree --reset -u $new
+ git-read-tree $v --reset -u $new
else
git-update-index --refresh >/dev/null
merge_error=$(git-read-tree -m -u --exclude-per-directory=.gitignore $old $new 2>&1) || (
# Match the index to the working tree, and do a three-way.
git diff-files --name-only | git update-index --remove --stdin &&
work=`git write-tree` &&
- git read-tree --reset -u $new &&
- eval GITHEAD_$new=${new_name:-${branch:-$new}} GITHEAD_$work=local &&
- export GITHEAD_$new GITHEAD_$work &&
- git merge-recursive $old -- $new $work || exit
+ git read-tree $v --reset -u $new || exit
- if result=`git write-tree 2>/dev/null`
- then
- echo >&2 "Trivially automerged."
- else
- git merge-index -o git-merge-one-file -a
- fi
+ eval GITHEAD_$new='${new_name:-${branch:-$new}}' &&
+ eval GITHEAD_$work=local &&
+ export GITHEAD_$new GITHEAD_$work &&
+ git merge-recursive $old -- $new $work
# Do not register the cleanly merged paths in the index yet.
# this is not a real merge before committing, but just carrying
# the working tree changes along.
unmerged=`git ls-files -u`
- git read-tree --reset $new
+ git read-tree $v --reset $new
case "$unmerged" in
'') ;;
*)
exit 0
)
saved_err=$?
- if test "$saved_err" = 0
+ if test "$saved_err" = 0 && test -z "$quiet"
then
- test "$new" = "$old" || git diff-index --name-status "$new"
+ git diff-index --name-status "$new"
fi
(exit $saved_err)
fi
#
if [ "$?" -eq 0 ]; then
if [ "$newbranch" ]; then
- if [ "$newbranch_log" ]; then
- mkdir -p $(dirname "$GIT_DIR/logs/refs/heads/$newbranch")
- touch "$GIT_DIR/logs/refs/heads/$newbranch"
- fi
- git-update-ref -m "checkout: Created from $new_name" "refs/heads/$newbranch" $new || exit
+ git-branch $track $newbranch_log "$newbranch" "$new_name" || exit
branch="$newbranch"
fi
if test -n "$branch"
then
- GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch"
+ GIT_DIR="$GIT_DIR" git-symbolic-ref -m "checkout: moving to $branch" HEAD "refs/heads/$branch"
+ if test -n "$quiet"
+ then
+ true # nothing
+ elif test "refs/heads/$branch" = "$oldbranch"
+ then
+ echo >&2 "Already on branch \"$branch\""
+ else
+ echo >&2 "Switched to${newbranch:+ a new} branch \"$branch\""
+ fi
elif test -n "$detached"
then
# NEEDSWORK: we would want a command to detach the HEAD
# git update-ref --detach HEAD $new
# or something like that...
#
- echo "$detached" >"$GIT_DIR/HEAD.new" &&
- mv "$GIT_DIR/HEAD.new" "$GIT_DIR/HEAD" ||
+ git-rev-parse HEAD >"$GIT_DIR/HEAD.new" &&
+ mv "$GIT_DIR/HEAD.new" "$GIT_DIR/HEAD" &&
+ git-update-ref -m "checkout: moving to $arg" HEAD "$detached" ||
die "Cannot detach HEAD"
if test -n "$detach_warn"
then
echo >&2 "$detach_warn"
fi
+ describe_detached_head 'HEAD is now at' HEAD
fi
rm -f "$GIT_DIR/MERGE_HEAD"
else