Git
简体中文 ▾ Topics ▾ Latest version ▾ git-checkout last updated in 2.44.0

名称

git-checkout - 切换分支或恢复工作目录树文件

概述

git checkout [-q] [-f] [-m] [<分支>]
git checkout [-q] [-f] [-m] --detach [<分支>]
git checkout [-q] [-f] [-m] [--detach] <提交>
git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <新分支>] [<起始点>]
git checkout [-f] <目录树对象> [--] <路径规范>…​
git checkout [-f] <目录树对象> --pathspec-from-file=<文件> [--pathspec-file-nul]
git checkout [-f|--ours|--theirs|-m|--conflict=<样式>] [--] <路径规范>…​
git checkout [-f|--ours|--theirs|-m|--conflict=<样式>] --pathspec-from-file=<文件> [--pathspec-file-nul]
git checkout (-p|--patch) [<目录树对象>] [--] [<路径规范>…​]

描述

更新工作区中的文件,使其与索引或指定的树中的版本一致。 如果没有给出pathspec,'git checkout’也将更新`HEAD`,将指定的分支设为当前分支。

git checkout [<分支>]

要准备在`<分支>上工作,需要更新索引和工作区中的文件,以及将`HEAD`指向该分支来切换到该分支。对工作区中文件的本地修改会被保留,以便修改可以被提交到<分支>`。

如果没有找到该`<分支>,但正好一个远程(称其为<远程仓库>)中确实存在一个名称相匹配的已跟踪分支,并且没有指定--no-guess`,则视为等同于

$ git checkout -b <分支> --track <远程仓库>/<分支>

你可以省略 <分支>,在这种情况下,该命令会退化为 “检出当前分支”,这是一个美化的无操作,具有非常大的副作用,如果存在当前分支的话,只显示当前分支的跟踪信息。

git checkout -b|-B <新分支> [<起始点>]

指定 -b 会导致一个新的分支被创建,就像调用 git-branch[1] 然后签出一样。 在这种情况下,你可以使用 --track--no-track 选项,它们将被传递给 git branch。 为方便起见,--track`不加-b`意味着创建分支;见下文对`--track`的描述。

如果给定了 -B,如果不存在 <新分支>,就会创建;否则,就会重置。这在事务上等同于

$ git branch -f <分支> [<起始点>]
$ git checkout <分支>

也就是说,除非 "git checkout" 成功,否则不会重置/创建分支(例如,当分支在另一个工作树中使用时,不仅当前分支保持不变,分支也不会重置为起点)。

git checkout --detach [<分支>]
git checkout [--detach] <提交>

准备在 <提交> 上工作,通过分离 HEAD 来实现(参见 "DETACHED HEAD" 部分),并更新工作区中的索引和文件。 对工作区中的文件的本地修改会被保留,所以最终的工作区将是提交时记录的状态加上本地的修改。

当`<提交>参数是一个分支名称时,--detach`选项可以用来分离分支顶端的`HEAD`(git checkout <分支>`会签出该分支而不分离`HEAD)。

省略`<分支>会在当前分支的顶端分离`HEAD

git checkout [-f|--ours|--theirs|-m|--conflict=<样式>] [<目录树对象>] [--] <路径规范>…​
git checkout [-f|--ours|--theirs|-m|--conflict=<样式>] [<树状对象>] --pathspec-from-file=<文件> [--pathspec-file-nul]

覆盖符合路径对范文件的内容。 当没有给出`<树状对象>(最常见的是提交),用索引中的内容覆盖工作区。 当<树状对象>被给出时,用<树状对象>`处的内容覆盖索引和工作区。

索引可能包含因之前合并失败导致的未合并条目。 默认情况下,如果你试图从索引中签出这样的条目,签出操作将失败,没有任何东西被签出。 使用 -f 将忽略这些未合并的条目。 通过使用 --ours--theirs 选项,可以从索引中检出合并的特定一方的内容。 使用`-m`,对工作区文件的修改可以被丢弃,以重新创建原冲突合并的结果。

