当当前分支上有未提交的更改时签出另一个分支

2024-05-18

大多数时候,当我尝试签出另一个现有分支时,如果我在当前分支上有一些未提交的更改,Git 会不允许我这样做。所以我必须首先提交或隐藏这些更改。

然而,有时 Git 确实允许我在不提交或存储这些更改的情况下签出另一个分支,并且它会将这些更改携带到我签出的分支。

这里的规则是什么?更改是分阶段的还是非分阶段的很重要吗?将更改携带到另一个分支对我来说没有任何意义,为什么 git 有时允许这样做?也就是说,它在某些情况下有用吗?


初步说明

这个答案试图解释whyGit 的行为方式就是这样。不建议参与任何特定的工作流程。 (我自己的偏好是无论如何都要提交,避免git stash并且不想太棘手,但其他人喜欢其他方法。)

这里的观察是,当你开始工作后branch1(忘记或没有意识到切换到不同的分支会很好branch2首先),你运行:

git checkout branch2

有时 Git 会说“好吧,你现在在分支 2 上!”有时,Git 会说“我不能这样做,我会丢失你的一些更改”。

If Git won't让你这样做,你必须提交你的更改,将它们永久保存在某个地方。您可能想使用git stash拯救他们;这是它的设计目的之一。 https://git-scm.com/docs/git-stash注意git stash save or git stash push实际上means“提交所有更改,但根本不在任何分支上,然后将它们从我现在所在的位置删除。”这使得切换成为可能:您现在没有正在进行的更改。那么你可以git stash apply切换后的他们。

侧边栏:git stash save是旧语法;git stash push在 Git 2.13 版本中引入,以修复参数的一些问题git stash并允许新的选择。当以基本方式使用时,两者都做同样的事情。

如果你愿意的话,你可以在这里停止阅读!

If Git won't让你切换,你已经有补救措施:使用git stash or git commit;或者,如果您的更改很容易重新创建,请使用git checkout -f来强迫它。这个答案是关于whenGit 会让你git checkout branch2即使你开始做出一些改变。为什么它有效有时, 并不是other times?

这里的规则一方面很简单,另一方面又复杂/难以解释:

当且仅当所述切换不需要破坏这些更改时,您才可以切换工作树中具有未提交更改的分支。

也就是说,请注意,这仍然是简化的;有一些特别困难的极端情况需要分阶段进行git adds, git rm等等——假设你在branch1. A git checkout branch2必须这样做:

  • For every file that is in branch1 and not in branch2,1 remove that file.
  • 对于每个文件is in branch2 and not in branch1,创建该文件(具有适当的内容)。
  • 对于两个分支中的每个文件,如果版本branch2不同,更新工作树版本。

这些步骤中的每一个都可能会破坏您的工作树中的某些内容:

  • 如果工作树中的版本与中提交的版本相同,则删除文件是“安全的”branch1;如果您进行了更改,则“不安全”。
  • Creating a file the way it appears in branch2 is "safe" if it does not exist now.2 It's "unsafe" if it does exist now but has the "wrong" contents.
  • 当然,如果工作树版本已经提交到,则用不同版本替换文件的工作树版本是“安全的”branch1.

创建一个新分支(git checkout -b newbranch) is always被视为“安全”:在此过程中,不会在工作树中添加、删除或更改任何文件,并且索引/暂存区域也不会受到影响。 (警告:创建新分支而不更改新分支的起点是安全的;但是如果您添加另一个参数,例如,git checkout -b newbranch different-start-point,这可能需要改变一些事情,移动到different-start-point。然后 Git 将照常应用结帐安全规则。)


