1#!/bin/sh 2 3USAGE='[-f] [-b <new_branch>] [<branch>] [<paths>...]' 4SUBDIRECTORY_OK=Sometimes 5. git-sh-setup 6 7old=$(git-rev-parse HEAD) 8new= 9force= 10branch= 11newbranch= 12while["$#"!="0"];do 13 arg="$1" 14shift 15case"$arg"in 16"-b") 17 newbranch="$1" 18shift 19[-z"$newbranch"] && 20 die "git checkout: -b needs a branch name" 21[-e"$GIT_DIR/refs/heads/$newbranch"] && 22 die "git checkout: branch$newbranchalready exists" 23 git-check-ref-format"heads/$newbranch"|| 24 die "we do not like '$newbranch' as a branch name." 25;; 26"-f") 27 force=1 28;; 29--) 30break 31;; 32-*) 33 usage 34;; 35*) 36ifrev=$(git-rev-parse --verify "$arg^0" 2>/dev/null) 37then 38if[-z"$rev"];then 39echo"unknown flag$arg" 40exit1 41fi 42 new="$rev" 43if[-f"$GIT_DIR/refs/heads/$arg"];then 44 branch="$arg" 45fi 46elifrev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null) 47then 48# checking out selected paths from a tree-ish. 49 new="$rev" 50 branch= 51else 52 new= 53 branch= 54set x "$arg""$@" 55shift 56fi 57break 58;; 59esac 60done 61 62# The behaviour of the command with and without explicit path 63# parameters is quite different. 64# 65# Without paths, we are checking out everything in the work tree, 66# possibly switching branches. This is the traditional behaviour. 67# 68# With paths, we are _never_ switching branch, but checking out 69# the named paths from either index (when no rev is given), 70# or the named tree-ish (when rev is given). 71 72iftest"$#"-ge1 73then 74iftest''!="$newbranch$force" 75then 76 die "updating paths and switching branches or forcing are incompatible." 77fi 78iftest''!="$new" 79then 80# from a specific tree-ish; note that this is for 81# rescuing paths and is never meant to remove what 82# is not in the named tree-ish. 83 git-ls-tree --full-name -r"$new""$@"| 84 git-update-index --index-info||exit $? 85fi 86 git-checkout-index -f -u --"$@" 87exit $? 88else 89# Make sure we did not fall back on $arg^{tree} codepath 90# since we are not checking out from an arbitrary tree-ish, 91# but switching branches. 92iftest''!="$new" 93then 94 git-rev-parse --verify"$new^{commit}">/dev/null 2>&1|| 95 die "Cannot switch branch to a non-commit." 96fi 97fi 98 99# We are switching branches and checking out trees, so 100# we *NEED* to be at the toplevel. 101cdup=$(git-rev-parse --show-cdup) 102iftest!-z"$cdup" 103then 104cd"$cdup" 105fi 106 107[-z"$new"] && new=$old 108 109# If we don't have an old branch that we're switching to, 110# and we don't have a new branch name for the target we 111# are switching to, then we'd better just be checking out 112# what we already had 113 114[-z"$branch$newbranch"] && 115["$new"!="$old"] && 116 die "git checkout: you need to specify a new branch name" 117 118if["$force"] 119then 120 git-read-tree --reset$new&& 121 git-checkout-index -q -f -u -a 122else 123 git-update-index --refresh>/dev/null 124 git-read-tree -m -u$old $new 125fi 126 127# 128# Switch the HEAD pointer to the new branch if we 129# checked out a branch head, and remove any potential 130# old MERGE_HEAD's (subsequent commits will clearly not 131# be based on them, since we re-set the index) 132# 133if["$?"-eq0];then 134if["$newbranch"];then 135 leading=`expr "refs/heads/$newbranch" : '\(.*\)/'`&& 136mkdir-p"$GIT_DIR/$leading"&& 137echo$new>"$GIT_DIR/refs/heads/$newbranch"||exit 138 branch="$newbranch" 139fi 140["$branch"] && 141 GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch" 142rm-f"$GIT_DIR/MERGE_HEAD" 143else 144exit1 145fi