git checkout (-p|--patch) [<树状对象>] [--] [<路径规范>…​]

这与前面的模式类似,但让你使用交互式界面来显示 "diff "输出,并选择在结果中使用哪些代码块。 关于`--patch`选项的描述,见下文。

选项

-q
--quiet

静默,压制反馈信息。

--progress
--no-progress

当它附加到终端时,除非指定 --quiet,否则默认情况下会在标准错误流中报告进度状态。这个标志可以启用进度报告,即使没有附在到终端,而不管 --quiet

-f
--force

当切换分支时,即使索引或工作区与`HEAD`不同,即使有未追踪的文件挡住去路,也要继续。 这是用来丢弃本地修改和任何碍事的未追踪文件或目录的。

当从索引中检查出路径时,不将未合并条目视为失败;相反,忽略未合并条目。

--ours
--theirs

当从索引中检查出路径时,要检查第二阶段(ours)或第三阶段(theirs)的未合并路径。

注意在 git rebasegit pull --rebase 过程中,"ours" 和 "theirs" 可能会互换;--ours 给出了分支变基后的版本,而 --theirs 则给出你即将变基的分支版本。

这是因为 "rebase"在工作流程中使用,它将远程的历史视为共享的规范历史,并将在你重命名的分支上所做的工作视为需要整合的第三方工作,而你在重命名过程中暂时承担了规范历史守护者的角色。 作为规范历史的守护者,你需要将远程的历史视为 "ours"(即 "我们共享的规范历史"),而将你在侧边分支上的工作视为 "their"(即 "一个贡献者在上面所作的工作")。

-b <新分支>

创建一个名为"<新分支>"的新分支,从"<起点>"开始,并检出产生的分支;详情见 git-branch[1]

-B <新分支>

从`<起点>开始,创建分支<新分支>;如果分支已经存在,则重置为<起点>`。然后检出生成的分支。这相当于用 "-f"选项 运行 "git branch" ,然后用 "git checkout" 检出该分支;详见 git-branch[1]

-t
--track[=(direct|inherit)]

创建新分支时,要设置 "上游"配置。详情见 git-branch[1] 中的 "--track"。

如果没有给出`-b`选项,新分支的名称将从远程跟踪分支中推导出来,方法是查看为相应的远程配置引用规范的本地部分,然后剥离初始部分,直至 "*"。由上述可得出,在从`origin/hack`(或`remotes/origin/hack`,甚至`refs/remotes/origin/hack`)分支时,将使用`hack`作为本地分支。如果给定的名字没有斜线,或者上述推测的结果是一个空名,则会终止推测。在这种情况下,你可以用`-b`明确地给出一个名字。

--no-track

不设置 "上游 "配置,即使`branch.autoSetupMerge`配置变量为true。

--guess
--no-guess

如果没有找到`<分支>,但确实有一个远程分支(称为<远程分支>`)的跟踪分支存在,且名称匹配,则视为等同于

$ git checkout -b <分支> --track <远程仓库>/<分支>

如果该分支存在于多个远程,并且其中一个是由`checkout.defaultRemote`配置变量命名的,为了消除歧义,我们将使用该变量,即使`<分支>在所有远程中并不唯一。将其设置为例如 `checkout.defaultRemote=origin,以便在`<分支>不明确但存在于'origin'远程时,总是从那里签出远程分支。参见 git-config[1] 中的 `checkout.defaultRemote

--guess`是默认行为。使用--no-guess`来禁用它。

默认行为可以通过`checkout.guess`配置变量设置。

-l

创建新分支的引用日志;详见 git-branch[1]

-d
--detach

与其签出一个分支来工作,不如签出一个提交来进行检查和可放弃的实验。当`<提交>`不是一个分支名时, 这是`git checkout <提交>`的默认行为,。 详见下面的 "游离状态(DETACHED HEAD)"部分。

--orphan <新分支>

