Skip to content

git-checkout

命令名称 - 切换分支或恢复工作树文件

概要

bash
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 <tree-ish> [--] <pathspec>...
git checkout <tree-ish> --pathspec-from-file=<file> [--pathspec-file-nul]
git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [--] <pathspec>...
git checkout [-f|--ours|--theirs|-m|--conflict=<style>] --pathspec-from-file=<file> [--pathspec-file-nul]
git checkout (-p|--patch) [<tree-ish>] [--] [<pathspec>...]

描述

git checkout 有两种主要模式:

  1. 切换分支,使用 git checkout <branch>
  2. 恢复文件的不同版本,例如使用 git checkout <commit> <filename>git checkout <filename>

有关 Git 如何决定执行哪个操作,请参阅下面的"参数消歧义"。

git checkout [<branch>] - 切换到 <branch>。这将当前分支设置为 <branch> 并更新工作目录中的文件。如果 <branch> 与当前提交内容不同的任何文件有未提交的更改,检出将失败。否则未提交的更改将被保留。

如果 <branch> 未找到,但在恰好一个远程仓库(称之为 <remote>)中存在匹配名称的跟踪分支,且未指定 --no-guess,则视为等同于:

$ git checkout -b <branch> --track <remote>/<branch>

如果分支存在于多个远程仓库中,且其中一个由 checkout.defaultRemote 配置变量命名,我们将使用该远程仓库进行消歧义,即使 <branch> 在所有远程仓库中不唯一。将其设置为例如 checkout.defaultRemote=origin,以便在 <branch> 有歧义但存在于 'origin' 远程仓库时始终从那里检出远程分支。另请参阅 git-config(1) 中的 checkout.defaultRemote

--guess 是默认行为。使用 --no-guess 禁用它。默认行为可通过 checkout.guess 配置变量设置。

