在Git中仅提交文件的一部分


2764

当我在Git中更改文件时,如何仅提交某些更改?

例如,如何在文件中更改的30行中仅提交15行?


3
相关的stackoverflow.com/q/34609924/52074:如果需要将大块拆分为较小的大块。
Trevor Boyd Smith,

摘要:就能力而言:git gui= git add -e> git add -i -p; 在便利性方面:git gui> git add -i -p> git add -e。所以:挑选git gui时,你有机会获得十挑git add -i -p简单的东西,当你没有或者不想使用X. git add -e复杂分期无X.
Penghe耿

Answers:


3686

您可以使用git add --patch <filename>(或-p简称为git),并且git会开始将您的文件分解为它认为合理的“大块”(文件的某些部分)。然后它将提示您以下问题:

Stage this hunk [y,n,q,a,d,/,j,J,g,s,e,?]?

这是每个选项的说明:

  • y 进行大块准备下一次提交
  • n 不要为下一次提交暂存此块
  • q退出; 不要上演这个大块头或其他任何大块头
  • a 暂存此大块,然后将其后的所有大块
  • d 不要暂存此大块或文件中任何以后的大块
  • g 选择一个大块头去
  • / 搜索与给定正则表达式匹配的块
  • j 尚未确定此大块,请参阅下一个未确定的大块
  • J 尚未确定此大块,请参阅下一个大块
  • k 保持未确定状态,请参阅先前未确定的状态
  • K 尚未确定此大块,请参阅先前的大块
  • s 将当前的块分割为较小的块
  • e 手动编辑当前大块
  • ? 打印大块帮助

如果文件不在存储库中,则可以先执行git add -N <filename>。之后,您可以继续git add -p <filename>

之后,您可以使用:

  • git diff --staged 检查您是否进行了正确的更改
  • git reset -p 取消误添加帅哥的舞台
  • git commit -v 在编辑提交消息时查看您的提交。

请注意,这与git format-patch命令的用途大不相同,命令的用途是将提交数据解析为.patch文件。

未来参考:Git工具-交互式登台


83
注意这-p/--patch-i/--interactive启动有用的“ 交互”模式的命令中补丁操作的快捷方式,可能会很有用。
tutuDajuju 2015年

5
>如果该文件已经上演会怎样?它将仅显示未分阶段的更改。一样git diff
Eugen Konkov 2015年

3
如何手动编辑当前大块?输入e后我不知道该怎么办。
洪苏2015年

23
按下之后e,您可以通过替换+-#
veksen

1
这很棒,但是现在我该如何推动它了?如果我这样做,git push它说已经是最新的了。如果我愿意,git diff我会看到我说过的帅哥n。如果我git diff --staged看到我要推送的提交,假设我可以推动提交,如何删除对我说的粗俗内容no
chovy

250

您可以使用git add --interactive或,然后使用(not); 看到交互模式的git-ADD手册页,或只需按照说明进行操作。git add -p <file>git commit git commit -a

Modern Git还具有git commit --interactive(和git commit --patch,这是交互式提交中补丁选项的快捷方式)。

如果您更喜欢通过GUI进行操作,则可以使用git-gui。您可以简单地标记要包含在提交中的块。我个人觉得比使用容易git add -i。其他git GUI,例如QGit或GitX,也可能具有此功能。


1
有趣的是,对于windows.github.com部分文件提交了支持,但最近似乎放弃了它..
尤里

1
@Juri我认为部分文件提交的支持是回。
Ela782

@Juri不客气。我实际上从来没有注意到它曾经存在过-上周我看到了它,然后想:“哦,这真是一个了不起的新功能”!:-)
Ela782

1
如今,windows.github.com重定向到重新命名的GitHub桌面,它比Git GUI更好,并且支持部分提交...但是不支持提交签名。叹。

147

git gui在diff视图下提供了此功能。只需右键单击您感兴趣的行,您将看到“暂存此行以提交”菜单项。


