有没有办法让 Git 暂存/取消暂存文件而不是更改?

Posted

技术标签:

【中文标题】有没有办法让 Git 暂存/取消暂存文件而不是更改?【英文标题】:Is there a way to make Git stage/unstage files instead of changes? 【发布时间】:2021-03-16 15:54:44 【问题描述】:

每次编辑后都必须不断地重新暂存已经暂存的文件,这浪费了我的时间。我已经暂存了一次文件。忘记重新暂存文件意味着可能无法提交必要的更改。

关于 git 如何处理更改而不是文件的教育性声明还需要附带有关如何进行更改(无需命名文件)的信息,这不需要冗长的 CLI 指令。 AFAICT git add 需要文件名等。

编辑:这不是指定问题的重复,因为我不想在每次已暂存的文件编辑之后,甚至只是在提交之前执行一次操作(运行任何 CLI 命令、单击按钮等) .我问是否有办法在这方面配置 git(.gitattribute 等)的行为,所以它总是按照我需要的方式运行。我想在提交时处理文件,因为文件是我正在编辑的内容,并且在几乎所有常用工具中都被描述为更改列表。

【问题讨论】:

"git 适用于更改而不是文件" 不,它适用于文件。 git add -u 重新添加每个已暂存的文件以将任何新更改考虑在内。对非暂存文件没有影响。 git commit -a 拾取所有暂存更改的文件,就像您添加它们一样。 这能回答你的问题吗? Refresh staged files 有很多方法可以解决“我已提交但后来发现一个文件中有更多更改我忘记提交”;例如,很容易修改你刚刚提交的提交,或者用之前的提交压缩一个新的提交。有很多方法可以说“请确保您已将所有阶段文件的所有更改合并到暂存区域中。”甚至有一些方法可以提交而无需先添加。但这些都是必须做的。什么都不会自己发生。这很好。 【参考方案1】:

嗯,这就是 GIT 如此有用的部分原因,它允许您进行增量更改并在更新代码时查看差异。您可以使用git add -u 自动更新更改,但这与 GIT 和源代码管理自动更新的目的背道而驰,但我认为您不能这样做。

查看文件变化差异的好处是the diff,在开发时派上用场,它在staging之前显示了新的变化:

git diff

git add patch flag 是一个有用的工具,可以减轻您的挫败感:

git add -p

它将查看您在文件中更改的大量代码,并让您选择要暂存的代码。您不需要处理那么多文件。

【讨论】:

我要补充一点,如果大块太宽,可以使用“s”分割它,如果仍然不够,可以使用“e”直接编辑补丁。 是的,它是交互式的,您可以为每个块选择一组选项,“s”只有在 git 可以拆分时才会显示。当您单步执行Stage this hunk [y,n,q,a,d,K,j,J,g,/,e,?]? 时,选项看起来像这样,您可以通过回答“?”阅读更多内容 我使用过的所有其他 VCS 都会像 Git 一样进行增量更新。在这方面它并不特别。当文件系统上仅存在两者的组合并被程序/编译器/等使用时,我看不到分阶段与非分阶段差异的好处。该文件是我在本地编译和测试的以及应该提交的内容。这是 git 在“强大/有用”的幌子下允许的错误的另一个开口,而 VCS 的常见用途不需要存在。 我们中的一些人一次性编译/测试了一些东西,然后以更小的块提交它们。耸耸肩。 我认为哪个更好是一个见仁见智的问题,但我不认为我曾经认为较小的块是一件坏事。你有有趣的意见。【参考方案2】:

如果您要问的是是否可以使用git add 添加文件,然后对该文件所做的所有后续更改自动包含在下一次提交中,那么不,Git 没有内置该功能.

但是,您可以编写一个别名来执行此操作并使用它来代替git commit

[alias]
ci = "!f()  git status --porcelain | grep '^[AMD]' | cut -b4- | xargs git commit \"$@\" --; ; f"

然后您可以运行git ci,它会自动将所有更改提交到任何暂存文件。

但在别名之外,如果没有一些外部工具,这是不可能的。这种工作方式是有意为之的,即使它不符合您的喜好。

【讨论】:

commit -a 之上建立别名不是更简单吗? 但我不相信这就是 OP 所要求的。否则,他们可以毫无问题地使用git commit -a 对,但他从一开始就认为 commit -a 应该是标准行为(主要是因为他没有理解 Git,恕我直言)所以他认为有一种强制方法来设置它一劳永逸。这曾经存在于 CVS 等上,但如果我们迁移到其他东西,那是有原因的…… 不,我相信他们要求的是只提取暂存文件,而不是所有文件。我同意git commit -a 是获取所有文件的方式。 不完全是(这是一个陷阱):git add -A 确实会拾取所有文件,而 git commit -a 根据手册页仅拾取暂存文件,这使其成为git add -u ; git commit 的快捷方式.【参考方案3】:

考虑到您提出的问题以及您所做的 cmets 和编辑,确定 Git 是一个面向快照的 VCS这一事实可能会很有用。每个提交实际上都包含一个树对象,该对象指向该提交引用的每个文件。

