Git命令列表--git-checkout

Git Checkout

名称

git-Checkout - 切换分支或恢复工作树文件

语法

git checkout [-q] [-f] [-m] [<branch>]
git checkout [-q] [-f] [-m] --detach [<branch>]
git checkout [-q] [-f] [-m] [--detach] <commit>
git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
## 切换分支
git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <pathspec>…​
git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] --pathspec-from-file=<file> [--pathspec-file-nul]
git checkout (-p|--patch) [<tree-ish>] [--] [<pathspec>]
## 更新工作树中的文件,数据从版本库或者暂存区获取
## tree-ish 指定的提交点,如果不指定,则从暂存区中获取数据
## pathspec 需要更新的文件路径

更新工作树中的文件以匹配索引或指定树中的版本。如果没有给出路径规范 -- pathspec,git checkout也会更新HEAD以将指定的分支设置为当前分支。也就是切换分支的功能效果

使用

## 项目当前分支状态
$ git branch -a -vv 
  dev                  26e602f [origin/dev] dev commit
* main                 9df539e [origin/main] main file
  relea                c76aaf9 [origin/relea] rele
  remotes/origin/HEAD  -> origin/main
  remotes/origin/dev   26e602f dev commit
  remotes/origin/main  9df539e main file
  remotes/origin/relea c76aaf9 rele
  
## 删除分支dev relea 
$ git branch -d dev relea 
warning: deleting branch 'dev' that has been merged to
         'refs/remotes/origin/dev', but not yet merged to HEAD.
warning: deleting branch 'relea' that has been merged to
         'refs/remotes/origin/relea', but not yet merged to HEAD.
Deleted branch dev (was 26e602f).  
Deleted branch relea (was c76aaf9).

git checkout [<branch>]

为了准备在<分支>上工作,通过更新工作树中的索引和文件,并将HEAD指向分支来切换到它。保留对工作树中文件的本地修改,以便它们可以提交到<分支>。

--no-guess

如果未找到<branch>,但在一个具有匹配名称的远程(将其称为<远程>)中确实存在跟踪分支,并且未指定--no-guess,则将其视为等效于 git checkout -b <branch> --track <remote>/<branch>

## 当一个分支在本地和远程都找不到时会报错
xuyuansheng@XUYUANSHENG MINGW64 /d/VSCode/testgit (main)
$ git checkout abc
error: pathspec 'abc' did not match any file(s) known to git
## 如果本地没有该分支,远程有时就会从远程拉取分支 
xuyuansheng@XUYUANSHENG MINGW64 /d/VSCode/testgit (main)
$ git checkout --no-guess  dev  
error: pathspec 'dev' did not match any file(s) known to git
$ git checkout dev 
Switched to a new branch 'dev'
Branch 'dev' set up to track remote branch 'dev' from 'origin'.
## 当着分支状态
$ git log --pretty=oneline --graph main dev 
* 9df539ee86586d32d4349aa19e235941926cefec (origin/main, origin/HEAD, main) main file
| * 26e602f538ab6a74ac985853690136e064cbe172 (HEAD -> dev, origin/dev) dev commit    
| * 1d40930975eaeef50830c457bdcd7811db6ef173 first main commit
|/
* a94823afd688061ad02285591fb36a7dbeb520dd Initial commit

-t / --track

您可以省略<branch>,在这种情况下,命令退化为“签出当前分支”,这是一种美化的无操作,具有相当昂贵的副作用,仅显示当前分支的跟踪信息(如果存在)。

$ git checkout  --track origin/relea
Switched to a new branch 'relea'
Branch 'relea' set up to track remote branch 'relea' from 'origin'.

-b|-B 创建新分支

git checkout -b|-B <new_branch> []

指定-b会创建一个新分支,就像 调用git-branch(1)然后签出一样。在这种情况下,您可以使用--trackor--no-track选项,它将被传递给git branch。为方便起见, --track没有-b意味着创建分支;见下面的描述--track

如果-B给出,<new_branch>则在不存在时创建;否则,它被重置。

## 查看当前分支状态和提交log
$ git branch -vv 
  dev   26e602f [origin/dev] dev commit
  main  9df539e [origin/main] main file
* relea c76aaf9 [origin/relea] rele
$ git log --pretty=oneline 
c76aaf9fef36c80c2a315a2c4e859f1582270ec3 (HEAD -> relea, origin/relea) rele
26e602f538ab6a74ac985853690136e064cbe172 (origin/dev, dev) dev commit
1d40930975eaeef50830c457bdcd7811db6ef173 first main commit
a94823afd688061ad02285591fb36a7dbeb520dd Initial commit

