【问题标题】:Git reset soft vs mixed - why use --mixed at all?Git 重置软 vs 混合 - 为什么要使用 --mixed?
【发布时间】:2020-07-16 12:08:02
【问题描述】:

当使用git reset 时,如果第一个选项意味着重新添加--soft 已经处理的文件,为什么更喜欢使用git reset --mixed 而不是git reset --soft

另外,关于 2 个选项之间的区别 - 如果我 使用 git reset --soft(例如作为练习),是否存在 git reset --mixed && git add 获胜的情况?无法模仿git reset --soft 的行为?


编辑:我知道有类似的问题,但他们没有深入探讨git reset --mixedgit add 可能不等同于git reset --soft 的极端情况,它们主要总结了已知文档。

【问题讨论】:

  • @CodeCaster 否。它说明了差异,但没有显示一个选项优于另一个选项的场景。更重要的是,如果我们在“mixed”之后使用“add”,它并不能真正解释这 2 个选项是否等效,或者存在两个选项不等效的极端情况

标签: git git-reset


【解决方案1】:

考虑一下git reset(在它的三种模式中,软、混合和硬,而不是其他根本不属于这三种模式之一的其他东西)的作用。你跑:

git reset --<mode> <commit-specifier>

它做了以下三件事,或者可能是 2 或 1:

  1. (--soft, --mixed, --hard) 它改变了存储在HEAD 中的当前分支名称,以指向给定的提交。使用--soft,它现在停止了。

  2. (--mixed--hard) 它将现有的索引内容替换为您在步骤 1 中选择的 commit 的内容。使用 --mixed(或默认值),它现在停止了。

  3. (仅限--hard)它将工作树内容替换为在步骤 2 中更新的文件。

现在,您可以,如果您选择,在步骤 1 中选择 当前提交 作为目标,例如运行 git reset HEAD。如果您这样做,步骤 1 中更新的当前提交就是当前提交。也就是说,第 1 步没有实际改变。

如果您运行 git reset --soft HEAD,则第 1 步不会进行任何更改,然后 git reset 会退出。所以这绝对没有任何作用。

如果你运行 git reset 而不使用 --soft,但是 - 根本没有参数,默认为 --mixed,或者使用 --hard - 它会继续第 2 步:将索引的内容替换为一直冻结到当前提交中。实际上,这会取消您之前所做的任何 git add

如果您的目标是之后再次重新执行所有 git add,那么这没有用。但如果你的目标是重新做所有这些git adds,它可以。例如,考虑一下这个例子——它本身并不是非常有用,但只是为了说明:

git checkout somebranch
<edit for a while, test, `git add .`>

# think: wait, I don't want to commit everything
git reset      # index now matches HEAD

<edit README file to announce that the NEXT commit changes a lot of things>
git add README
git commit     # make a commit in which everything is the same except README

git add .
git commit     # make final commit in which everything is changed

为了理解这一切,请记住,每个文件在任何时候都有三个副本:

  • 当前提交中的每个文件(README.mdmain.py 等,无论您拥有什么文件)都有一个只读的、永久冻结的副本时间>。您可以随时使用git checkoutgit reset 更改哪个提交是当前提交,但提交本身一直被冻结:它的任何文件都不会改变,它的提交信息、作者等也不会。

  • 在 Git 的索引中有一个文件的冻结格式副本。1您可以随意更改:您可以覆盖该文件的副本具有另一个文件的副本或同一文件的另一个版本的文件。您甚至可以使用git rm 从索引中完全删除该文件。索引副本处于冻结格式,准备好进入提交,但它本身不是提交,因此它可以更改。

  • 最后,有一个可用的文件版本。它不是某种特殊的仅 Git 格式,您的计算机程序的 rest 实际上可以使用这个版本的文件。该版本位于您的工作树中。

文件的索引副本匹配至少一个其他副本(HEAD 副本、工作树副本或两者兼有)是非常典型的,但实际上,您可以让所有三个文件都不同。为此,只需:

  • 编辑工作树副本(务必保存以便git add 可以看到);
  • 使用git add 将工作树副本复制到索引;和
  • 再编辑工作树副本(并确保再次保存)。

现在文件都为提交暂存,这意味着HEAD和索引副本不同,并且没有为提交暂存,这意味着索引和工作-树副本不同。


1从技术上讲,索引中的内容只是模式、文件名和对内部 Git blob 对象引用。 blob 对象表示文件内容 的冻结格式副本。 Reset (git reset) 将模式、名称和哈希 ID 复制到索引中。添加 (git add) 通过创建一个新的 blob 对象或查找已经存在的 blob 对象来压缩(准备冻结)工作树文件,该对象稍后将重新扩展到工作树文件。

【讨论】:

    【解决方案2】:

    你说得对,你可以经常模仿 git reset --softgit reset --mixedgit add

    但是,我可以想象不可能的极端情况。假设您编辑了一个文件,然后使用 git add 将您的更改添加到索引中,但之后您意识到它是错误的并且您使用某些编辑器返回到以前的版本。现在,您处于一种情况,您认为文件根本没有更改,但您的更改仍然存在于索引中。区别就在这里:git reset --soft 将保留您的分阶段更改,而使用 git reset --mixed 它们将永远丢失(git add 不会帮助您,因为您没有什么可添加的)。

    这些标志有不同的用例:--mixed 通常用于从索引中删除意外添加的更改,我感觉--soft 很少使用。我只使用了一次 --soft 标志,当时我忘记创建功能分支并在 master 上提交。

    【讨论】:

    • 我明白你的意思。正是我正在寻找的情况,也是一个很好的例子,有助于更好地理解索引如何与 git add 和 commit 交互。谢谢!
    猜你喜欢
    • 2013-07-19
    • 2011-01-29
    • 2011-04-01
    • 2012-06-27
    • 2018-03-27
    • 1970-01-01
    相关资源
    最近更新 更多