选项

  • -q / --quiet - 安静模式,抑制反馈消息。

  • --progress / --no-progress - 默认情况下,当连接到终端时,进度状态报告在标准错误流上,除非指定了 --quiet。此标志即使未连接到终端也启用进度报告,无论 --quiet 如何。

  • -f / --force - 切换分支时,即使索引或工作树与 HEAD 不同,即使有未跟踪的文件挡路也继续执行。这用于丢弃本地更改和任何挡路的未跟踪文件或目录。 从索引检出路径时,不会因未合并的条目而失败;相反,未合并的条目被忽略。

  • --ours / --theirs - 从索引检出路径时,对未合并的路径检出阶段 #2("ours")或 #3("theirs")。 请注意,在 git rebasegit pull --rebase 期间,ourstheirs 可能看起来是交换的;--ours 给出变更要变基到的分支的版本,而 --theirs 给出包含您正在进行变基的工作的分支的版本。 这是因为 rebase 在将远程的历史视为共享规范历史的工作流中使用,并将您在要变基的分支上所做的工作视为要集成的第三方工作,您在变基期间临时担任规范历史的保管者角色。作为规范历史的保管者,您需要将远程的历史视为 ours(即"我们的共享规范历史"),而将您在侧分支上所做的视为 theirs(即"一个贡献者在它之上的工作")。

  • -b <new-branch> - 创建一个名为 <new-branch> 的新分支,在 <start-point> 处启动,并检出结果分支;详情参见 git-branch(1)

  • -B <new-branch> - 与 -b 相同,不同之处在于如果分支已存在,它将 <branch> 重置为起始点而不是失败。

  • -t / --track[=(direct|inherit)] - 创建新分支时,设置"上游"配置。详情参见 git-branch(1) 中的 --track。作为便利,不带 -b 的 --track 隐含创建分支。

  • --no-track - 即使 branch.autoSetupMerge 配置变量为 true,也不设置"上游"配置。

  • --guess / --no-guess - 如果 <branch> 未找到,但在恰好一个远程仓库中存在匹配名称的跟踪分支,且未指定 --no-guess,则视为等同于 git checkout -b <branch> --track <remote>/<branch>

  • -l - 创建新分支的 reflog;详情参见 git-branch(1)

  • -d / --detach - 不是检出分支来工作,而是检出提交进行检查和可丢弃的实验。这是 git checkout <commit><commit> 不是分支名称时的默认行为。详情请参阅下面的"分离 HEAD"部分。

  • --orphan <new-branch> - 创建一个新的未诞生分支,命名为 <new-branch>,从 <start-point> 开始并切换到它。在此新分支上进行的第一次提交将没有父级,它将成为完全断开与所有其他分支和提交的新历史的根。 索引和工作树会像您先前运行了 git checkout <start-point> 一样进行调整。这允许您通过轻松运行 git commit -a 来创建根提交,从而开始记录与 <start-point> 相似的一组路径的新历史。 当您想从提交发布树而不暴露其完整历史时,这可能很有用。您可能想这样做来发布项目的开源分支,其当前树是"干净的",但其完整历史包含专有或其他受限制的代码片段。 如果您想开始记录与 <start-point> 完全不同的路径集的断开历史,那么您应该在创建孤儿分支后立即通过从工作树顶层运行 git rm -rf . 来清除索引和工作树。之后,您就可以准备新文件,通过从其他地方复制、解压缩 tarball 等重新填充工作树。

  • --ignore-skip-worktree-bits - 在稀疏检出模式下,git checkout -- <path>... 将仅更新由 <paths>$GIT_DIR/info/sparse-checkout 中的稀疏模式匹配的条目。此选项忽略稀疏模式,并将 <path>... 中的任何文件添加回来。

  • -m / --merge - 切换分支时,如果您对一个或多个文件有本地修改,而这些文件在当前分支和要切换到的分支之间不同,该命令将拒绝切换分支以在上下文中保留您的修改。使用此选项,冲突的本地更改会在切换前自动存储,并在之后重新应用。如果本地更改与分支之间的差异不重叠,则切换在不存储的情况下进行。如果重新应用存储导致冲突,条目将保存到存储列表中。解决冲突后运行 git stash drop,或在稍后运行 git stash pop 重新应用更改之前清除工作树(例如使用 git reset --hard)。 从索引检出路径时,此选项允许您在指定路径中重新创建冲突的合并。从 tree-ish 检出路径时不能使用此选项。

  • --conflict=<style> - 与上面的 --merge 选项相同,但更改冲突块的呈现方式,覆盖 merge.conflictStyle 配置变量。可能的值为 merge(默认)、diff3zdiff3

  • -p / --patch - 交互式选择 <tree-ish>(或未指定时为索引)与工作树之间差异中的块。然后将选定的块反向应用到工作树(如果指定了 <tree-ish>,也应用到索引)。 这意味着您可以使用 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 时,出现在索引和工作树中但不在 <tree-ish> 中的文件将被删除,以使其与 <tree-ish> 完全匹配。

  • --pathspec-from-file=<file> - 路径规范在 <file> 中传递,而不是命令行参数。如果 <file> 恰好是 -,则使用标准输入。路径规范元素以 LFCR/LF 分隔。路径规范元素可以按照配置变量 core.quotePath 的说明进行引用(参见 git-config)。另请参阅 --pathspec-file-nul 和全局 --literal-pathspecs

  • --pathspec-file-nul - 仅与 --pathspec-from-file 一起使用有意义。路径规范元素由 NUL 字符分隔,所有其他字符按字面意思处理(包括换行符和引号)。

  • <branch> - 要检出的分支;如果它引用一个分支(即,前面加上 "refs/heads/" 后是有效引用的名称),则检出该分支。否则,如果它引用一个有效的提交,您的 HEAD 变为"分离"状态,您不再在任何分支上(详情见下文)。 您可以使用 @{-N} 语法引用使用"git checkout"操作检出的第 N 个最近的分支/提交。您也可以指定 -,它与 @{-1} 同义。 作为特殊情况,如果恰好有一个合并基础,您可以使用 <rev-a>...<rev-b> 作为 <rev-a><rev-b> 合并基础的快捷方式。您可以省略 <rev-a><rev-b> 中的最多一个,在这种情况下默认为 HEAD

  • <new-branch> - 新分支的名称。

  • <start-point> - 开始新分支的提交名称;详情参见 git-branch(1)。默认为 HEAD

  • <tree-ish> - 要从中检出的树(当给定路径时)。如果未指定,将使用索引。

  • -- - 不再将任何参数解释为选项。

  • <pathspec>... - 限制操作影响的路径。更多详情请参阅 gitglossary(7) 中的 'pathspec' 条目。