## -b  创建并切换到新分支
$ git checkout -b fromRelea 1d40930975eaeef50830c457bdcd7811db6ef173 
Switched to a new branch 'fromRelea'
$  git log --pretty=oneline 
1d40930975eaeef50830c457bdcd7811db6ef173 (HEAD -> fromRelea) first main commit
a94823afd688061ad02285591fb36a7dbeb520dd Initial commit
## 再来一次,失败了、因为分支已经存在
$ git checkout -b fromRelea 
fatal: A branch named 'fromRelea' already exists.
## 使用-B 强制签出,这里会重置已经存在的分支
$ git  checkout relea 
$ git checkout -B  fromRelea
Switched to and reset branch 'fromRelea'
$ git log --pretty=oneline
c76aaf9fef36c80c2a315a2c4e859f1582270ec3 (HEAD -> fromRelea, origin/relea, relea) rele
26e602f538ab6a74ac985853690136e064cbe172 (origin/dev, dev) dev commit
1d40930975eaeef50830c457bdcd7811db6ef173 first main commit
a94823afd688061ad02285591fb36a7dbeb520dd Initial commit

--detach 分离头指针

git checkout --detach [<branch>] / git checkout [--detach] <commit>

准备在 之上工作<commit>,方法是HEAD在它上分离,并更新工作树中的索引和文件。保留对工作树中文件的本地修改,因此生成的工作树将是提交中记录的状态加上本地修改。当<commit>参数是分支名称时,该--detach选项可用于HEAD在分支的HEAD分离(git checkout <branch>将在不分离的情况下检查该分支HEAD)。在当前分支的HEAD省略<branch>分离HEAD

$ git checkout dev 
$ cat .git/HEAD
ref: refs/heads/relea
## HEAD指向relea分支,相当于间接指向提交 c76aaf9
$ cat .git/refs/heads/relea
c76aaf9fef36c80c2a315a2c4e859f1582270ec3
$ git log --pretty=reference
c76aaf9 (rele, 2022-10-25)
26e602f (dev commit, 2022-10-25)
1d40930 (first main commit, 2022-10-25)
a94823a (Initial commit, 2022-10-25)
## --detach ,HEAD会直接指向特定的commit ,此时不在任何分支上
$ git checkout --detach dev 
HEAD is now at 26e602f dev commit
Your branch is up to date with 'origin/dev' 
$ git checkout --detach 26e602f 
HEAD is now at 26e602f dev commit
$  cat .git/HEAD
26e602f538ab6a74ac985853690136e064cbe172
## 此时会可以在当前commit上创建新分支

-- <pathspec> 限制受checkout 操作影响的路径

如果没有指定时pathspec,会更新HEAD以将指定的分支设置为当前分支或HEAD指定指定commit

语法: git checkout [<tree-ish>] [--] [<pathspec>... ]

<tree-ish> checkout的树(当给出路径时)。如果未指定,将使用索引(HEAD)。

$ git branch -vv 
  dev       26e602f [origin/dev] dev commit
  fromRelea c76aaf9 rele
  main      9df539e [origin/main] main file
* relea     95ef627 [origin/relea: ahead 1] commit dev file in relea
## 在当前分支(relea)修改文件dev 
$ echo 'edit file in relea' >> dev
$ git add dev 
$ echo 'edit one more time' >> dev
$ git status 
On branch relea
Your branch is ahead of 'origin/relea' by 1 commit.
  (use "git push" to publish your local commits)
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   dev
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   dev
## 查看(索引)暂存区、工作树、Git库中dev文件内容
$ git ls-files --stage |grep  -E 'dev$'  |awk '{print$2}' |xargs git cat-file -p
dev file in relea
edit file in relea
## 查看Git库中文件内容(真难,有谁知道更好的办法请告诉我)
$ git cat-file -p  HEAD |grep tree |awk '{print$2}' |xargs git cat-file -p |grep  -E 'dev$' |awk '{print$3}' |xargs git cat-file -p 
dev file in relea
## 查看工作树中文件
$ cat dev
dev file in relea
edit file in relea
edit one more time
## checkout 签出dev文件内容
##  错误,提示你本地有未提交的修改,无法切换到dev,这时候dev被识别为了一个分支
$ git checkout  dev
error: Your local changes to the following files would be overwritten by checkout:
        dev
Please commit your changes or stash them before you switch branches.
Aborting
##使用-- <pathspec> 语法,成功签出,dev文件的内容变成了暂存区的内容,所以不指定tree-ish时默认是从暂存区签出
$ git checkout  -- dev
$ cat dev
dev file in relea
edit file in relea
##  指定tree-ish时,就会从指定的树(git中的树对象,不是工作树worktree)中签出文件内容
$ git checkout HEAD  -- dev
$ cat dev
dev file in relea

-p/--patch

git checkout (-p|--patch) [<tree-ish>] [--] [<pathspec>... ]