每次您更改文件时,它是否是一个字节,它被假定为新的东西,然后再次记录。但是,由于所有内容都使用它们的 SHA1 和进行索引,因此只有不同的内容被单独保存。如果您多次录制同一个文件或恢复到以前的版本,则只会录制一次。此外,所有这些东西都是压缩的,因此您永远不会因此而面临任何空间问题。

通过这种方式,这种行为被引入为类似于文件系统的快照机制,这使得它可以接受。

这回答了您的第一个问题:文件始终被记录,而不是更改。您在浏览提交时看到的实际上是该提交与其父提交之间的自动“差异”操作。这也使您能够轻松地在两个任意修订之间进行“差异”,而无需先解决任何问题。它还向您保证,一旦您可以提交,您将可以访问其全部文件,即使您看不到其历史记录(对于影子克隆或您的存储库已损坏很有用)。

如果您现在想在每次提交时自动嵌入所有修改过的文件,您可以使用git add -u 标记所有更新的文件,或使用git add -A 将所有新文件包含在更新的文件中,甚至使用git commit -a 来执行一个 add -u/commit 在单个操作中。

您还可以轻松地定义 aliases 命令,如果您使用的是 shell,则可以从外部定义,也可以在 gitconfig 文件的 [alias] 部分中定义。例如,我个人使用:

[alias]
    root = rev-parse --show-toplevel

... 有一个git root 命令来查找我的存储库的根目录。

但是……你可能不想这样做。

这不是 Git 自动执行的原因是为了鼓励开发人员准备“熟”,一次只专注于一个目的的单一提交,即使此任务一次应用于多个文件,如果,在另一方面,同一个文件可以根据不同的目的在不同的地方进行修改。

这就是为什么,从这个角度来看,一次暂存所有修改过的文件通常是没有意义的,因为除非您非常频繁地提交,否则所有修改过的文件不太可能同时涉及一个主题。

如果你真的不关心它并且你想要保存你的工作状态,使用上述命令仍然很容易,但相信我,做干净的提交至少和代码一样有价值本身。当您独自工作时,这一点非常重要,而在团队合作中变得至关重要。

至于现在的索引:它实际上是一个非常聪明的方式来处理整个事情。起初,索引只是已经跟踪的文件列表。这是一个位于.git/index 下的平面二进制文件。但它不会坚持保存名称,它还会引用这些文件关联的内容对象。这意味着对象是在add 时间创建的,当你提交时,Git 只需要记录这个索引的状态。

这真的很有趣,因为这使 Git 能够知道文件是否未更改、已暂存、未暂存或两者兼而有之。此外,当您使用git add -p 选择大块时,Git 不会收集存储在某处的临时更改位:它会直接修改索引,然后允许您准确地准备您想要的内容,或者在您更改时将其恢复到初始状态你介意。

Git 并不像看起来那么神秘。您需要掌握的唯一概念是对象概念、索引的工作方式以及可选的 reflog,以便在出现问题时轻松恢复。特别是,不要尝试模仿 Mercurial 的行为:一开始看起来很容易,但很快就会把你带入死胡同。

您可能对此帖子感兴趣:What is the use of Staging area in git

【讨论】:

提交是干净的提交。所有更改都旨在一起提交,因为那是我一起开发和测试的。我主要是在提交更改之前查看更改时遇到这种痛苦。如果我在文件中找到我必须解决的问题,我会这样做并对其进行测试...然后必须再次暂存文件。啊。另外我正在使用 Visual Studio,因此可以将运行外部 CLI 命令的选项转换为 IDE 命令,但我首先在寻找内置的东西。 Git 和其他 VCS 工作在一般意义上对我来说并不神秘。提交更改、合并、分支、标记/标签、重新父级、回滚等。它们都做这些基本的事情,只是有些比其他的更好或更有效或更安全或更以团队为中心。我不应该关心或担心像 reflog 这样的内部机制,除非我是制作 VCS 的团队中的一员。 Hg 是我没有实际使用过的一种。我更喜欢 TFVC,因为我可以用最少的操作完成所有必要的日常活动,可视化工具很好,为团队管理 repo 不需要大量的分支清理,我不需要担心任何人不小心删除提交或丢失更改,它有搁置集。对我来说不幸的是,由于热衷于迎合 FOSS 社区,MSFT 已经忘记了它所做的一件了不起的事情,以至于 VC PM 被错误地告知了它的功能(“tfvc 没有分支,等等”...... Smh)

以上是关于有没有办法让 Git 暂存/取消暂存文件而不是更改?的主要内容,如果未能解决你的问题,请参考以下文章

Git stash 部分暂存文件

基于更改类型的 git add/rm 文件(文件的)

git基础教程(14)取消暂存和取消工作区修改git restore 和 git restore --staged

如何在 git 中取消暂存已删除的文件? [关闭]

如何 Git 取消暂存所有暂存文件? [复制]

10-git-取消暂存的文件