git stash 是否仅存储暂存文件,甚至是未暂存和未跟踪的文件?

aak*_*iti 5 git github gitlab gitlab-ci

我在错误的分支()上对代码做了一些更改dev。我想将所有更改转移到master分支,我从这里得到了一些线索,但我不清楚git stash存储是否仅暂存文件,甚至是未暂存未跟踪的文件?

\n

因为,切换分支后,我需要将未暂存未跟踪的文件提交到master分支上。

\n

分支机构状态dev

\n
\xe2\x9d\xaf git status\nOn branch dev\nYour branch is up to date with \'origin/dev\'.\n\nChanges not staged for commit:\n  (use "git add <file>..." to update what will be committed)\n  (use "git restore <file>..." to discard changes in working directory)\n    modified:   __init__.py\n    modified:   src/App.py\n    modified:   src/analysis/insis.py\n    modified:   src/access/via/db.py\n    modified:   src/process/DM.py\n    modified:   start.sh\n    modified:   utility/utils.py\n\nUntracked files:\n  (use "git add <file>..." to include in what will be committed)\n    docs/\n    process.py\n    src/flow.py\nno changes added to commit (use "git add" and/or "git commit -a")\n
Run Code Online (Sandbox Code Playgroud)\n

当切换到master分支时,我收到以下错误:

\n
\xe2\x9d\xaf git checkout master\nerror: Your local changes to the following files would be overwritten by checkout:\n    start.sh\nPlease commit your changes or stash them before you switch branches.\nAborting\n
Run Code Online (Sandbox Code Playgroud)\n

如何进行安全切换master,将所有上述未暂存和未跟踪的更改从转移devmaster

\n

LeG*_*GEC 13

默认情况下:git stash存储暂存文件(索引)和未暂存文件(跟踪文件,已修改但未添加)。未跟踪的文件不会被存储并保留在磁盘上。

您可以使用 :

  • git stash -k告诉 stash 将暂存的文件保留原样,并且仅存储未暂存的修改,
  • git stash -u告诉 stash包含未跟踪的文件,
  • git stash -a告诉存储包括未跟踪和忽略的文件。

参考:git-stash 选项


tor*_*rek 8

所做git stash的就是进行一些提交。这意味着它不会做任何您无法通过其他方式(仅通过提交)做的事情。

\n
\n

我不清楚 git stash 是否仅存储暂存文件,甚至是未暂存和未跟踪的文件?

\n
\n

除了最后一部分之外,这并不是一个格式良好的问题。默认情况下,git stash不会存储未跟踪的文件\xe2\x80\x94,但有一个选项可以git stash使其执行此操作。 您可能不应该使用此选项。 要真正了解git stash其工作原理以及您可以做什么,您需要了解很多事情。

\n

Git 就是关于提交

\n

Git 并不是真正关于分支*。相反,它与提交有关。分支名称很有用:它们可以帮助您(和 Git)找到提交。但重要的是承诺。

\n

每次提交都包含所有跟踪文件的完整快照。(当我们讨论 Git 的索引暂存区域时,我们将在后面的部分中进行跟踪)这些文件以特殊的、只读的、仅限 Git 的、冻结、压缩和去重复的形式存储在提交中。这种重复数据删除意味着当您进行新的提交并重新使用先前提交中的大部分文件时,新提交的文件将被重新使用。提交实际上不需要文件的另一个副本:它只是重新使用先前提交中的冻结文件犯罪。

\n

每个提交都有编号,但这些编号不是简单的连续编号,如 #1、#2、#3 等。相反,每个提交都有一个丑陋的大哈希 ID,该 ID 对于该特定提交来说是唯一的。任何地方的每个 Git 都会同意提交获取哈希 ID,并且其他提交都不能使用该哈希 ID。这在内部通过计算构成提交的所有位(1 和 0)的加密校验和来实现。由于所有 Git 使用相同的算法,因此他们都会就该哈希 ID 达成一致

\n

(这反过来意味着实际上不可能更改提交。如果您从 Git 对象的大数据库中取出提交,修改一些位,然后将其放回原处,则新提交具有不同的哈希 ID。之前的提交继续存在。因此提交,就像 Git 冻结存储的文件一样,不可能更改。)

\n

除了每个文件的完整副本(但已删除重复)之外,每个提交还存储一些元数据:有关提交本身的一些信息。此信息包括进行提交的人员的姓名和电子邮件地址、一些日期和时间戳以及他们解释为何进行该提交的日志消息;但它也包含了 Git 本身的一些东西:前一个的哈希 ID提交的哈希 ID。这允许 Git 向后工作。