13
对于复杂的补丁程序,这通常对我来说是最快的方法。
hochl 2015年

7
这是一种非常有效且直观的方式,可以以精细的方式将更改添加到登台区域。也可以选择多行,并且将添加该选择中的所有更改。
jox

请注意,这不是gitk,但Windows的Git Bash附带了它。您应该有一个开始菜单项,或者可以使用命令启动它git gui。还有stage this hunk一个可能比有用stage this line。自从10年前创建此答案以来,它可能是新的。
克里斯,

82

我认为这git add -e myfile是最简单的方法(至少是我的喜好),因为它只是打开了一个文本编辑器,让您选择要暂存的行和不需要的行。关于编辑命令:

添加的内容:

添加的内容以“ +”开头的行表示。您可以通过删除它们来防止暂存任何附加行。

删除的内容:

删除的内容以“-”开头的行表示。您可以通过将“-”转换为“”(空格)来防止分段删除它们。

修改内容:

修改后的内容由“-”行(删除旧内容)和“ +”行(添加替换内容)表示。您可以通过将“-”行转换为“”并删除“ +”行来防止进行修改。请注意,仅修改一对中的一半可能会给索引带来混乱的变化。

有关的所有详细信息git add,请参见git --help add


7
如果在某处对如何实际选择这些行(即要输入的实际命令)有明确的解释,这将更有用。我在文档中找不到一个。您可以添加参考吗?
亚历克斯

4
对于那些不喜欢速记选项的人,-e--edit
Kolyunya '16

2
@Alex TheFreedomBanana添加的参考引号来自git --help add
Randall

8
这是唯一的答案(仅需要git),解决了s在交互式补丁程序模式下无法使小块变小时明智地添加/删除行的问题。
cdosborn

3
了解此命令(git add -e)*不会*更改磁盘上的文件内容可能会有所帮助。它只是将变更的一部分从非暂存转移到暂存(索引)。
Penghe Geng

44

如果您使用的是vim,则可以尝试使用名为fugitive的出色插件。

您可以使用来查看文件在工作副本和索引之间的差异:Gdiff,然后使用经典的vim diff命令(例如)在索引中添加行或块dp。将修改保存在索引中,然后使用提交:Gcommit,就可以了。

此处有非常好的入门级截屏视频(请参见第2部分)。


非常感谢您提供此链接。完全一样。特别是:diffget/:diffput在可视模式下,可以选择要重置/提交的特定行。因此,请再次确认:vim很棒。
goodniceweb

30

我强烈建议使用Atlassian的SourceTree。(它是免费的。)这使它变得微不足道。您可以快速,轻松地暂存单个代码块或单个代码行。

在此处输入图片说明


1
我同意SourceTree是用于此目的的好工具,因为与通过命令行提供的功能相比,它给您提供了更细粒度的控制。

18
@cupcake我反过来说,看到SourceTree可能使用了这些命令行git可执行文件,从本质上讲,始终可以通过“命令行”执行相同(或更多个)细粒度的操作。
tutuDajuju 2015年

2
不管细粒度的论点,我都强烈建议SourceTree来进行大块划分和单独的行很容易:i.imgur.com/85bNu4C.png
Mars Robertson

1
@tutuDajuju在这种情况下,我不确定那是真的。SourceTree有选择什么样的部分,以舞台的能力,一行行。您不必上演整场大礼;您可以在大块中间上演2行。不过,我不知道它是如何实现的。(目前,我正在尝试解决SourceTree无法为未跟踪的文件暂存特定行的问题。我在这里着手寻找解决方法,只是发现git似乎似乎没有提供逐行功能-至少不是简单的方式。)
jpmc26,2015年

1
@Sun,您可以单击第50行,并按住Shift键并单击第100行,然后进行登台。您可以在Sourcetree中轻松上线50-100行:)
ryan123 '18

26