1This requires that we define what it means for a file to be in a branch, which in turn requires defining the word branch properly. (See also What exactly do we mean by "branch"? https://stackoverflow.com/q/25068543/1256452) Here, what I really mean is the commit to which the branch-name resolves: a file whose path is P is in branch1 if git rev-parse branch1:P produces a hash. That file is not in branch1 if you get an error message instead. The existence of path P in your index or work-tree is not relevant when answering this particular question. Thus, the secret here is to examine the result of git rev-parse on each branch-name:path. This either fails because the file is "in" at most one branch, or gives us two hash IDs. If the two hash IDs are the same, the file is the same in both branches. No changing is required. If the hash IDs differ, the file is different in the two branches, and must be changed to switch branches.

这里的关键概念是文件提交被永远冻结。您要编辑的文件显然是 not 冻结了。至少在最初,我们只关注两个冻结提交之间的不匹配。不幸的是,我们(或 Git)还必须处理以下文件:aren't在你要切换的提交中are在您要切换到的提交中。这导致了剩余的复杂性,因为文件也可以存在于索引和/或工作树中,而不必存在我们正在处理的这两个特定的冻结提交。

2It might be considered "sort-of-safe" if it already exists with the "right contents", so that Git does not have to create it after all. I recall at least some versions of Git allowing this, but testing just now shows it to be considered "unsafe" in Git 1.8.5.4. The same argument would apply to a modified file that happens to be modified to match the to-be-switch-to branch. Again, 1.8.5.4 just says "would be overwritten", though. See the end of the technical notes as well: my memory may be faulty as I don't think the read-tree rules have changed since I first started using Git at version 1.5.something.


更改是分阶段的还是非分阶段的很重要吗?

是的,在某些方面。特别是,您可以暂存更改,然后“取消修改”工作树文件。这是两个分支中的文件,不同之处在于branch1 and branch2:

$ git show branch1:inboth
this file is in both branches
$ git show branch2:inboth
this file is in both branches
but it has more stuff in branch2 now
$ git checkout branch1
Switched to branch 'branch1'
$ echo 'but it has more stuff in branch2 now' >> inboth

此时,工作树文件inboth与其中的一个匹配branch2,即使我们在branch1。此更改不是为提交而暂存的,这就是git status --short此处显示:

$ git status --short
 M inboth

space-then-M 表示“已修改但未暂存”(或更准确地说,工作树副本与暂存/索引副本不同)。

$ git checkout branch2
error: Your local changes ...

好的,现在让我们暂存工作树副本,我们已经知道它也与中的副本匹配branch2.

$ git add inboth
$ git status --short
M  inboth
$ git checkout branch2
Switched to branch 'branch2'

这里的舞台和工作副本都与里面的内容相匹配branch2,因此允许结账。

让我们尝试另一个步骤:

$ git checkout branch1
Switched to branch 'branch1'
$ cat inboth
this file is in both branches

我所做的更改现在已从暂存区域丢失(因为结账会通过暂存区域进行写入)。这是一个有点特殊的情况。改变并没有消失,但事实是我已经上演了它,is gone.

让我们暂存文件的第三个变体,与任一分支副本不同,然后设置工作副本以匹配当前分支版本:

$ echo 'staged version different from all' > inboth
$ git add inboth
$ git show branch1:inboth > inboth
$ git status --short
MM inboth

The two M此处的意思是:暂存文件不同于HEAD file, and,工作树文件与暂存文件不同。工作树版本确实匹配branch1 (aka HEAD) 版本:

$ git diff HEAD
$

But git checkout不允许结帐:

$ git checkout branch2
error: Your local changes ...

让我们设置branch2版本作为工作版本:

$ git show branch2:inboth > inboth
$ git status --short
MM inboth
$ git diff HEAD
diff --git a/inboth b/inboth
index ecb07f7..aee20fb 100644
--- a/inboth
+++ b/inboth
@@ -1 +1,2 @@
 this file is in both branches
+but it has more stuff in branch2 now
$ git diff branch2 -- inboth
$ git checkout branch2
error: Your local changes ...

即使当前工作副本与中的副本匹配branch2,暂存文件没有,所以git checkout将会丢失该副本,并且git checkout被拒绝。

技术说明——仅供那些极度好奇的人使用:-)

这一切的底层实现机制是Git的index。索引也称为“暂存区”,是您构建索引的地方next提交:它开始匹配当前提交,即您现在签出的任何内容,然后每次您git add一个文件,你replace索引版本与工作树中的任何内容。

请记住,工作树是您处理文件的地方。在这里,它们具有正常的形式,而不是像在提交和索引中那样仅对 Git 有用的特殊形式。所以你提取一个文件from一次提交,through索引,然后进入工作树。改变之后,你git add它到索引。因此,每个文件实际上有三个位置:当前提交、索引和工作树。

当你跑步时git checkout branch2,Git 在幕后所做的就是比较提示提交 of branch2到当前提交和索引中的任何内容。任何与现有文件匹配的文件,Git 都可以不理会。一切都未曾动过。两者相同的任何文件commits,Git 可以also不用管——这些是可以让你切换分支的。

