只提交Git中文件的一部分

Commit only part of a file in Git

当我在Git中对一个文件进行更改时,如何只提交其中的一些更改?

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


你可以使用git add --patch (或者简称-p),git会开始把你的文件分解成它认为合理的"大块"(文件的一部分)。然后,它将提示您以下问题:

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

以下是每个选项的说明:

  • Y为下一次提交准备这个模块
  • n不为下一次提交准备此块
  • Q退出;不要将此块或任何剩余块放入阶段
  • 将此块和文件中的所有后续块放入阶段
  • D不准备此块或文件中的任何后期块
  • g选择要转到的块
  • /搜索与给定regex匹配的块
  • JABBD离开这个混蛋还没决定,看下一个未定混蛋
  • JABBD离开这个混蛋还没决定,看下一个混蛋
  • KBBD离开这个混蛋还没决定,见上一个未定混蛋
  • KBBD离开这个混蛋还没决定,见前一个混蛋
  • s将当前的大块拆分为较小的大块
  • e手动编辑当前hunk
  • 打印Hunk帮助

如果文件还不在存储库中,您可以先执行git add -N 。然后你可以继续使用git add -p

之后,您可以使用:

  • git diff --staged检查是否进行了正确的更改。
  • git reset -p到unstage错误地添加了大块
  • git commit -v在编辑提交消息时查看提交。

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

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


您可以使用git add --interactivegit add -p ,然后使用git commit(而不是git commit -a);请参见git add手册页中的交互模式,或者只需按照说明操作即可。

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

如果您喜欢从GUI执行,可以使用Git GUI。您可以简单地标记要包含在提交中的块。我个人认为它比使用git add -i更容易。其他git gui,如qgit或gitx,也可能具有此功能。


GitGUI在diff视图下提供此功能。只需右键单击您感兴趣的行,您就会看到一个"准备这行提交"菜单项。


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

新增内容:

Added content is represented by lines beginning with"+". You can prevent staging any addition lines by deleting them.

删除的内容:

Removed content is represented by lines beginning with"-". You can prevent staging their removal by converting the"-" to a"" (space).

修改内容:

Modified content is represented by"-" lines (removing the old content) followed by"+" lines (adding the replacement content). You can prevent staging the modification by converting"-" lines to"", and removing"+"
lines. Beware that modifying only half of the pair is likely to introduce confusing changes to the index.

关于git add的每一个细节都可以在git --help add上找到。


如果您使用的是Vim,那么您可能需要尝试一个名为"逃犯"的优秀插件。

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

非常好的介绍性电影放映(特别是第2部分)。


我强烈推荐使用来自亚特兰蒂斯的sourcetree。(它是免费的。)它使这变得微不足道。您可以快速、轻松地准备单个代码块或单个代码行。

enter image description here


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

1
2
git add -N file
git add -p file

当我有很多更改,并且最终将从这些更改中创建一些提交时,那么我希望在分段之前暂时保存我的起点。

这样地:

1
2
3
4
5
6
7
8
9
$ 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

Whymarh的答案是我通常做的事情,除了有时会有很多变化,我可以告诉你我可能会在安排事情的时候犯错误,我希望有一个承诺的状态,我可以退回到第二关。


如果您使用emacs,请看一下magit,它为emacs提供了一个git接口。它非常支持分段大块(文件的一部分)。


就像jdsumsion的答案一样,您也可以存储当前的工作,但是可以使用像meld这样的不同工具从存储中提取所选的更改。这样,您甚至可以非常容易地手动编辑大块,这在git add -p中有点痛苦:

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

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


对于使用git扩展的用户:

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


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

enter image description here


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

1
:GitGutterStageHunk

除此之外,它还提供了其他很酷的特性,如一些现代IDE中的diff符号列。

如果只有一部分人是逃犯

1
:Gdiff

允许视觉范围选择,然后选择:'<,'>diffput:'<,'>diffget,以阶段/恢复单个行更改。


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


乌龟土:

right click on the file and use Context Menu → Restore after commit. This will create a copy of the file as it is. Then you can edit the file, e.g. in TortoiseGitMerge and undo all the changes you don't want to commit. After saving those changes you can commit the file.


对于Atom用户,包Github以git gui的风格包含交互式登台。有关快捷方式,请参阅包的文档。

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


Git Meld指数——网站引用:

git-meld index运行meld或任何其他git difftool(kdiff3、diffuse等),以允许您以交互方式将更改转移到git索引(也称为git临时区域)。

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

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

用法

在Git存储库中,运行:

1
git meld-index

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

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

右:包含索引内容的临时目录。这还包括索引中还没有的文件,但是在工作副本中被修改或取消了跟踪——在本例中,您将从头部看到文件内容。

编辑索引(右手边),直到满意为止。需要时记得保存。

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


对于emacs,还有gitsum


在前面的回答中添加,如果您更喜欢使用命令行,输入git add -e myfile可以选择逐行选择要提交的内容,因为此命令将打开一个具有不同之处的编辑器,如:

enter image description here

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

  • 如果不准备添加内容,只需删除该行即可。
  • 为了不进行删除,只需将-替换为空格

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

added content
Added content is represented by lines beginning with"+". You can
prevent staging any addition lines by deleting them.

removed content:
Removed content is represented by lines beginning with"-". You can
prevent staging their removal by converting the"-" to a""
(space).

modified content:
Modified content is represented by"-" lines (removing the old
content) followed by"+" lines (adding the replacement content).
You can prevent staging the modification by converting"-" lines to
"", and removing"+" lines. Beware that modifying only half of the
pair is likely to introduce confusing changes to the index.

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


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

或者简称
git add -p filename.txt

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

…或者,同样的,简短的形式
git commit -p filename.txt

…然后使用上述键(Y/N等)选择要包含在提交中的行。


问这个问题已经10年了。我希望这个答案对某些人有用。正如在这里的答案中提到的,在GUI不是一个选项的地方,Andrew Shadura的crecord扩展帮助带来一个ncurses窗口,我们可以在其中选择要提交的行。

按如下方式设置扩展:

1
2
3
4
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并调用它,如下所示:

1
git crecord

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

1
2
3
4
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

显示示例usageExample的屏幕放映


Git-Cola是一个很好的图形用户界面,并且内置了这个功能。只需选择要分级的行,然后按s。如果没有进行选择,则将执行完整的Hunk。


如果在Windows平台上,我认为git gui对于stagecommit文件来说是非常好的工具。

1。聪明的:

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

2。线型:

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

三。如果要暂存除两行以外的完整文件:

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