我想在特定提交中获取已修改和添加的文件的列表,以便我可以导出它们并生成具有文件结构的包。
想法是获取包并将其解压缩到服务器上。由于许多原因,我无法创建一个钩子来自动拉动repo,并且我必须保持服务器更新的最简单方法是生成此包。
答案 0 :(得分:89)
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 -
答案 1 :(得分:66)
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $commit_id | xargs tar -rf mytarfile.tar
为了解决这个问题,这里是用tar命令的命令。这会将文件导出到tar存档中。
答案 2 :(得分:38)
这是一个适用于Windows 7的单行命令。从存储库的顶级文件夹中运行它。
for / f“usebackq tokens = *”%A in(`git diff-tree -r --no-commit-id --name-only --diff-filter = ACMRT HEAD~1 HEAD`)做回声FA | xcopy“%~fA”“C:\ git_changed_files \%A”
答案 3 :(得分:28)
如果您的提交哈希是例如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/
答案 4 :(得分:18)
您可以使用Tortoise Git将差异导出到MS Windows:
我右键单击并选择 TortoiseGit > 显示日志和日志消息将打开。
选择两个修订并进行比较。 之间的差异将会打开。
选择文件并将选择导出到... 到文件夹!
答案 5 :(得分:7)
我需要更新我的测试服务器并添加自2.1版以来更改过的文件 对我来说,像James Ehly发布的那样处理类似的解决方案,但在我的情况下,我想导出两个旧标签之间差异的存档包 - tag_ver_2.1和tag_ver_2.2不是唯一一个提交。
例如:
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
答案 6 :(得分:2)
我已经制作了一个PHP脚本来导出Windows上已更改的文件。如果你有一个设置了php的localhost开发服务器,那么你可以轻松运行它。它将记住您的上一个存储库并始终导出到同一文件夹。导出前始终清空导出文件夹。您还将看到已删除的文件为红色,以便您知道要在服务器上删除的内容。
这些只是两个文件,所以我会在这里发布。假设您的存储库位于c:/ www下的自己的文件夹中,http://localhost也指向c:/ www并且启用了php。我们将这两个文件放在c:/ www / git-export -
中index.php:
<?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的安装程序进行配置
答案 7 :(得分:1)
导出以日期开头的修改过的文件:
diff --stat @{2016-11-01} --diff-filter=ACRMRT --name-only | xargs tar -cf 11.tar
快捷方式(使用别名)
git exportmdf 2016-11-01 11.tar
.gitconfig中的别名
[alias]
exportmdf = "!f() { \
git diff --stat @{$1} --diff-filter=ACRMRT --name-only | xargs tar -cf $2; \
}; f"
答案 8 :(得分:0)
这是我编写的一个小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
创建一个名为&#39;〜/ Scripts / copy-commit.sh&#39;的文件。然后赋予它执行权限:
chmod a+x ~/Scripts/copy-commit.sh
然后,从git存储库的根目录:
~/Scripts/copy-commit.sh COMMIT_KEY ~/Existing/Destination/Folder/
答案 9 :(得分:0)
以下命令对我有用。
如果您希望上次提交更改的文件有所不同:
git archive -o update.zip HEAD $(git diff --name-only HEAD^)
或者如果您想在两个特定的提交之间有所区别:
git archive -o update.zip 4d50f1ee78bf3ab4dd8e66a1e230a64b62c49d42 $(git diff --name-only 07a698fa9e5af8d730a8c33e5b5e8eada5e0f400)
或者如果您有未提交的文件,请记住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^)
答案 10 :(得分:0)
我以前也遇到过类似的问题。 我写了一个简单的Shell脚本。
$git log --reverse commit_HashX^..commit_HashY --pretty=format:'%h'
上面的命令将以相反的顺序显示从commit_HashX到commit_HashY的Commit Hash(修订)。
456d517 (second_hash)
9362d03
5362d03
226x47a
478bf6b (six_hash)
现在使用上面的命令来显示主要的Shell脚本。
commitHashList=$(git log --reverse $1^..$2 --pretty=format:'%h')
for hash in $commitHashList
do
echo "$hash"
git archive -o \Path_Where_you_want_store\ChangesMade.zip $hash
done
将此代码添加到export_changes.sh。现在,将文件和提交哈希值传递给脚本。
请确保初始的commit_hash必须是第一个参数,然后是您要导出更改的最后一个commit_hash。
示例:
$ sh export_changes.sh hashX hashY
将此脚本放入git本地目录或在脚本中设置git本地目录路径。 希望有帮助。.
答案 11 :(得分:0)
这对Unix和Windows都适用:
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT __1__.. | xargs cp --parents -t __2__
命令中有两个占位符。您需要根据需要更换它们:
__ 1 __ :在要导出的所有提交之前用 commit id 替换(例如997cc7b6-不要忘记保留该双点提交ID后-这表示“涉及比此提交更新的所有提交”)
__ 2 __ :替换为您要导出文件的现有路径(例如../ export_path /)
结果是,您会将文件保存在文件夹结构中(没有zip / tars ...),因为有人可能习惯于在svn存储库中使用 stov svn导出。
例如,当您要手动部署很少提交的添加/修改的文件时,这非常有用。这样,您就可以通过ftp客户端复制这些文件了。
答案 12 :(得分:0)