\n

分支名称仅保存分支上最后一次提交的哈希 ID。我们不会在这里讨论太多细节,因为我们对存储提交更感兴趣,除了描述 Git 通常如何进行新提交之外。

\n

你的工作树

\n

每次提交中存储的文件都是只读的,而且其格式是计算机上的大多数程序实际上无法读取的。那么您如何处理您的文件呢?或者,换句话说,提交是只读的,那么如何创建新的提交呢?

\n

Git 对此的回答是为您提供一个工作树工作树。首先使用git checkout或选择一些提交\xe2\x80 git switch\x94,例如\xe2\x80\x94,Git 会从提交中获取所有冻结、压缩、重复数据删除的仅 Git 文件,并将它们扩展为正常的日常读/写文件你可以读和写。这些日常使用的文件副本(取自提交)位于您的工作树中。

\n

这意味着您看到和使用的文件实际上并不是Git 的文件。Git 的文件隐藏在目录中.git(大多数文件也没有正常的文件名:它们.git/objects以哈希 ID 名称存储和/或移动到特殊的包文件中,这些文件以更高的压缩率存储多个对象)。

\n

必须是这样,因为Git的文件是只读的,而且是Git-only的,你需要任何东西都可以使用的读/写文件。所以 Git 会填充你的工作树,然后你就可以开始你的工作了。工作树文件是你的: Git 只是在你要求时填写它们。

\n

这就足够了:Git 可以只拥有每个文件的两个副本,一份在当前提交中冻结,一份在工作树中解冻并有用。事实上,其他版本控制系统也这样做。但 Git 没有。Git 保留每个文件的第三个副本。1 这个额外的副本采用 Git 的冻结格式,但与提交中的副本不同,它并不完全冻结:您可以替换它。

\n
\n

1从技术上讲,第三个副本已预先进行重复数据删除,因此它实际上并不直接位于索引中。相反,索引保存每个文件的模式、文件名、blob 哈希 ID、暂存号以及其他使 Git 运行更快的信息。不过,您通常不需要知道这些:您可以假装索引保存每个文件的冻结格式副本,准备提交。如果您开始使用低级索引操作命令,则只需了解 blob 哈希值,git ls-files --stage并且git update-index.

\n
\n

索引或暂存区

\n

索引是 Git 中另一个非常重要的东西,但它通常没有得到很好的解释。部分问题在于它有点复杂:例如,它在合并期间扮演着更大的角色。但总的来说,Git 的索引有一个很好且相对简单的描述:Git 的索引保存着您建议的下一次提交。

\n

注意:该索引要么非常重要,要么最初的命名非常糟糕,以至于它现在有三个名称。它被称为索引(如此处),或者暂存区(代表它在进行新提交时的作用),或者\xe2\x80\x94,这些天很少\xe2\x80\x94缓存。这三个名字都指同一件事。2

\n

换句话说,任何时候,都有三个每个文件

\n
    \n
  • 一个位于当前或HEAD提交中,并且该副本被冻结:没有任何东西可以改变它。您可以进行具有不同副本的新提交,但旧提交将继续保留旧副本。

    \n
  • \n
  • 第二个已准备好冻结,位于 Git 的索引中。它开始匹配冻结的副本。

    \n
  • \n
  • 最后一个是日常格式,可供您使用:它位于您的工作树中。

    \n
  • \n
\n

当您运行并进行新提交时,Git 会立即git commit打包 Git 索引中的所有文件,并将它们放入新提交中。因此,新提交恰好包含当时 Git 索引中每个文件的版本。

\n

当你运行git add一个文件时,你实际上是在告诉 Git:将文件的工作树版本复制到索引中。 Git 将其压缩为冻结格式(如果已经有副本,则对其进行重复删除)。如果这是一个全新的文件,那么它现在位于索引中。如果它已经在索引中,则会启动旧副本索引中引导出来;现在索引副本与工作树副本匹配。

\n

您还可以告诉 Git从索引中删除文件。如果它之前存在(从提交或工作树复制),现在它就消失了。执行此操作的主要命令是git rm, 和git rm会删除索引副本,还会删除工作树副本。由于工作树副本根本不在 Git\xe2\x80\x94 中,除非您将其复制到索引中,也就是说,或者除非它来自提交 \xe2\x80\x94 并且您刚刚也删除了索引复制,请小心此操作。

\n

要删除文件的索引副本而不删除工作树副本,您可以使用git rm --cached. 由于仍然存在工作树副本,因此危险性较小,但请记住工作树副本不在 Git 中,并且当您进行新提交时,新提交不会有文件的副本。