从`<起点>` 开始,创建一个新的 “未出生” 分支,命名为 <新分支>,并切换到该分支。 在这个新分支上的第一次提交将没有父分支,它将是一个新的历史起点,与所有其他的分支和提交完全断开。

索引和工作区的调整就像你之前运行 git checkout <起点> 一样。 这允许你轻松地通过运行 git commit -a 来启动一个新的历史,记录一组类似于 <新起点> 的路径,进行根提交。

当你想发布一个提交树而不暴露其完整的历史时,这就很有用。你可能想这样做来发布一个项目的开源分支,这个分支的当前树是 "干净的",但其完整的历史包含了专有的或其他一些代码。

如果你想启动一个断开的历史,记录一组完全不同于`<起点>的路径,那么你应该在创建孤儿分支后立即清除索引和工作区,从工作区的顶层运行`git rm -rf .。 之后你就可以准备你的新文件了,重新填充工作区,办法是从其他地方复制它们,提取一个包,等等。

--ignore-skip-worktree-bits

在稀疏签出模式下,git checkout -- <路径>`将只更新由<路径>$GIT_DIR/info/sparse-checkout`中的稀疏模式匹配的条目。这个选项忽略了稀疏模式,并添加回`<路径>`中的任何文件。

-m
--merge

在切换分支时,如果你对一个或多个文件的本地修改在当前分支和你要切换的分支之间是不同的,命令会拒绝切换分支,以保留你的修改内容。 然而,使用这个选项后,就会在当前分支、你的工作区内容和新的分支之间进行三方合并,之后,你会处于新分支。

当合并冲突发生时,冲突路径的索引条目会被留下,你需要解决冲突,并用`git add`标记已解决的路径(如果合并应导致删除路径,则用`git rm`)。

从索引中检出路径时,该选项可让你在指定路径中重新创建冲突的合并。 该选项不能用于从目录树对象路径中检出路径。

当用`--merge`切换分支时,可能会丢失阶段性修改。

--conflict=<样式>

与上面的 --merge 选项相同,但改变了冲突块的显示方式,覆盖 merge.conflictStyle 配置变量。可能的值是 "merge"(默认)和 "diff3"(除了 "merge" 样式显示的内容外,还显示原始内容)。

-p
--patch

<树状对象>(或索引,如果没有指定)和工作区之间的差异中,交互式地选择目标。 选择的目标会被反向应用到工作区上(如果指定了 <树状对象>,则是索引)。

这意味着你可以使用 git checkout -p 来有选择地丢弃当前工作区上的编辑内容。参见 git-add[1] 的 "互动模式''部分,了解`--patch`模式如何操作。

注意,这个选项默认使用无覆盖模式(另见`--overlay`),目前不支持覆盖模式。

--ignore-other-worktrees

`git checkout`在想要的引用已经被另一个工作区签出时拒绝。这个选项让它无论如何都要签出这个引用。换句话说,这个引用可能被多个工作区持有。

--overwrite-ignore
--no-overwrite-ignore

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

--recurse-submodules
--no-recurse-submodules

使用`--recurse-submodules`将根据父项目的提交记录更新所有活动的子模块的内容。如果子模块中的本地修改会被覆盖,除非使用`-f`,则会签出将失败。如果什么都不使用(或`--no-recurse-submodules`),子模块的工作区将不会被更新。 就像git-submodule[1],这将分离子模块的`HEAD`。

--overlay
--no-overlay

在默认的覆盖模式下,git checkout`不会从索引或工作区中删除文件。 当指定--no-overlay`时,出现在索引和工作区中,但不在`<树状对象>中的文件会被删除,以使它们与<树状对象>`完全匹配。

--pathspec-from-file=<file>

Pathspec在 <文件> 中传递,而不是在命令行参数中传递。如果 <文件> 正好是 -,则使用标准输入。路径规范元素由 LF 或 CR/LF 分隔。可以引用配置变量 core.quotePath 的路径规范元素(请参见 git-config[1])。另请参见 --pathspec-file-nul 和全局 --literal-pathspecs

--pathspec-file-nul

