Git diff-仅名称并复制该列表


151

我只想获取两个修订版本之间已更改文件的列表,这很简单:

git diff -–name-only commit1 commit2 > /path/to/my/file

但是,如果我想将所有列出的文件复制到另一个地方,该怎么写?对于复制的文件,我需要完全相同的目录结构。

例如,我已经修改并添加了文件:

/protected/texts/file1.txt
/protected/scripts/index.php
/public/pics/pic1.png

我想要/home/changes/所有已更改和添加的文件:

/home/changes/protected/texts/file1.txt
/home/changes/protected/scripts/index.php
/home/changes/public/pics/pic1.png

1
我不太了解您要实现的目标...将更改传播到不同的克隆?创建补丁?在git仓库之外修补文件?
knittl 2011年

不是补丁,而是更改文件的确切副本结构。像补丁一样,但带有可靠的文件
BazZy 2011年

是的,在git仓库外部修补文件-对我来说是最接近的目标:)
BazZy 2011年

3
抱歉。什么?您要捕获并重放对文件的更改以及对树的更改?那是一个补丁。git format-patch可以针对提交范围执行此操作。
knittl 2011年

1
git diff commit1 commit2 > my.patch然后cd other/path; patch -p1 < my.patch。为什么必须使用文件的完整副本?如果是因为您认为该补丁程序可能不适用,因此另一个目录不是真正处于该commit1状态,那么您真的应该从该状态复制所有内容commit2 ……
Cascabel 2011年

Answers:


118

请尝试以下已测试过的命令:

$ cp -pv --parents $(git diff --name-only) DESTINATION-DIRECTORY

2
感谢您的cp --parents提示,我多年来一直希望使用该选项,但从未知道它的存在!..很显然,我从来没有想过要找它==
Stephan Henningsen

2
请注意,这在Mac上不起作用,因为--parents选项cp不可用。
M. Justin

如果文件有异常字符,使用此技巧有什么提示吗?空格,北欧字符。
Halvor Holsten Strand '11

@HalvorStrand,我尚未测试过,但是IFS=$'\n'先设置可能会完成。(最好放在子外壳中,以免弄乱您原来的IFS值。)
通配符

cp: cannot stat 'git diff --name-only': No such file or directory在Windows上的git bash上遇到错误。我究竟做错了什么?存在目标目录
Shiva,

14

以下应该可以正常工作:

git diff -z --name-only commit1 commit2 | xargs -0 -IREPLACE rsync -aR REPLACE /home/changes/protected/

进一步说明:

  • -zgit diff --name-only同NUL分隔的文件的方式输出列表字节而不是换行,以防万一您的文件名中都有特殊字符。

  • -0xargs说,解释标准作为输入参数的NUL分隔的列表。

  • -IREPLACE需要,因为默认xargs将参数追加到的结束rsync命令。相反,这表示将它们放在后面的REPLACE位置。(这是该服务器故障答案的一个很好的技巧。)

  • -a对参数rsync的手段维护权限,所有权等如果可能的话。的-R手段来创建在目标文件时使用完整的相对路径。

更新:如果您使用的是旧版本xargs,则需要使用-i选项代替-I。(在的更高版本中不推荐使用前者findutils。)


这很奇怪-您使用的是什么操作系统?如果是Linux发行版,那是什么,怎么xargs --version说呢?
Mark Longair 2011年

1
啊,在那个版本的xargs中,您需要使用-i它,而在更高版本中不推荐使用-4.1现在已经很旧了。我将更新我的答案。
Mark Longair 2011年

@Mark:我记得-I在某些版本中读过某个地方后需要一个空格,所以也许可以试试看-I REPLACE
Mikel

没关系。那也不行。 -Ifindutils2004
Mikel

您应该添加--diff-filter=d以从列表中排除已删除的文件。否则,在尝试将它们复制到changes文件夹时会出现错误。否则,很好的答案。谢谢!
taymless

11

这里是单线:

列出更改的文件并将其打包为* .zip:

git diff --name-only | zip patched.zip -@

列出最后提交的更改文件,并将其打包为* .zip:

git diff --name-only HEAD~ HEAD | zip patched.zip -@

如果您使用的是Windows,则可以从sourceforge.net/projects/gnuwin32/files/zip
Radon8472,18年

@ Radon8472安装sed.exe吗?我仍然zip在Windows上找不到。
希瓦

不,该链接指向zip.exe的下载而不是sed的下载。如果不能在命令行中使用zip,则应将zip.exe的安装文件夹添加到PATHenv变量中。
Radon8472

6
zip update.zip $(git diff --name-only commit commit)


2

它完美地工作。

git diff 1526043 82a4f7d --name-only | xargs zip update.zip

git diff 1526043 82a4f7d --name-only |xargs -n 10 zip update.zip

1

没有人提到cpio易于输入,创建硬链接并处理文件名中的空格的方法:

git diff --name-only $from..$to  | cpio -pld outdir
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.