如何使用git只暂存新文件的一部分?


221

喜欢 git add --interactive。现在,它已成为我日常工作流程的一部分。

该问题似乎不适用于未跟踪的文件。我想做的是跟踪一个新文件,但仅添加其中的一部分,即该新文件的某些部分尚未准备就绪。

例如,使用git add -i,我可以选择patch选项,甚至编辑各个块,以暂存新代码的某些部分,而使调试代码注释未暂存。我喜欢以这种方式工作,因为它使我目前正在工作的大型补丁程序的哪些位置仍很明显仍需要工作。

不幸的是,我似乎无法对未跟踪的文件执行相同的操作。我要么登台整个文件,要么什么都没有。我一直在使用的解决方法是暂存或什至在文件为空时提交新文件,然后以通常的方式暂存单个更改。但是,这种解决方案感觉就像是一个肮脏的hack,当我忘记或改变主意时,它会带来更多的麻烦。

因此,问题是:如何仅暂存新文件的一部分,以便跟踪此新文件,但不暂存其全部或部分内容?

Answers:


414

哇,这一切update-indexhash-object业务似乎都过于复杂。怎么样呢:

git add -N new_file
git add -i

来自git help add

-N, --intent-to-add
    Record only the fact that the path will be added later.  An entry
    for the path is placed in the index with no content.  This is useful
    for, among other things, showing the unstaged content of such files
    with git diff and committing them with git commit -a.

9
++ 1!到期信用。我确实非常信任我现在知道这些手册....</shame>
sehe 2011年

1
很好发现。我应该进一步滚动手册页。也许我应该归还Git Pro徽章。
dave1010 2011年

3
想知道为什么git-gui在内部不使用它来能够从新文件中暂存行。
Deiwin 2014年

6
精彩的-N发现,谢谢!尽管-p在这种情况下我更喜欢将其与。gid add -N the_filegit add -p。应该补充一点,它-N也适用于-A
Cyril CHAPON 2015年

@Deiwin-您可以在您的.gitconfig文件中添加[guitool]以执行“ git add -N $ FILENAME”:[guitool“意图添加”] cmd =“ git add -N $ FILENAME” needsfile =是noconsole =是
史蒂夫·弗利

7

执行此操作最简单的方法(通常是imho交互式暂存)git gui。它与git捆绑在一起,并且可以在git支持的几乎所有平台上使用。

只需运行git gui,就会打开一个gui,可以暂存和取消暂存块,甚至允许单行跟踪和未跟踪文件。

Git Gui屏幕截图


这是一个创造性的答案,有时非常非常有用。
Pablo Olmos de Aguilera C.

3
请注意,并非所有git发行版都包含git gui。例如,在Debian中,它位于单独的名为“ git-gui”的软件包中。
cristoper

多年来(一直不够努力)一直在寻找这个功能,这是改变生活的方式
austinmarton 2014年

2
对我而言,单行未跟踪文件的暂存git gui从未成功。实际上,它禁用了这些菜单选项
Deiwin

2
@Deiwin我实际上必须在问题中错过了–我的屏幕截图显示了已经被跟踪的文件。如果要git gui用于新文件,则必须先运行git add -N new_file-请参阅Richard Hansen的答案。
慢性的

6
git update-index --add --cacheinfo 100644 $(git hash-object -w /dev/null) newfile
git add --interactive newfile

简单的演示:

mkdir /tmp/demo
cd /tmp/demo
git init .

echo hello > newfile
git update-index --add --cacheinfo 100644 $(git hash-object -w /dev/null) newfile
  • 提示如果您确定git对象数据库中已存在“空” blob,则可以对哈希进行硬编码e69de29bb2d1d6434b8b29ae775ad8c2e48c5391。我不建议这样做
  • 提示如果您使用的是Windows,则可以使用NUL:代替/dev/null。否则,使用类似echo -n '' | git hash-object --stdin -w

现在索引将包含newfile为空blob,并且如果尚未存在该空blob,则将该空blob输入到对象数据库中:

$ find .git/objects/ -type f 
.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391

$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   newfile
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   newfile
#

$ git diff
diff --git a/newfile b/newfile
index e69de29..ce01362 100644
--- a/newfile
+++ b/newfile
@@ -0,0 +1 @@
+hello

这应该正是您想要的。我是否也可以建议使用vim逃犯插件进行非常智能的索引管理(请参阅更好的git add -p?


1
这似乎运作良好。我将其别名为“ stage-empty-file”,因为要记住它有点复杂。
dave1010 2011年

@ dave1010:很高兴它有所帮助!是的,我曾考虑过添加一个别名,但是我不知道您一般应该如何处理通配符或多个文件名参数。所以我选择不这么做
2011年

2

编辑:这似乎现在不起作用。我敢肯定是以前(在git 1.7.1上)。如果它不起作用,我建议/dev/null按照上面的建议进行分期:

git update-index --add --cacheinfo 100644 $(git hash-object -w /dev/null) newfile

如果您使用的是Windows(不带/dev/null),则可以将其替换为空文件的路径。

原始答案

你要

git add -p # (or --patch)

这为我添加了未跟踪的文件。从手册页:

交互地选择索引和工作树之间的补丁块并将它们添加到索引中。这使用户有机会在将修改的内容添加到索引之前检查差异。

这将有效地运行add --interactive,但会绕过初始命令菜单,而直接跳转到patch子命令。有关详细信息,请参见“交互模式”。


2
无论多么有趣,它对我都不起作用(git 1.7.4);git add -p newfile根本不起作用(nu效果),git add --interactive“ [a] dd untracked”具有的效果git add newfile编辑还用git 1.7.5.3进行了检查;没有骰子
sehe 2011年

Windows的好提示,在我的回答中添加了提示。Thx
sehe 2011年

-3

只是为了记录另一种可能性:我用

git add -N file
git add -p file

然后,您可以登上大块头,或就地编辑它们。


1
该答案与接受的答案相同,该答案可以追溯到2011年。Downvote。
Stanislav Pankevich '18

接受的答案add -N与结合add -i。我只是添加了它add -p而不是add -i作品。
Pedro Adame Vergara
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.