我希望能够获取特定提交中的修改和添加文件清单,以便我可以导出它们并生成带有文件结构的软件包。
其想法是获取软件包并在服务器上进行解压缩。由于多种原因,我无法创建钩子来自动拉取仓库,而我保持服务器更新的最简单方法是生成此软件包。
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $commit_id
git diff-tree -r $commit_id
:
对给定的提交与其父提交进行差异比较(包括所有子目录,而不仅仅是顶级目录)。
--no-commit-id --name-only
:
不输出提交的 SHA1。仅输出受影响文件的名称,而不是完整的差异。
--diff-filter=ACMRT
:
仅显示在此提交中添加、复制、修改、重命名或更改类型(例如,文件 → 符号链接)的文件。这排除了已删除的文件。
评论中的更新:
根据问题上下文和下面的评论,使用以下命令,您可以将 ACMRT
文件作为带有其文件夹结构的 .tar
文件获取。
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $commit_id | tar -czf file.tgz -T -
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $commit_id | xargs tar -rf mytarfile.tar
为了完整地说明,这里是管道连接到tar的命令。将文件导出为tar档案。
这是一条可在Windows 7上运行的单行命令,从您的存储库顶级文件夹运行它。
for /f "usebackq tokens=*" %A in (`git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT HEAD~1 HEAD`) do echo FA|xcopy "%~fA" "C:\git_changed_files\%A"
如果你的提交哈希值,例如是a9359f9,那么执行以下命令:
git archive -o patch.zip a9359f9 $(git diff --name-only a9359f9^..a9359f9)
将会提取在该次提交中修改的文件,并将它们放置在patch.zip中,同时保持项目目录结构的完整性。
这个命令看起来有点啰嗦,重复了三次提交哈希值,但对我来说似乎很有效。
来源:http://tosbourn.com/2011/05/git/using-git-to-create-an-archive-of-changed-files/
function
来将命令简化为只需要函数名称,并使用$args
来仅传递一次提交哈希。在*nix系统中,您可能可以使用shell脚本来实现相同的效果。 - ADTCgit archive -o patch.zip HEAD/**或提交**/ $(git diff --name-only commit1 commit2)
。传递给archive
命令的提交可以是任意的提交(最有可能是HEAD或后续提交),文件被拉取得像它们在该提交阶段已经检出一样。传递给diff
的commit1和commit2只用于生成要拉取的文件列表,它们不会影响所拉取的文件版本。 - ADTCdiff
命令:git archive -o patch.zip HEAD /**或提交**/ $(git diff --name-only commit1A commit1B; git diff --name-only commit2A commit2B; git diff --name-only commit3A commit3B)
。 - ADTCgit diff -z --name-only commit1 commit2 | xargs -0 git archive -o patch.zip HEAD
。该命令的作用是将两个提交之间的差异打包成一个zip文件。 - Boggin右键单击并选择TortoiseGit > 显示日志,然后日志消息将打开。
选择两个版本进行比较。会打开之间的差异。
选择文件并将所选内容导出到...文件夹中!
tag_ver_2.1 = 1f72b38ad
tag_ver_2.2 = c1a546782
这里是修改后的示例:git diff-tree -r --no-commit-id --name-only c1a546782 1f72b38ad | xargs tar -rf test.tar
git archive -o update.zip HEAD $(git diff --name-only HEAD HEAD^)
或者如果你想要比较两个特定提交之间的区别:
git archive -o update.zip sha1 $(git diff --name-only sha1 sha2)
如果您有未提交的文件,请记住git的方式是将所有内容都提交,分支是便宜的:
git stash
git checkout -b feature/new-feature
git stash apply
git add --all
git commit -m 'commit message here'
git archive -o update.zip HEAD $(git diff --name-only HEAD HEAD^)
<?php
/* create directory if doesn't exist */
function createDir($dirName, $perm = 0777) {
$dirs = explode('/', $dirName);
$dir='';
foreach ($dirs as $part) {
$dir.=$part.'/';
if (!is_dir($dir) && strlen($dir)>0) {
mkdir($dir, $perm);
}
}
}
/* deletes dir recursevely, be careful! */
function deleteDirRecursive($f) {
if (strpos($f, "c:/www/export" . "/") !== 0) {
exit("deleteDirRecursive() protection disabled deleting of tree: $f - please edit the path check in source php file!");
}
if (is_dir($f)) {
foreach(scandir($f) as $item) {
if ($item == '.' || $item == '..') {
continue;
}
deleteDirRecursive($f . "/" . $item);
}
rmdir($f);
} elseif (is_file($f)) {
unlink($f);
}
}
$lastRepoDirFile = "last_repo_dir.txt";
$repo = isset($_POST['repo']) ? $_POST['repo'] : null;
if (!$repo && is_file($lastRepoDirFile)) {
$repo = file_get_contents($lastRepoDirFile);
}
$range = isset($_POST['range']) ? $_POST['range'] : "HEAD~1 HEAD";
$ini = parse_ini_file("git-export.ini");
$exportDir = $ini['export_dir'];
?>
<html>
<head>
<title>Git export changed files</title>
</head>
<body>
<form action="." method="post">
repository: <?=$ini['base_repo_dir'] ?>/<input type="text" name="repo" value="<?=htmlspecialchars($repo) ?>" size="25"><br/><br/>
range: <input type="text" name="range" value="<?=htmlspecialchars($range) ?>" size="100"><br/><br/>
target: <strong><?=$exportDir ?></strong><br/><br/>
<input type="submit" value="EXPORT!">
</form>
<br/>
<?php
if (!empty($_POST)) {
/* ************************************************************** */
file_put_contents($lastRepoDirFile, $repo);
$repoDir = $ini['base_repo_dir'] ."/$repo";
$repoDir = rtrim($repoDir, '/\\');
echo "<hr/>source repository: <strong>$repoDir</strong><br/>";
echo "exporting to: <strong>$exportDir</strong><br/><br/>\n";
createDir($exportDir);
// empty export dir
foreach (scandir($exportDir) as $file) {
if ($file != '..' && $file != '.') {
deleteDirRecursive("$exportDir/$file");
}
}
// execute git diff
$cmd = "git --git-dir=$repoDir/.git diff $range --name-only";
exec("$cmd 2>&1", $output, $err);
if ($err) {
echo "Command error: <br/>";
echo implode("<br/>", array_map('htmlspecialchars', $output));
exit;
}
// $output contains a list of filenames with paths of changed files
foreach ($output as $file) {
$source = "$repoDir/$file";
if (is_file($source)) {
if (strpos($file, '/')) {
createDir("$exportDir/" .dirname($file));
}
copy($source, "$exportDir/$file");
echo "$file<br/>\n";
} else {
// deleted file
echo "<span style='color: red'>$file</span><br/>\n";
}
}
}
?>
</body>
</html>
git-export.ini :
; path to all your git repositories for convenience - less typing
base_repo_dir = c:/www
; if you change it you have to also change it in the php script
; in deleteDirRecursive() function - this is for security
export_dir = c:/www/export
现在在浏览器中加载 localhost/git-export/。该脚本已设置为始终将其导出到 c:/www/export - 更改所有路径以适应您的环境或修改脚本以满足您的需求。
如果您已将 Git 安装到 PATH 中,则可以运行此操作 - 这可以在运行 Windows Git 安装程序时进行配置。
我也遇到了同样的问题。@NicolasDermine的解决方案没有起作用,因为在比较的提交之间更改了太多文件。我收到一个错误,提示shell参数过长。
因此,我添加了一个Python实现。可以通过pip install gitzip
进行安装,然后执行以下命令:
python -m gitzip export.zip <commit id> <commit id>
export.zip
文件,其中包含保留目录结构的所有更改文件。也许有人也需要它,所以我想在这里分享一下。这是我编写的一个小型bash(Unix)脚本,可以按照文件夹结构复制给定提交哈希的文件:
ARRAY=($(git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $1))
PWD=$(pwd)
if [ -d "$2" ]; then
for i in "${ARRAY[@]}"
do
:
cp --parents "$PWD/$i" $2
done
else
echo "Chosen destination folder does not exist."
fi
chmod a+x ~/Scripts/copy-commit.sh
~/Scripts/copy-commit.sh COMMIT_KEY ~/Existing/Destination/Folder/
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $commit_id | tar -czf file.tgz -T -
。 - Matthieu Sadouni--diff-filter=ACMRT
的文档在这里:https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---diff-filterACDMRTUXB82308203,所以你可以通过使用小写字母来排除修改和添加的文件(如问题标题所述):--diff-filter=am
。 - rklec