只有在使用 --pathspec-from-file 选项时才有意义。指定路径元素用 NUL 字符分隔,所有其他字符都按字面意思(包括换行符和引号)表示。

<分支>

签出的分支;如果它指的是一个分支(即一个名字,在前面加上 "refs/heads/"时,是一个有效的 引用),那么这个分支就被签出。否则,如果它指的是一个有效的提交,你的`HEAD`就会"分离",此时,你就不再在任何一个分支上了(详见下文)。

你可以使用`@{-N}语法来指代使用 "git checkout "操作检查出来的第N个最后的分支或是提交。你也可以指定-,它与@{-1}`同义。

作为一种特殊情况,如果正好有一个合并基础,你可以使用`A…​B`作为`A`和`B`的合并基础的快捷方式。你最多可以省略在`A`和`B`中默认为`HEAD`的一个分支。

<新分支>

新分支的名称。

<start-point>

启动新分支的提交名称;详见 git-branch[1]。默认为 HEAD

作为一种特殊情况,如果正好有一个合并基数,你可以使用`"A…​B "作为`A`和`B`的合并基数的快捷方式。你最多可以漏掉`A`和`B`中的一个,在这种情况下,它默认为`HEAD`。

<tree-ish>

签出的树(当路径给定时)。如果没有指定,将使用索引。

作为一种特殊情况,如果正好有一个合并基数,你可以使用`"A…​B "作为`A`和`B`的合并基数的快捷方式。你最多可以漏掉`A`和`B`中的一个,在这种情况下,它默认为`HEAD`。

--

不将之后的参数解释为选项。

<pathspec>…​

限制受操作影响的路径。

更多细节请参见 gitglossary[7] 中的 路径规范 条目。

游离状态(DETACHED HEAD)

HEAD`通常指的是一个分支的引用(例如`master)。同时,每个分支指的是一个特定的提交。让我们看看一个有三个提交的仓库,其中一个被标记了,并且分支`master`被检出:

           HEAD('master'分支的引用)
            |
            v
a---b---c  branch 'master'('c' 提交的引用)
    ^
    |
  tag 'v2.0' ('b' 提交的引用)

当在这种状态下创建一个提交时,分支会被更新以引用新的提交。具体来说,'git commit’创建了一个新的提交`d`,其父级是提交`c`,然后更新分支`master`以引用新的提交`d`。HEAD'仍指向`master',所以现在间接地指向提交`d

$ edit; git add; git commit

               HEAD (指向'master'分支)
                |
                v
a---b---c---d  分支'master' (指向提交'd')
    ^
    |
  tag 'v2.0' (指向提交'b')

有时能够签出一个不在任何命名分支顶端的提交,甚至创建一个不被命名分支引用的新提交,是很有用的。让我们来看看当我们签出提交 `b`时会发生什么(这里我们展示了两种方法):

$ git checkout v2.0  # 或
$ git checkout master^^

   HEAD (指向提交'b')
    |
    v
a---b---c---d  分支'master'(指向提交'd')
    ^
    |
  tag 'v2.0' (指向提交'b')