值得注意的是,要git add --patch用于新文件,您需要首先使用以下命令将文件添加到索引中git add --intent-to-add

git add -N file
git add -p file

23

当我进行了很多更改时,最终将根据更改创建一些提交,那么我想在暂存之前临时保存起点。

像这样:

$ git stash -u
Saved working directory and index state WIP on master: 47a1413 ...
$ git checkout -p stash
... step through patch hunks
$ git commit -m "message for 1st commit"
$ git checkout -p stash
... step through patch hunks
$ git commit -m "message for 2nd commit"
$ git stash pop

Whymarrh的答案是我通常要做的,除了有时会有很多变化之外,我可以告诉我在上演事情时可能会犯错,而且我希望我可以回到第二阶段。


12

如果您使用emacs,请看一下 Magit,它为emacs提供了git接口。它很好地支持暂存块(文件的一部分)。


当我从Mx Shell窗口运行git命令时,经常会想打开一个编辑器。magit是否会拦截这种疯狂行为,并为此打开一个新的缓冲区?(请不要提供background-emacs-daemon提示;无论如何都要感谢,但生活太短了)。
user2066657

不,据我所知它不会截获此消息。但是,不要只听我的话,因为(1)我几乎从未使用过Emacs中的shell窗口,(2)我通常使用emacsclient。话虽如此,如果emacsclient 您的选择,则至少可以防止打开带有emacs的附加窗口,并在现有的Emacs窗口中打开“ COMMIT_EDITMSG”缓冲区。
Mark van Lent


9

对于那些使用Git Extensions的人

在“提交”窗口中,选择要部分提交的文件,然后在右窗格中选择要提交的文本,然后右键单击所选内容,然后从上下文菜单中选择“阶段选定的行”。


2
Git Extensions中“选定行的阶段”中的键盘快捷键s非常有用-对于快速暂存部分文件进行提交非常有用。
Alchemistmatt

8

就像jdsumsion的答案一样,您也可以隐藏当前的工作,但是然后使用diff工具(例如,meld)从存储中提取选定的更改。这样,您甚至可以非常轻松地手动编辑帅哥,当您使用时git add -p

$ git stash -u
$ git difftool -d -t meld stash
$ git commit -a -m "some message"
$ git stash pop

使用stash方法使您有机会在提交代码之前测试代码是否仍然有效。


这很好用,但是如果您使用git commit --amend,则似乎以后无法弹出存储,还是有办法做到这一点?
2014年

7

在上一个答案的基础上,如果您更喜欢使用命令行,请输入git add -e myfile来逐行选择要提交的内容,因为此命令将打开具有差异的编辑器,如下所示:

在此处输入图片说明

您可能知道以开头的行+是加法,以开头的行-是删除。所以:

  • 要不进行添加,只需删除该行。
  • 要不进行删除,只需将其替换-为space即可

这就是git add -h有关以这种方式添加文件(修补文件)的说明:

添加的内容 添加的内容由以“ +”开头的行表示。您可以通过删除它们来防止暂存任何附加行。

删除的内容: 删除的内容由以“-”开头的行表示。您可以通过将“-”转换为“”(空格)来防止分段删除它们。

修改后的内容: 修改后的内容由“-”行(删除旧内容)和“ +”行(添加替换内容)表示。您可以通过将“-”行转换为“”并删除“ +”行来防止进行修改。请注意,仅修改一对中的一半可能会给索引带来混乱的变化。

注意:请勿更改文件的内容,这不是一个好地方。只需更改已删除或已添加行的运算符。


先前的答案是什么?根据答案的分数来存储答案。因此,与其他答案相比,您的答案现在处于与编写时不同的位置。
KulaGGin

我相信引用的答案来自@theFreedomBanana
K. Symbol

6

vim-gitgutter插件可以在不离开vim编辑器的情况下进行大礼

:GitGutterStageHunk