分离 HEAD

HEAD 通常引用一个命名分支(例如 master)。同时,每个分支引用一个特定的提交。让我们看一个有三个提交的仓库,其中一个打了标签,并检出了分支 master

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

假设您在此状态下将分支移动到另一个提交:

$ git switch -c topic   # 从 'b' 创建并切换到新分支 'topic'
           HEAD(引用分支 'topic')
            |
            v
a---b---c  分支 'master'
     \
      d   分支 'topic'(引用提交 'd')

重要的是要认识到此时没有任何东西引用提交 f。最终提交 f(以及扩展的提交 e)将被常规 Git 垃圾回收过程删除,除非我们在那之前创建一个引用。如果我们尚未从提交 f 移开,以下任何操作都将创建对它的引用:

$ git checkout -b foo  # 或 "git switch -c 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 <something> 时,Git 会尝试猜测 <something> 是打算作为分支、提交还是一组文件,然后切换到该分支或提交,或恢复指定的文件。

如果有任何歧义,Git 将把 <something> 视为分支或提交,但您可以使用双破折号 -- 强制 Git 将参数视为文件和/或目录列表,如下所示:

$ git checkout -- file.txt

示例

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. 合并

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

$ git checkout mytopic

但是,您的"错误"分支和正确的 mytopic 分支可能在您本地修改的文件中有所不同,在这种情况下,上面的检出将失败:

$ git checkout mytopic
error: You have local changes to 'frotz'; not switching branches.

您可以给命令 -m 标志,它将把您的本地更改带到新分支:

$ git checkout -m mytopic
Applied autostash.
Switched to branch 'mytopic'
The following paths have local changes:
M	frotz

切换后,本地修改被重新应用,_不会_注册在您的索引文件中,因此 git diff 将显示您自新分支顶端以来所做的更改。

3. 合并冲突

当给定 --merge (-m) 选项且本地更改与我们要切换到的分支中的更改重叠时,更改会被存储并在切换后重新应用。如果此过程导致冲突,存储条目将被保存并打印消息:

$ git checkout -m mytopic
Your local changes are stashed, however applying them
resulted in conflicts.  You can either resolve the conflicts
and then discard the stash with "git stash drop", or, if you
do not want to resolve them now, run "git reset --hard" and
apply the local changes later by running "git stash pop".

配置

本节中此行以下的所有内容都是从 git-config(1) 文档中有选择地包含的。内容与那里找到的相同:

  • checkout.defaultRemote - 当您运行 git checkout <something>git switch <something> 且只有一个远程仓库时,它可能隐式回退到检出和跟踪例如 origin/<something>。一旦您有多个具有 <something> 引用的远程仓库,这就停止工作。此设置允许设置在消歧义时应始终优先的首选远程仓库的典型用例是将其设置为 origin。 目前这由 git-switch(1)git-checkout(1) 使用,当 git checkout <something>git switch <something> 将检出另一个远程仓库上的 <something> 分支时,以及由 git-worktree(1)git worktree add 引用远程分支时使用。此设置可能在将来用于其他类似检出的命令或功能。

  • checkout.guess - 为 git checkoutgit switch 中的 --guess--no-guess 选项提供默认值。参见 git-switch(1)git-checkout(1)

  • checkout.workers - 更新工作树时使用的并行工作者数量。默认为一个,即顺序执行。如果设置为小于一的值,Git 将使用与可用逻辑核心数一样多的工作者。此设置和 checkout.thresholdForParallelism 影响所有执行检出的命令。例如 checkout、clone、reset、sparse-checkout 等。

    TIP

    并行检出通常在位于 SSD 或 NFS 上的仓库中提供更好的性能。对于在旋转磁盘和/或核心数较少的机器上的仓库,默认的顺序检出通常表现更好。仓库的大小和压缩级别也可能影响并行版本的表现。

  • checkout.thresholdForParallelism - 在文件数较少的情况下运行并行检出时,子进程生成和进程间通信的成本可能超过并行化的收益。此设置允许您定义应尝试并行检出的最小文件数。默认为 100。

另请参阅

git-switch(1), git-restore(1)

Git

git(1) 套件的一部分

基于 CC BY-NC-SA 3.0 许可发布