\n

因此,当索引/暂存区域开始匹配提交时,您通常会修改内容,然后让 Git更新索引。您对索引所做的更新会导致“文件暂存以供提交”。如果您尚未更新索引,但已更新工作树中的文件,则会导致“文件未暂存以供提交”。请注意,您可以同时执行以下两项操作:

\n
    \n
  1. 提取提交:现在文件F的所有三个副本都匹配。
  2. \n
  3. 修改F的工作树副本。现在HEAD和索引F匹配,但工作树不匹配:文件“未暂存以进行提交”。
  4. \n
  5. Run Now与F的索引副本不匹配,但索引和工作树副本匹配:文件已“暂存以供提交”。git add FHEAD
  6. \n
  7. 对F的工作树副本进行更多修改。现在,所有三个副本都不同,因此文件F既“暂存用于提交”又“未暂存用于提交”!
  8. \n
\n

同样,这里要记住的是每个文件都有三个副本。通常,其中两个,甚至三个都匹配。当它们匹配时,Git 只是不任何有关额外副本的信息。

\n

和命令是更新 Git 索引的git add两个git rm主要命令。您必须在进行新提交之前更新 Git 的索引,因为git commit使用 Git 索引中的文件副本。这就是这里的全部内容。3

\n
\n

2有时,尤其是在 Git 源代码中,“缓存”一词指的是读取索引产生的内部数据结构。

\n

3请注意,git commit -a并将任何要提交的文件添加到索引中。这可能会变得相当复杂,特别是如果您使用git commit filesgit commit --only; 我们不会在这里讨论这些细节。

\n
\n

跟踪文件与未跟踪文件

\n

这给我们带来了未跟踪文件的定义,它也非常简单:未跟踪文件是指不在 Git 索引中的文件。 也就是说,如果您的工作树中有一些名为U 的文件,但U目前不在 Git 的索引中,则U未被跟踪。

\n

将文件U添加到 Git 的索引(同时将其保留在工作树中),现在U已被跟踪。将其从 Git 的索引中删除(同时将其保留在工作树中),U将再次不受跟踪。由于git commit在新提交中只会存储 Git 索引中的那些文件,因此未跟踪的文件不会被提交。

\n

现在我们终于可以理智地谈谈git stash

\n

一个普通的git commit命令:

\n
    \n
  • 收集您的一些元数据,例如您的姓名、电子邮件地址以及日志消息;
  • \n
  • 将 Git 索引中已经处于冻结格式的所有文件写出到新的提交中,并使用上面的元数据(以及当前提交的哈希 ID)将所有这些文件写入新的提交中;和
  • \n
  • 将新提交的哈希 ID 存储在当前分支名称中,因为新提交是新的最后提交。
  • \n
\n

git stash命令的开始非常相似,但它不是从您那里获取日志消息,而是自己生成一条日志消息。然后它会从当前Git 索引\xe2\x80\x94 中的任何内容进行提交,但它根本不会将此提交放在当前分支上。

\n

以几乎通常的方式进行提交后,git stash现在运行相当于git add -u根据工作树中的同一文件更新 Git 索引中的所有文件。这会更新索引以匹配您的工作树文件\xe2\x80\x94,但索引中只有跟踪的文件(根据定义),因此只有这些文件会被更新。stash 命令现在从此索引进行提交,保存所有跟踪的文件。

\n

Git 将这两个提交\xe2\x80\x94(索引一和工作树一\xe2\x80\x94)联系在一起,4然后运行git reset --hard​​. 5 这会将工作树中的所有跟踪文件恢复到当前提交中的相同状态,并且还会使用当前提交中的冻结格式副本覆盖 Git 的索引。因此,您现在有一对提交,它们保存了先前的索引先前的工作树\xe2\x80\x94两个完整快照\xe2\x80\x94但未跟踪文件根本不保存在这里。

\n

由于此存储提交对不在任何分支上,因此您稍后可以更改到新分支并使用git stash applygit stash pop或它们的任何变体将存储应用到不同的起点。--index实际的应用过程有些复杂,如果您在应用时忘记使用,则该pop命令如果成功,将删除两个提交,即使它实际上并不使用索引提交。因此,我总是建议任何使用该方法的人git stash避免git stash popgit stash apply先使用,然后检查以确保获得所需的结果,然后再使用它git stash drop来丢弃存储。

\n
\n

4从技术上讲,Git 通过以合并提交的形式进行工作树提交来实现此目的。其他 Git 工具会认为这是正常的合并,并且不能很好地处理它;您需要在存储提交上使用git stash以使它们表现良好。