<tree-ish>在和工作树之间的差异中以交互方式选择大块(hunk ) 。然后将选择的块反向应用于工作树(如果<tree-ish>指定了,则为索引)。这意味着您可以使用它git checkout -p来选择性地丢弃当前工作树中的编辑。请参阅git-add(1)的“交互模式”部分以了解如何操作该--patch模式。请注意,此选项默认使用无覆盖模式(另请参阅 --overlay),目前不支持覆盖模式。

## 接上例 ,再次修改dev文件文件内容后
$ git status 
On branch relea
Your branch is ahead of 'origin/relea' by 1 commit.
  (use "git push" to publish your local commits)
Changes to be committed:
        modified:   dev
Changes not staged for commit:
        modified:   dev
## 以交互的模式签出指定文件
$ git checkout -p -- dev
diff --git a/dev b/dev
index 5753032..228d0b0 100644
--- a/dev
+++ b/dev
@@ -1,2 +1,3 @@
 dev file in relea
 edit file in relea
+edit dev noe more time agin
\ No newline at end of file
## 从工作树中丢弃这个大块头?? y=yes,n=no,q=quit...,具体交互方式参阅git-add
(1/1) Discard this hunk from worktree [y,n,q,a,d,e,?]?
## 输入y后 ,工作树中修改的内容被回退到暂存区一样了
$ git diff  -- dev

## 指定<tree-ish>,这时会将tree-ish与工作树(worktree)对比
$ git checkout -p HEAD  -- dev
diff --git a/dev b/dev
index f3e3544..e0b2374 100644
--- a/dev
+++ b/dev
@@ -1 +1,3 @@
 dev file in relea
+edit file in relea
+asfdadasdasf
\ No newline at end of file
## 第一次输入了yes,但是提示错误,因为这个修改块(hunk)没有应用到(索引)暂存区中
(1/1) Discard this hunk from index and worktree [y,n,q,a,d,e,?]? y
error: patch failed: dev:1      
error: dev: patch does not apply
The selected hunks do not apply to the index!
Apply them to the worktree anyway? y
## 上面再次输入yes,工作树中dev文件内容变为了和HEAD中文件一样
$ cat  dev
dev file in relea
$ git diff  -- dev
diff --git a/dev b/dev
index 5753032..f3e3544 100644
--- a/dev
+++ b/dev
@@ -1,2 +1 @@
 dev file in relea
-edit file in relea

--ignore-other-worktrees 忽略其他工作树

git checkout当想要的 ref 已经被另一个工作树签出时拒绝。这个选项使它无论如何都要检查参考。换句话说,ref 可以被多个工作树保存

$ git reset --hard HEAD 
HEAD is now at 95ef627 commit dev file in relea
$ git branch -vv
  dev       26e602f [origin/dev] dev commit
  fromRelea c76aaf9 rele
  main      9df539e [origin/main] main file
* relea     95ef627 [origin/relea: ahead 1] commit dev file in relea
## 从dev分支新建一个工作树
$ git  worktree add ../wtree_dev   dev
Preparing worktree (checking out 'dev')
HEAD is now at 26e602f dev commi
## 切换到新的工作树目录并查看分支状态(去掉了无关的分支)
$ cd ../wtree_dev/ && git branch -v
* dev       26e602f dev commit
  wtree     95ef627 commit dev file in relea
user@NAME MINGW64 /d/VSCode/wtree_dev (dev)
## 切换回Git仓库,并签出到指定(dev)分支
$ cd ../testgit/
$ git checkout dev 
fatal: 'dev' is already checked out at 'D:/VSCode/wtree_dev'
## --ignore-other-worktrees  忽略其他工作树 
$ git checkout --ignore-other-worktrees dev 
Switched to branch 'dev'
Your branch is up to date with 'origin/dev'.

--overwrite-ignore 覆盖忽略的文件(默认)

--no-overwrite-ignore

切换分支时静默覆盖忽略的文件。这是默认行为。--no-overwrite-ignore当新分支包含被忽略的文件时,用于中止操作。

$ git checkout relea
## 添加.gitignore文件(内容为 *.sh),并提交后,新建一个ab.sh文件
$ echo 'sadfa' >  ab.sh
## 没有看懂,后续再看

--overlay /--no-overlay

在默认覆盖模式下,git checkout从不从索引或工作树中删除文件。指定--no-overlay时,将删除出现在索引和工作树中但不在其中的<tree-ish>文件,以使它们<tree-ish>完全匹配。

## 没有看懂,后续再看

-m / --merge

切换分支时,如果您对一个或多个在当前分支和您要切换到的分支之间不同的文件进行了本地修改,该命令将拒绝切换分支以在上下文中保留您的修改。但是,使用此选项,当前分支、工作树内容和新分支之间的三向合并完成,您将位于新分支上。

当发生合并冲突时,冲突路径的索引条目将保持未合并,您需要解决冲突并将已解决的路径标记为git add(或者git rm如果合并应该导致删除路径)。从索引中检出路径时,此选项允许您在指定路径中重新创建冲突的合并。使用 切换分支时--merge,分阶段的更改可能会丢失。