除此之外,它还提供了其他一些很酷的功能,例如某些现代IDE中的差异符号列

如果只有部分大块应该上演逃亡者

:Gdiff

允许选择可视范围,然后选择:'<,'>diffput:'<,'>diffget登台/还原单个行的更改。



4

使用TortoiseGit:

右键单击该文件并使用Context Menu → Restore after commit。这将按原样创建文件的副本。然后,您可以编辑文件,例如在TortoiseGitMerge中,并撤消所有您不想提交的更改。保存这些更改后,您可以提交文件。


4

提出这个问题已有10年了。我希望这个答案对某人有用。正如答复中提到这里,这里GUI是不是一种选择,安德鲁Shadura的crecord扩展有助于带来ncurses的窗口中,我们可以选择行提交。

如下设置扩展名:

git clone https://github.com/andrewshadura/git-crecord
cd git-crecord
./setup.py install
ln -s $PWD/git-crecord ~/.local/bin/git-crecord

cd到您的git repo并按以下方式调用它:

git crecord

这将打开ncurses接口,该接口可以如下所示使用。在ncurses窗口中按以下键将执行某些操作:

f       hunk toggle fold (arrow keys can also be used)
space   toggle hunk selection
a       toggle commit or amend
c       confirm and open commit window

截屏视频显示了示例用法例




2

git-meld- index-从网站引用:

git-meld-index运行meld或任何其他git difftool(kdiff3,diffuse等),以允许您交互式地将更改暂存到git索引(也称为git暂存区)。

这类似于git add -p和git add --interactive的功能。在某些情况下,比git add -p更容易/更快地使用meld。这是因为,例如,meld允许您:

  • 查看更多内容
  • 查看行内差异
  • 手动编辑并查看“实时”差异更新(每次按键后更新)
  • 导航到更改,而无需对要跳过的每个更改说“ n”

用法

在git仓库中,运行:

git meld-index

您会看到融合(或您配置的git difftool)弹出:

:从工作树复制的临时目录继续文件

RIGHT:带有索引内容的临时目录。这还包括尚未在索引中但在工作副本中已修改或未跟踪的文件-在这种情况下,您将看到HEAD中的文件内容。

编辑索引(右侧),直到满意为止。请记住在需要时保存。

完成后,关闭meld,并且git-meld-index将更新索引以匹配刚编辑的meld右侧临时目录的内容。


2

如果是上Windows平台,在我看来git gui是非常好的工具stage/ commit从几行unstaged文件

1.大块头:

  • unstagged Changes部分中选择文件
  • 右键单击需要暂存的代码块
  • 选择 Stage Hunk for commit

2.行明智的:

  • unstagged Changes部分中选择文件
  • 选择要暂存的行
  • 右键单击并选择 Stage Lines for commit

3.如果要暂存完整文件,请注意以下几行:

  • unstagged Changes部分中选择文件
  • Ctrl+T (Stage file to commit)
  • 所选文件现在移到“ Staged Changes部分”
  • 选择要分段的线
  • 右键单击并选择 UnStage Lines for commit

1

如上面的答案所示,您可以使用 git add --patch filename.txt

或简称 git add -p filename.txt

...但是对于存储库中已经存在的文件,in最好直接在commit命令上使用--patch标志(如果使用的是最新版本的git): git commit --patch filename.txt

...或者还是简短形式 git commit -p filename.txt

...然后使用上述键(y / n等)来选择要包含在提交中的行。


git add -p filename.txt除了减少错误的余地,这还给您带来了什么?如果您弄乱了部分文件的更改,则撤消添加要比撤消提交更好。
CTMacUser 2014年

我不知道为什么,但是当我说'n'时,该行被包括在内....当我在第二个大块头中说'y'时,该行也被包括在内。
chovy

0

git-cola是一个很棒的GUI,并且还内置了此功能。只需选择要登台的线,然后按S。如果未选择,则上演完整的大块。

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.