\n

5不久前,git stash这是一个奇特的脚本,并且直接使用各种 Git 命令,包括git reset --hard. 现在它是一个 C 程序,但它仍然执行相同的操作,只是不运行额外的命令。

\n
\n

git stash有选项

\n

当您运行git stash创建新的存储时,您可以为其提供以下两个选项之一:

\n
    \n
  • -u或者--include-untracked:这将进行第三次提交,我们稍后将对此进行描述。
  • \n
  • -a--all:这也进行了第三次提交。
  • \n
\n

这两个选项都告诉我们git stash要进行第三次存储提交,以及通常的两个(索引和工作树)。唯一的区别是第三次提交的内容:

\n
    \n
  • 使用-a,工作树中但不在 Git 索引中的所有.gitignore文件都将进入第三次提交,包括 中列出的文件;
  • \n
  • 使用 时-u,未在 中列出的.gitignore跟踪文件会进入第三次提交,但在 中列出的未跟踪文件不会.gitignore进入第三次提交。
  • \n
\n

完成第三次提交后,6 stash 命令会从您的工作树中删除进入此提交的每个文件。

\n

当您去恢复存储时,Git 会检查它是两次提交存储还是三次提交存储。如果是三次提交存储,Git 将尝试从第三次提交中提取所有文件。如果这些文件中的任何一个现在在您的工作树中\xe2\x80\x94请记住,这些文件在您进行存储时是未跟踪的文件,因此它们在您的工作树中,然后\xe2\x80\x94Git将拒绝完全提取这个藏品。您必须将任何此类文件移开,或完全删除它们。

\n

如果 Git可以提取第三个提交,它就会这样做,并且还会以通常的方式提取其他两个提交。因此,您可以使用这些三提交存储之一来存储未跟踪的文件。

\n
\n

6出于技术原因,此提交必须在工作树提交之前进行,因此在某种程度上,这是第二次提交,但它被小心地转移到像第三次提交一样,以便稍后提取。

\n
\n

保持阶段性变更

\n

如上所述,git stash push或者git stash save将创建一个包含两次提交的新存储:

\n
    \n
  • 一次提交按原样保存当前索引。
  • \n
  • 另一个提交按原样保存当前工作树。
  • \n
\n

暂存的更改实际上意味着“某些文件的索引副本与该文件的提交副本不同”。通常,这又意味着该文件的工作树副本与索引副本匹配。

\n

git stash apply 没有--index选项的稍后将忽略索引提交。如果索引提交与工作树提交具有相同的每个文件副本,并且您仅应用工作树提交,那么您将获得对工作树所做的相同更改:忽略索引不会丢失任何内容提交,除了忘记git add之前使用过哪些命令。

\n

稍后的git stash apply with --index告诉 Git:在应用工作树提交之前,尝试将索引提交应用到当前索引。 这并不总是有效,如果它不起作用,git stash只会建议您尝试不使用--index. 如果使用--index非常重要,这可能是个坏建议!

\n

如果一切正常,Git 的索引将会更新。因此,现在某些更改将再次“暂存以供提交”\xe2\x80\x94,请记住,这仅意味着“文件的索引副本与当前提交的副本不同”。

\n

无论如何,无论有没有--index,如果git stash apply命令现在移至工作树提交,它将使用 Git 的合并机制来尝试应用此提交。这可能会导致合并冲突。如果确实如此,他们可能会非常混乱。

\n

git stash我宁愿大部分时间不使用

\n

大多数时候,而不是git stash我建议您只进行提交,而不是进行提交。

\n

很容易做出提交,即使是在“错误的分支”上,然后稍后“删除”它。(提交本身会保留一段时间,以防您决定要回它:默认情况下,Git 至少需要 30 天才能决定该提交不再有任何用处,之后 Git 将清除它。)在分支上进行的“错误提交”是无害的,只要您小心不要将其与git push其他东西一起发送,并且进行提交后,您现在可以切换到正确的分支并使用git cherry-pick复制它。

\n

拥有所有 Git 工具\xe2\x80\x94,包括git diff和\xe2\x80\x94,它们可以在正常、日常、容易找到和容易看到的提交上工作,这比必须在难以检查的提交上使用要愉快得多,因为它们是不是每天提交,也不在任何分支上。git showgit cherry-pickgit stash apply

\n

尽管如此,git stash有时还是非常方便的。如果出现问题,该git stash branch命令可以将现有存储转变为新分支,然后您可以访问 Git 的所有常规工具。

\n