Git switch 和 git checkout 之间的区别是什么

Git 2.23 介绍一个新的命令 git switch——在阅读了文档之后,它似乎与 git checkout <branchname>非常相似,有人能解释一下其中的区别或用例吗?

引入了两个新命令“ git switch”和“ git 恢复” 将“检查一个分支机构以推进其历史进程”和“检查一个分支机构以推进其历史进程”分开 ”检查索引外的路径和/或要处理的树形路径 推进单个“ git checkout”的当前历史 指挥官。

177587 次浏览

git checkout有点像瑞士军刀,它有几个不相关的用途。

如果您修改了一个文件,但还没有执行更改,那么git checkout <filename>将反转修改…一种快速而简单的方法取消对文件的更改。你仍然在同一个分支。

git checkout <branchname>(正如你所注意到的)切换分支。

两个完全不同的目的,如果文件名和分支名称相似,可能会导致混淆。

把它作为两个命令就更清楚了。

好吧,根据你链接到的文档,它的唯一目的是拆分和澄清git checkout的两种不同用法:

  • git switch现在可以用来改变分支,就像git checkout <branchname>一样
  • git restore可以像git checkout -- <path_to_file>一样,将文件重置为某些修订

人们对使用git checkout的不同方式感到困惑,正如你可以从Stackoverflow上关于git checkout的许多问题中看到的那样。Git开发人员似乎已经考虑到了这一点。

switch有一些限制:目前你可以将任何提交切换到<branch name>,但是不可能将 <branch name>切换到状态为分离的头的特定提交。因此您需要使用git checkout 5efb(其中5efb是任意提交的哈希引用的示例)

这里是一个从git手册 - man git-switch的摘录。

剧情简介

git switch [<options>] [--no-guess] <branch>
git switch [<options>] --detach [<start-point>]
git switch [<options>] (-c|-C) <new-branch> [<start-point>]
git switch [<options>] --orphan <new-branch>

描述

切换到指定分支。工作树和索引是 已更新以匹配分支。所有新提交将被添加到

< p >选择# EYZ2, 自动从同名的远程分支(见--guess), 或者使用--detach从任何分支分离工作树,

切换分支不需要干净的索引和工作树 (即与HEAD相比没有区别)。操作被终止 但如果操作导致局部改动丢失,则除非

. --discard-changes--merge

这个命令是实验性的。行为可能会改变。

switch命令确实做了与checkout相同的事情,但仅适用于那些切换分支的使用。特别是,与checkout不同,它不能恢复工作树文件——而是使用与switch一起引入的restore命令来完成。

详细解释

正如你在2.23.0发布说明中提到的,引入switchrestore命令是为了将checkout命令分成两个单独的部分:

  • “检查一个分支机构,以推进其历史”;
  • “查出路径索引和/或树状工作推进当前历史”;

换句话说,checkout做了两件不同的事情,这个版本将每一件不同的事情分割成自己的重点命令。

checkout的双重目的可以在文档的摘要描述中看到:

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

添加了switch命令的提交在其提交消息中解释了新命令的基本原理:

< p >“git checkout"做太多事情会让很多人感到困惑 用户(有时甚至是老用户)。为了补救, 命令将拆分为两个新的命令:switch和restore。良好的 旧的“git checkout”;命令仍然在这里,直到所有(或大部分)

由此可以明显看出,引入新命令是为了减少混淆,因为有两个集中的命令,而不是一个多用途命令。

请注意,截至2021年12月,新命令仍被列为实验性(switchrestore):

这个命令是实验性的。行为可能会改变。

命令比较

我还没有在任何地方找到这些命令的完整比较。通过阅读文档,我认为这应该是一个相当完整的比较:

之前的命令 新命令
# EYZ0 # EYZ0
# EYZ0 (使用git status)
# EYZ0 # EYZ0
# EYZ0 # EYZ0
# EYZ0 # EYZ0
# EYZ0 N/A(先用git switch <start-point>再用git switch --orphan <new-branch>)
# EYZ0 # EYZ0
# EYZ0 # EYZ0
# EYZ0 # EYZ0
# EYZ0 # EYZ0
# EYZ0 # EYZ0
# EYZ0 # EYZ0
# EYZ0 # EYZ0

从这个比较中可以看出,通过将旧的命令名(checkout)替换为新命令名(switchrestore),可以将一些先前的用法转换为新命令,而其他用法则需要进行额外的调整。值得注意的变化包括:

  • 切换前用于创建新分支的-b/-B选项被重命名为-c/-C。他们也有较长的选项变体(--create/--force-create),而之前他们只有单字母的选项版本。
  • --detach(或-d)现在在切换到分离头时总是必需的,以前它对于提交是可选的,但对于分支是必需的。
  • 用于恢复的源树现在由-s(或--source)选项给出,而不是作为一个内联参数。
  • 现在,如果有未合并的条目,使用--force进行切换将失败,而不是忽略它们。--force也被重命名为--discard-changes,其中--force保留为别名。

当使用checkout--force时,你可以在合并过程中切换分支。你不能用switch这样做。

细节:

其他答案已经涵盖了将checkout分为switchrestore背后的动机,以及语法使用差异存在的事实。(例如,你可以将checkout与提交或远程跟踪分支一起使用,如origin/main,但对于switch,你还必须显式地指定--detach选项。)然而,我也发现了至少一个重要的功能区别。

git switch -f等于记录:

即使索引或工作树与HEAD不同,也要继续。索引和工作树都被恢复以匹配交换目标。如果指定了--recurse-submodules,子模块内容也会恢复到与切换目标匹配。这用于丢弃局部更改。

类似地,git checkout -f就是记录(强调最后一句):

在切换分支时,即使索引或工作树与HEAD不同,即使存在未跟踪的文件,也要继续执行。这用于丢弃本地更改和任何碍事的未跟踪文件或目录。

当从索引中检出路径时,不要在未合并的条目上失败;相反,未合并的条目将被忽略。

似乎像最后一句一样适用于checkout的另一个含义,即restore命令等价。然而,当您试图在合并过程中切换分支时,git checkout -f将会成功,即使您当时有未解决的冲突。如果你正在合并(即使没有冲突),git switch -f根本不起作用,因为你得到这个错误消息:

致命:合并时不能切换分支

注意:这个差异是使用Git 2.37.1版本测试的