3215

当我在 Git 中对文件进行更改时,如何仅提交部分更改?

例如,我如何才能只提交文件中已更改的 30 行中的 15 行?

4

26 回答 26

4323

您可以使用git add --patch <filename>(或-p简称),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手动编辑当前大块
    • 然后,您可以通过将+/-替换为手动编辑大块#(感谢veksen
  • ?打印大块帮助

如果该文件尚未在存储库中,您可以先执行git add -N <filename>. 之后你可以继续git add -p <filename>

之后,您可以使用:

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

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

未来参考:Git Tools - Interactive Staging

于 2009-07-06T02:36:42.233 回答
274

您可以使用git add --interactiveor ,然后( not ); 请参阅git-add手册页中的交互模式,或简单地按照说明进行操作。git add -p <file>git commit git commit -a

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

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

于 2009-07-06T11:49:28.263 回答
169

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

于 2009-07-06T02:41:47.263 回答
104

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

添加内容:

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

删除的内容:

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

修改内容:

修改后的内容由“-”行(删除旧内容)后跟“+”行(添加替换内容)表示。您可以通过将“-”行转换为“”并删除“+”行来防止暂存修改。请注意,仅修改该对的一半可能会给索引带来令人困惑的更改。

每个细节git add都可以在git --help add

于 2015-09-25T20:45:27.977 回答
48

如果你使用 vim,你可能想试试名为fugitive的优秀插件。

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

非常好的介绍性截屏视频(见特别是2 部分)。

于 2012-02-23T10:37:39.340 回答
38

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

在此处输入图像描述

于 2014-08-12T13:32:06.937 回答
33

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

git add -N file
git add -p file
于 2014-12-05T17:29:10.147 回答
30

如果您使用的是 VS Code,那么您很幸运。选择要暂存的范围,然后用于Git: Stage Selected Ranges暂存它们,并根据需要提交。

我录制了一个 gif 来说明我的意思:

在此处输入图像描述

于 2021-01-10T02:59:36.247 回答
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 的回答是我通常会做的,除了有时会有很多变化,我可以告诉我在暂存事情时可能会犯错误,我想要一个承诺状态,我可以再次通过。

于 2013-06-06T22:14:36.497 回答
16

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

于 2009-07-08T07:00:31.223 回答
15

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

在此处输入图像描述

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

  • 要不进行添加,只需删除该行。
  • 要不进行删除,只需-用空格替换

这就是以git add -h这种方式添加文件的内容(修补文件):

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

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

修改内容: 修改内容由“-”行(删除旧内容)后跟“+”行(添加替换内容)表示。您可以通过将“-”行转换为“”并删除“+”行来防止暂存修改。请注意,仅修改该对的一半可能会给索引带来令人困惑的更改。

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

于 2018-08-24T15:24:08.123 回答
14

IntelliJ IDEA(我猜该系列的所有其他产品)自 v2018.1 以来就内置了对部分提交的支持。

在此处输入图像描述

于 2018-03-28T07:00:44.660 回答
12

对于那些使用Git 扩展的人:

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

于 2015-07-27T09:52:10.313 回答
8

就像 jdsumsion 的答案一样,您也可以存储您当前的工作,然后使用像 meld 这样的 difftool 从存储中提取选定的更改。这样,您甚至可以非常轻松地手动编辑帅哥,这在以下情况下有点痛苦git add -p

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

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

于 2013-08-07T13:25:35.187 回答
6

vim-gitgutter插件可以在不离开 vim 编辑器的情况下使用

:GitGutterStageHunk

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

如果只有部分大块头应该上演vim-fugitive

:Gdiff

然后允许视觉范围选择:'<,'>diffput:'<,'>diffget阶段/恢复个别行的变化。

于 2015-01-09T17:11:00.450 回答
6

问这个问题已经10年了。我希望这个答案对某人有用。正如这里的答案中提到的,在 GUI 不是一个选项的情况下,Andrew 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 存储库并按如下方式调用它:

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

显示示例用法的截屏视频例子

于 2019-03-24T19:55:44.207 回答
5

试过了git add -p filename.x,但在 Mac 上,我发现 gitx(http://gitx.frim.nl/https://github.com/pieter/gitx)更容易准确地提交我想要的行。

于 2011-08-15T23:43:36.853 回答
5

使用 TortoiseGit:

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

于 2015-04-06T16:16:02.967 回答
3

如果它在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
于 2015-05-28T12:52:34.403 回答
3

对于Atom用户,包github包括交互式 staging,样式为git gui. 有关快捷方式,请参阅包的文档

使用 Atom 允许使用具有深色背景的主题(默认情况下,git gui具有白色背景)。

于 2018-04-10T02:31:42.943 回答
2

对于 emacs,还有gitsum

于 2009-07-12T21:52:10.173 回答
2

我想将lazygit添加到工具列表中。这是一个很好的命令行 gui(即,即使不允许 X 转发,也可以通过 ssh 工作)。它具有广泛的功能(例如,选择要提交的行、交互式变基)、有用的着色,并且使用起来相对简单。可以以多种方式安装(go、conda、包管理器,...)。仍在积极开发/维护。

于 2021-10-27T15:51:58.913 回答
1

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

或缩写形式 git add -p filename.txt

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

...或者,再次,简短的形式 git commit -p filename.txt

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

于 2014-06-30T08:34:06.680 回答
1

git-meld-index - 引用网站:

git-meld-index 运行 meld——或任何其他 git difftool(kdiff3、diffuse 等)——以允许您以交互方式暂存对 git 索引(也称为 git 暂存区)的更改。

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

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

用法

在 git 存储库中,运行:

git meld-index

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

LEFT:临时目录,包含从工作树复制的文件

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

编辑索引(右侧)直到满意。需要时记得保存。

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

于 2015-07-04T20:26:43.953 回答
1

git-cola是一个很棒的 GUI,并且还内置了这个功能。只需选择要暂存的行并按S。如果未进行选择,则上演完整的大块。

于 2015-08-27T11:28:04.627 回答
1

您可以使用 Eclipse IDE,每个修改的本地文件都可以与暂存区域进行比较,在此并排差异视图中,您可以自由选择从本地复制哪个块到暂存区域,或者相反,回滚本地更改舞台区域。

但是还有更多 :),所有图形化 git 客户端也都进行大块暂存(git add -p),但我知道没有一个可以做到这一点:直接在暂存区域中编辑,因此可以在同一行或同一块上进行多次更改up(甚至写入/删除/更新本地不存在的东西),例如在补丁级别工作但没有破坏补丁内容的风险的“git add -e”。此外,由于它在 diff 视图中使用常规文本编辑器,因此您可以使用语法颜色来帮助您,并且您可以进行文本替换操作(更改所有缩进类型,重命名在许多地方使用的局部变量,...)以开始单独提交一些在提交“真实”更改之前重新格式化/重构,但不将所有文件更改嵌入到同一提交中。

当然 Eclipse 更面向 Java,但由于其强大的 git staging 编辑器,它也可以用于其他语言。有一个基于 Eclipse 的免费产品,只专注于 git 操作,称为 GitEye:https ://www.collab.net/downloads/giteye ,但似乎没有更好地使用基本的 Eclipse 发行版,例如:https ://www.eclipse.org /downloads/packages/release/2020-12/r/eclipse-ide-java-developers

编辑:由于 IntelliJ 2020.3 允许使用真正的 git 索引,它现在能够像 Eclipse 一样直接编辑暂存区域

于 2021-03-05T00:40:53.883 回答