Git 的大部分内容(包括提交切换)都相对较快因为这个指数。索引中实际上不是每个文件本身,而是每个文件的hash。文件本身的副本存储为 Git 所称的斑点对象,在存储库中。这也类似于文件在提交中的存储方式:提交实际上并不包含files,它们只是将 Git 引导至每个文件的哈希 ID。因此,Git 可以比较哈希 ID(当前为 160 位长的字符串)来决定是否提交X and Ysame文件与否。然后,它也可以将这些哈希 ID 与索引中的哈希 ID 进行比较。

这就是导致上述所有奇怪的极端情况的原因。我们有承诺X and Y两者都有文件path/to/name.txt,我们有一个索引条目path/to/name.txt。也许所有三个哈希值都匹配。也许其中两个匹配,一个不匹配。或许三者各有不同。而且,我们也可能有another/file.txt那只是在X或仅在Y现在是否在索引中。这些不同的情况中的每一种都需要单独考虑:Git 是否need将文件从提交复制到索引,或从索引中删除它,以切换X to Y?如果是这样的话,也has to将文件复制到工作树,或将其从工作树中删除。而如果that在这种情况下,索引和工作树版本最好至少与已提交的版本之一匹配;否则 Git 会破坏一些数据。

(所有这些的完整规则都在中描述,而不是git checkout正如您所期望的那样,而是文档the git read-tree文档,标题为“两棵树合并”的部分下 https://www.kernel.org/pub/software/scm/git/docs/git-read-tree.html#_two_tree_merge.)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当当前分支上有未提交的更改时签出另一个分支 的相关文章

  • GitHub - 指定时间的存储库状态

    我是使用 git 版本控制工具的初学者 我想在指定时间 例如 2013 年 10 月 5 日 下载存储库状态 文件 我怎样才能做到这一点 截至 2019 年 5 月 不确定何时引入 您可以简单地按以下格式添加日期 HEAD 2019 04
  • 如何与其他用户共享 bitbucket 存储库?

    我正在使用 Bit 存储桶 并且我想与一位朋友分享我的存储库 我用的是免费的个人账户 似乎有一个选项可以在位桶中创建团队 但它说它将把我的帐户从个人帐户转换为团队帐户 我不要那个 我如何授予其他用户访问此存储库的权限 有一个共享链接选项 如
  • 如何防止克隆我的 github 存储库?

    我正在尝试找到一种方法来防止从 github 存储库克隆 例如 我有一个私有存储库 有些人在该存储库中工作 在公司计算机中 团队中的每个人都设置了授权级别 当我在 github 上为某个用户设置授权时 该存储库可在他 她自己的 github
  • 如何从父克隆中过去的提交中获取 git 子模块的关联提交 ID?

    有没有一种方法 除了实际检查父提交之外 还可以根据父克隆中的提交 ID 确定子模块的 SHA 1 提交 ID 我知道我能找到现在与 SHA 1 关联git submodule 这是一个例子 我有一个带有单个子模块的克隆foo上个月情况发生了
  • 从预提交挂钩中排除某些文件类型

    我想要一个预提交 git 钩子来检查 如果可能的话 自动删除 尾随空格 In 让 git 在提交之前自动删除尾随空格 https stackoverflow com questions 591923 make git automatical
  • 如何使用 LibGit2Sharp 从 Git 获取更改?

    下面的代码将 Git url 克隆到测试目录 var url http abc 555 com team project 555 git var path E temp 555 var credential new Credentials
  • 如何在Git中手动合并所有文件?

    我想合并所有文件manually有了 meld 或任何其他 diff 工具 我如何使用 Git 来做到这一点 当我跑步时git mergetool它说no files need merging 所以我想只有当我有冲突时我才能做到这一点 有更
  • 如何 git checkout 提交并将子模块更新到该提交?

    我正在克隆一个带有子模块的项目并恢复到大约一年前的提交 git clone recursive branch 5 6 https codereview qt project org pyside pyside setup cd pyside
  • Git 和重定向

    我注意到 当 git html 项目页面如下所示 https github com fruux sabre dav 被克隆 以这种方式 git clone https github com fruux sabre dav 实际生成的远程 U
  • 为什么 cmake 在 git commit 后编译所有内容

    假设我有时在 Linux 上使用 cmake 2 8 编译一段代码 我更改了一个文件 my changed file 运行 cmake 并且只构建了这个文件 到目前为止 一切都很好 现在我想提交这个 git add my changed f
  • 如何从 git 存储库中删除作者?

    如果我创建一个 Git 存储库并公开发布它 例如在 GitHub 等上 并且我收到存储库贡献者的请求 无论出于何种原因删除或隐藏他们的名字 有没有一种方法可以轻松做到这一点 基本上 我有这样的请求 可能想将他们的姓名和电子邮件地址替换为 匿
  • 如何正确设置 Azure DevOps 和 GitHub 之间的双向同步

    我想通过执行以下操作在 Azure DevOps 和 GitHub 之间创建双向同步 使用 CI 触发器创建 Azure DevOps 管道 将更改从 Azure DevOps 存储库推送到 GitHub 中的分支 创建第二个管道 用于侦听
  • 无论我做什么,我都无法推送我的代码并不断收到相同的错误

    我正在尝试将代码推送到远程分支 但不断收到此错误 rejected non fast forward error failed to push some refs to email protected cdn cgi l email pro
  • 将存储库从 Github 移至 Gitlab

    有没有办法将整个存储库从 Github 移动到 GitLab 对于代码本身来说 只需在 GitLab 上创建一个新的存储库并推送到它即可 Wiki 页面位于 Github 上的单独分支中 并通过 Git 机制进行管理 据我所知 GitLab
  • 自给定提交以来 git 中的作者列表

    我想要一种列出所有 git 作者的方法 仅自给定提交以来 是独特的 这两个很简单 我在网上看到过一些解决方案 大多数使用git log format 但我看到的都不符合附加要求 按提交日期排序 因此 如果约翰 史密斯 John Smith
  • 是否可以使用“最小”算法进行交互式添加?

    当从快照计算变更集时 Git 并不总是正确选择块边界 git diff has a diff algorithm允许在这方面进行一些调整的选项 git diff minimal有时会给出比git diff alone 有没有办法获得相同的优
  • 配置 Eclipse/EGit 来跟踪上游存储库

    我正在使用 EGit 如新的 Eclipse 4 2 Juno 版本中提供的 我在 GitHub 上有一个存储库 是从另一个上游存储库分叉的 当我从 Github 上的存储库在 Eclipse 中创建项目时 它正确设置origin指向 Gi
  • 本地分支显示在 GitHub 的“网络”视图上

    我们使用 Git 我们的工作流程由 dev 和 master 分支组成 它们位于 GitHub 和每个开发人员的本地存储库上 不会直接在 master 或 dev 上执行任何工作 而是在本地分支中执行工作 并且仅在 dev 上进行合并 然后
  • 反向合并具有干净历史记录的缝合功能分支

    我有这个 d0 f1 d1 d2 f2 d3 merge d4 f3 merge
  • git svn 克隆特定分支并合并

    我希望将我的代码库从 svn 迁移到 git 我的 svn 仓库中有太多分支 我只想克隆几个分支并将它们合并在一起并将其推送到 git 我想避免克隆所有分支 因为这需要很长时间 我该如何实现这一目标 完成后 我想定期从这些 svn 分支获取

随机推荐

  • 成功安装 Composer,但消息显示:必须设置 HOME 或 COMPOSER_HOME 环境变量才能使 Composer 正确运行

    我已经在 Ubuntu vagrant box 上安装了 Composer 正在运行php 7 0 在此之前刚刚安装 简单地尝试一下composer 或完整路径php usr local bin composer两者都会导致以下错误 The
  • Django-tables2 列总计

    我正在尝试使用此总结列中的所有值文档 https github com bradleyayers django tables2 blob master docs pages column headers and footers rst 但页
  • 如何应用一个函数 n 次? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 假设我有一个函数 它接受一个参数并返回相同类型的结果 def increment x return x 1 如何制作高阶函数repeat可以
  • 如何计算Python中字典中最常见的前10个值

    我对 python 和一般编程都很陌生 所以请友善 我正在尝试分析包含音乐信息的 csv 文件并返回最常听的前 n 个乐队 从下面的代码中 每听一首歌曲都是一个列表中的字典条目 格式如下 album Exile on Main Street
  • 如何让Gtk+窗口背景透明?

    我想让 Gtk 窗口的背景透明 以便只有窗口中的小部件可见 我找到了一些教程 http mikehearn wordpress com 2006 03 26 gtk windows with alpha channels https web
  • 如何按时间间隔匹配数据帧?

    这是我从数据记录器导入原始数据时经常出现的问题 温度记录仪设置为每十分钟记录一次温度 单独的气体记录仪设置为记录最后十分钟间隔内使用的气体 我想将这两个记录器的数据合并到一个数据框中进行绘图和分析 但时间并不完全一致 我希望每十分钟的时间段
  • 从固定文档中删除页面?

    如何从固定文档中删除页面 我添加这样的页面 Add page to pageContent PageContent pageContent new PageContent IAddChild pageContent AddChild fix
  • Bootstrap 导航栏与 Google 位置重叠自动完成下拉菜单

    我有一个导航栏 我试图在其中添加一个地点搜索框 除了谷歌位置提示框的一小部分被导航栏重叠 如下图所示 之外 一切几乎都有效 我尝试过改变z index输入框的值改为10或2000或90000但似乎没有效果 我还缺少其他需要做的事情吗 这是
  • Flutter Web 崩溃并显示无法打开文件 client.js

    我可以就这个错误请求你的帮助吗 当我第一次尝试使用 flutter run d chrome 运行 flutter web 时会发生这种情况 Launching lib main dart on Chrome in debug mode S
  • 将文本叠加在图像背景上并转换为 PDF

    使用 NET 我想以编程方式创建一个 PDF 它仅包含一个背景图像 其上有两个具有不同字体和位置的标签 我已阅读过有关现有 PDF 库的信息 但不知道 如果适用 哪一个对于如此简单的任务来说最简单 有人愿意指导我吗 P D 我不想使用生成的
  • NHibernate - CreateCriteria 与 CreateAlias

    假设以下场景 class Project public Job Job class Job public Name 假设我想使用 Criteria API 搜索其 Job 名称为 sumthing 的所有项目 我可以使用 CreateAli
  • 在 Dynamics CRM 插件中访问电子邮件发件人地址

    我正在编写一个 Dynamics CRM 2011 插件 该插件挂钩到电子邮件实体的更新后事件 阶段 40 pipeline http msdn microsoft com en us library gg327941 aspx 并且在此阶
  • 模块“””在 ionic 3 Geolocation 中没有导出成员“NativeGeocoderReverseResult”

    模块 没有导出成员 NativeGeocoderReverseResult L13 从 ionic native geolocation ngx 导入 Geolocation L14 导入 NativeGeocoder NativeGeoc
  • WCF:将随机数添加到 UsernameToken

    我正在尝试连接到用 Java 编写的 Web 服务 但有些东西我无法弄清楚 使用 WCF 和 customBinding 几乎一切似乎都很好 除了 SOAP 消息的一部分 因为它缺少 Nonce 和 Created 部分节点 显然我错过了一
  • 如何在查询语句之外从mysql查询中获取值?

    这是下面的函数console log function quo value value connection query SELECT role from roles where id 1 function error results fi
  • REST URI 和对象上的操作,可以进行评论、标记、评级等

    我正在为我的公司研究一种 Web API 看起来我们可能会实现一个 RESTful API 我现在已经阅读了几本关于此的书籍 O Reilly 的 RESTful Web 服务 似乎最有用 并为可以评论 标记和评级的对象提出了以下一组 UR
  • Pandas 每周计算重复值

    我有一个Dataframe包含按周分组的日期和 ID df date id 2022 02 07 1 3 5 4 2022 02 14 2 1 3 2022 02 21 9 10 1 2022 05 16 我想计算每周有多少 id 与上周重
  • R.java是手动修改的!恢复到生成的版本

    我在布局中添加了一个 xml 文件 之后这个错误就来了 但问题是我还没有接触过 R java 文件 现在 在我的新活动中 我要将其内容视图设置为我新创建的 xml 文件 但是当我执行 R layout 时 新创建的 xml 不会出现在建议中
  • OutputCache 因复杂对象属性而异

    我有一个控制器操作 它接收一个复杂对象作为参数 我需要 OutputCache 根据该复杂对象的属性之一而变化 这可能吗 如何 如果你有一个像这样的模型 public class person public string Name get
  • 当当前分支上有未提交的更改时签出另一个分支

    大多数时候 当我尝试签出另一个现有分支时 如果我在当前分支上有一些未提交的更改 Git 会不允许我这样做 所以我必须首先提交或隐藏这些更改 然而 有时 Git 确实允许我在不提交或存储这些更改的情况下签出另一个分支 并且它会将这些更改携带到