## 当前两个分支的状态,从26e602f分离后,relea分支有一个提交,dev分支有两个提交
$ git log --oneline --graph    dev  relea  --
* b14e821 (dev) README commit in dev
* 19957b7 add ignore
| * c76aaf9 (HEAD -> relea, origin/relea) rele
|/  
* 26e602f (origin/dev) dev commit
* 1d40930 first main commit
* a94823a Initial commit
## 本地有修改的文件 直接checkout会报错
$ git checkout dev 
error: Your local changes to the following files would be overwritten by checkout:
        README.md
Please commit your changes or stash them before you switch branches.
Aborting
##   在(索引)暂存区的内容有变动时也无法checkout
$ git checkout -m dev
fatal: cannot continue with staged changes in the following files:
README.md dev
##  restore 重置暂存区后
$ git checkout -m  dev
Switched to branch 'dev'
M       README.md
Your branch is ahead of 'origin/dev' by 2 commits.
  (use "git push" to publish your local commits)
## relea分支修改的文件被merge过来了
$ git status -sb 
dev...origin/dev [ahead 2]
UU README.md
?? dev
##  relea提交过的commit没有merge过来
$ git log --oneline --graph    dev  relea  -- 
* b14e821 (HEAD -> dev) README commit in dev
* 19957b7 add ignore
| * c76aaf9 (origin/relea, relea) rele
|/
* 26e602f (origin/dev) dev commit
* 1d40930 first main commit
* a94823a Initial commit

--orphan <new_branch>

创建一个新的孤立分支,命名为<new_branch>,开始于 <start_point>并切换到它。在这个新分支上进行的第一次提交将没有父母,它将成为与所有其他分支和提交完全断开的新历史的根。索引和工作树的调整就像您之前运行过一样 git checkout <start_point>。这允许您开始一个新的历史记录,该历史记录记录一组类似于<start_point>通过轻松运行 git commit -a以进行根提交的路径。

当您想从提交中发布树而不暴露其完整历史时,这可能很有用。您可能希望这样做以发布一个项目的开源分支,该项目的当前树是“干净的”,但其完整历史记录包含专有或其他受累的代码位。如果要开始记录一组完全不同的路径的断开连接的历史记录<start_point>,则应在创建孤立分支后立即通过git rm -rf .从工作树的顶层运行来清除索引和工作树。之后,您将准备好准备新文件、重新填充工作树、从其他地方复制它们、提取 tarball 等。

$ git log --pretty=oneline
582753e3e445ad3ae52b7b4c92e9dd49aacb408b (HEAD -> dev) 二次提交
9f486a25f360136435b671727010d15dd683516b dev commit
b14e8215f41eb16f55de50a50f12a6420477cd47 README commit in dev
19957b719c0f15b8ac9569290a956953f7f7ca68 add ignore
26e602f538ab6a74ac985853690136e064cbe172 (origin/dev) dev commit
1d40930975eaeef50830c457bdcd7811db6ef173 first main commit
a94823afd688061ad02285591fb36a7dbeb520dd Initial commit
## 此时Git库中还没有dev文件
$ git cat-file --filters b14e8215f41eb16f55de50a50f12a6420477cd47:dev
fatal: Not a valid object name b14e8215f41eb16f55de50a50f12a6420477cd47:dev
## dev文件被添加到库中并提交
$ git cat-file --filters 9f486a25f360136435b671727010d15dd683516b:dev
dev file init
## dev文件被修改后并提交
$ git cat-file --filters 582753e3e445ad3ae52b7b4c92e9dd49aacb408b:dev
dev file initdev edit first time
## 从指定的提交(commit)切换到新分支
$ git checkout  --orphan=new_branch_from  9f486a25f360136435b671727010d15dd683516b 
Switched to a new branch 'new_branch_from'
## 新的分支并没有任何提交,需要我们重新去commit,文件的内容就是从这个commit快照中来的
$ git status -sb 
## No commits yet on new_branch_from
A  .gitignore
A  README.md
A  ab.sh
A  dev
A  dev.txt
$ cat dev
dev file init
## 切换回dev 分支 
$ git checkout --no-merge -f dev
Switched to branch 'dev'
Your branch is ahead of 'origin/dev' by 4 commits.
  (use "git push" to publish your local commits)  
## 再次切换到新分支,发现dev文件的内容是提交582753e3快照中的内容
$ git checkout  --orphan=new_branch_from  582753e3e445ad3ae52b7b4c92e9dd49aacb408b
Switched to a new branch 'new_branch_from'
$ cat dev
dev file initdev edit first time
posted @ 2023-02-12 20:29  菜阿  阅读(651)  评论(0编辑  收藏  举报