刷新暂存文件

25
在git中,是否有任何(简单的)方法可以修改索引(index),以便只添加已经存在于索引中的文件的更改?这听起来有点复杂,但我想要实现的很简单。
假设我的索引看起来像这样(稍微削弱了git status输出):
# Changes to be committed:
#       modified:   A
#       modified:   B
#
# Changed but not updated:
#       modified:   B
#       modified:   C
#
# Untracked files:
#       D

一些对 B 的更改已经在索引中了, 但有一些并没有。 C 根本没有被暂存。

我该如何更新索引中的 B (暂存它未暂存的更改),而不添加 C?

也就是说,我希望索引看起来像这样:

# Changes to be committed:
#       modified:   A
#       modified:   B
#
# Changed but not updated:
#       modified:   C
#
# Untracked files:
#       D
在这种简单的情况下,可以通过简单的git add B实现,但我想知道通用情况下是否有简单的答案。我尝试过git add --refresh,但如果我理解正确,那只会更新stat信息。

你能展示一个实际的使用案例来解释为什么要这样做吗?我无法想象出任何这样的案例(当我添加一个文件并对其进行修改时,并不意味着我会自动希望添加这些更改,尤其是当我不想在其他文件中添加更改时)。 - Jan Hudec
@JanHudec 如果我更加严格地选择只提交应该在提交(B)中去的文件,我可能就不需要这个了。然而有时候我会有些冲动,开始做一些应该在新的提交(C)中的修改,所以我会将 B 添加到索引中。在提交之前,我总是会审查 diff --cached,并且有时会清理掉B中的某些内容。那么这就是我需要这个工具的时候。我猜也许可以用另一种方法来解决这个问题,比如使用 stash。 - axelarge
我的观点是,当你在文件 X 中做一些应该放在提交 B 中的事情,并且被带走并进行了应该放在提交 C 中的更改时,其中一些更改通常又会涉及到文件 X。在这种情况下,您需要手动添加-i个别块,而不仅仅是重新添加文件 X。显然,如果你被带走了,你可能会注意到你正在改变的点周围的某些东西,这就是为什么额外的更改不太可能不涉及第一组所涉及的文件的原因。 - Jan Hudec
2个回答

36
以下命令将更新索引以包含尚未暂存的B中的其他更改:
git update-index --again

2
啊,比我的方法好多了! - torek

1

我不知道有完全简单的方法来做到这一点,但是:

git status --porcelain

将只显示文件B,并且状态为“MM”,因此:

git status --porcelain | grep ^MM | cut -d' ' -f 2

将会生成这些文件的列表。

重复添加 A 没有任何害处。

您也可以使用 git diff-index --cached --name-status HEAD。(如果您的 git 版本太旧无法使用 git status --porcelain,可能需要使用此命令。)


目前它与 -s / --short 相同,但承诺将继续保持机器可解析性,如果您将其插入某些脚本中,则这一点非常重要。 :-) - torek
我尝试过 git status --porcelain | grep ^[AM]M | cut -d' ' -f 2- | xargs git add,但是它无法处理包含空格的文件名。我猜这可能被视为另一个问题,但是也许你可以帮忙吗?使用 xargs -0 根本不起作用。 - axelarge
呃,空格。我故意忽略了它们。:-) 在这里不使用-z,git用引号编码空格。这至少适用于一个情况:git status --porcelain | grep ^MM | sed 's/...//' | while read var; do eval git add $var; done但我不知道它是否适用于所有情况(像这样使用eval并不能让我感到温暖和舒适...)。 - torek
@hroptatyr: 这样做不太行,因为git会打印出带有双引号的文件名 "E F",对于名为 e-space-f 的文件。可以使用 git status --porcelain -z,但是简单的grep命令就无法正常工作了。 - torek
最初让我感到惊讶的是,git add E\\\ F 可以添加名称为 E\ F 的文件, 这可能是由于 Git 使用的 fnmatch 调用造成的。你甚至可以 git add \\A 添加名为 A(而不是 \A)的文件。但是,我会省略最后一个 sed,因为它不是必需的(例如,尝试使用 xargs ls -l 而不是 git add)。但是,这对于名称为 " 的文件不起作用。(使用 | while read -r var; do eval git add $var; done 可以处理名称为 " 的文件。尽管我不喜欢使用 eval。) - torek
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接