请注意,无论我们使用哪条结账命令,HEAD`现在都直接指向提交`b。这就是所谓的分离的`HEAD’状态。 这意味着,`HEAD`指向一个特定的提交,而不是指向一个命名的分支。让我们看看创建提交时发生了什么:

$ edit; git add; git commit

     HEAD (指向提交'e')
      |
      v
      e
     /
a---b---c---d  branch 'master' (指向提交'd')
    ^
    |
  tag 'v2.0' (指向提交'b')

现在有一个新的提交`e`,但它只被`HEAD`所引用。当然,我们可以在这个状态下再增加一个提交:

$ edit; git add; git commit

	 HEAD(指向提交'f')。
	  |
	  v
      e---f
     /
a---b---c---d 分支"master"(指向提交'd')。
    ^
    |
  tag 'v2.0'(指向提交'b')。

事实上,我们可以执行所有正常的 Git 操作。但是,让我们看看当我们签出`master`时会发生什么:

$ git checkout master

               HEAD(指向分支 'master')
      e---f     |
     /          v
a---b---c---d  branch 'master' (指向提交 'd')
    ^
    |
  tag 'v2.0' (指向提交 'b')

重要的是要意识到,在这一点上,没有任何引用是指向提交`f`的。最终,提交 f(以及提交 e)会被 Git 的例行垃圾回收程序删除,除非我们在这之前创建一个引用。如果我们还没有离开提交 f,以下任何一个操作都会创建一个对它的引用:

$ git checkout -b foo   (1)
$ git branch foo        (2)
$ git tag foo           (3)
  1. 创建一个新的分支`foo`,指向提交`f`,然后更新`HEAD`,指向分支`foo`。换句话说,这条命令之后,我们将不再处于分离的`HEAD`状态。

  2. 类似的,创建一个新的分支`foo`,它指向提交`f`,但将`HEAD`分离出来。

  3. 创建一个新的标签`foo`,指向提交`f`,让`HEAD`处于分离状态。

如果我们已经离开了`f’的提交,那么我们必须首先恢复它的对象名称(通常使用git reflog),然后我们可以创建一个对它的引用。例如,要查看`HEAD`指向的最后两个提交,我们可以使用以下任一命令:

$ git reflog -2 HEAD # 或
$ git log -g -2 HEAD

参数消歧义

当只有一个参数且不是`--时(例如`git checkout abc),当参数既是有效的`<树状对象>(例如分支`abc`存在)又是有效的<路径规范>(例如文件或目录的名称为 "abc "存在),Git通常会要求你进行区分。 因为签出分支是很常见的操作,`git checkout abc`在这种情况下把 "abc "作为<树状对象>。 如果你想从索引中签出这些路径,请使用`git checkout --<路径规范>

实例

1.路径

下面的序列检查了 "master "分支,将 "Makefile "恢复到两个修订版,错误地删除了 "hello.c",并从索引中取回它。

$ git checkout master             (1)
$ git checkout master~2 Makefile  (2)
$ rm -f hello.c
$ git checkout hello.c            (3)
  1. 选择分支

  2. 将一个文件从另一个提交中取出

  3. 从索引中恢复`hello.c`

如果你想从索引中检出_所有_的C源文件,你可以这样

$ git checkout -- '*.c'

注意 `*.c `周围的引号。 文件`hello.c`也将被检出,尽管它已经不在工作树中了,因为文件通配符被用来匹配索引中的条目(不是工作区中的shell)。

如果不幸你有一个分支被命名为 "hello.c",这一步会误认为切换到该分支的指令。 你应该这样写:

$ git checkout -- hello.c

2. Merge

在错误的分支工作后,切换到正确的分支将使用:

$ git checkout mytopic

然而,你的 "错误"分支和正确的`mytopic`分支可能在你本地修改的文件中存在差异,在这种情况下,上述检出会失败,像这样:

$ git checkout mytopic
错误:您对 'footz' 有本地更改;未切换分支。

你可以给命令加上 `-m`标志,这样就可以尝试三方合并了:

$ git checkout -m mytopic
自动合并 frotz 分支

在这个三方合并之后,本地的修改并「没有」登记在你的索引文件中,所以`git diff`会显示你在新分支的提示下做了哪些修改。

3. Merge 冲突

当使用`-m`选项切换分支时发生合并冲突,你会看到类似这样的情况:

$ git checkout -m mytopic
自动合并 frotz 分支
错误:对 frotz 分支的合并冲突
失败:merge 程序终止

在这一点上,`git diff`显示了与前面的例子一样干净地合并的修改,以及冲突文件中的修改。 编辑并解决冲突,让后像往常一样用`git add`标记已解决:

$ 编辑 frotz
$ git add frotz

配置

Warning

Missing zh_HANS-CN/includes/cmd-config-section-all.txt

See original version for this content.

Warning

Missing zh_HANS-CN/config/checkout.txt

See original version for this content.

GIT

属于 git[1] 文档

scroll-to-top