Экспортируйте только измененные и добавленные файлы со структурой папок в Git
Я хотел бы получить список измененных и добавленных файлов в конкретном коммите, чтобы я мог экспортировать их и сгенерировать пакет с файловой структурой.
Идея состоит в том, чтобы получить пакет и извлечь его на сервере. По многим причинам я не могу создать ловушку для автоматического извлечения репозитория, и самый простой способ поддерживать сервер в актуальном состоянии - генерировать этот пакет.
14 ответов
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $commit_id
git diff-tree -r $commit_id
:Возьмите diff данного коммита с его родителем (ями) (включая все подкаталоги, а не только верхний каталог).
--no-commit-id --name-only
:Не выводить коммит SHA1. Выведите только имена затронутых файлов вместо полной разницы.
--diff-filter=ACMRT
:Показывать только файлы, добавленные, скопированные, измененные, переименованные или имеющие измененный тип (например, file → symlink) в этом коммите. Это оставляет удаленные файлы.
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 - только для имени --diff-filter = ACMRT HEAD~1 HEAD`) do echo FA | xcopy "% ~ fA" "C: \ git_changed_files \% A"
- echo FA отвечает на неизбежный вопрос xcopy о том, копируете ли вы файл или каталог (файл), и возможный вопрос о перезаписи файла (перезаписать все)
- usebackq позволяет нам использовать выходные данные нашей команды git в качестве входных данных для нашего предложения do
- HEAD~1 HEAD получает все различия между предыдущим коммитом и текущим HEAD
- % ~ fA преобразует вывод git в полностью определенные пути (требуется для изменения прямой косой черты на обратную косую черту)
- C: \ git_changed_files \, где вы найдете все файлы, которые отличаются
Если ваш хеш коммита, например, 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/
Вы можете экспортировать diff с помощью Tortoise Git в MS Windows:
Я щелкаю правой кнопкой мыши и выбираю TortoiseGit > Показать журнал, и сообщения журнала будут открыты.
Выберите две ревизии и сравните их. Разница между ними будет открытой.
Выберите файлы и экспортируйте выбор в... в папку!
Мне нужно было обновить мой тестовый сервер и добавить файлы, которые изменились с версии 2.1.
Для меня сработало аналогичное решение, которое написал Джеймс Эли, но в моем случае я хотел экспортировать в архив пакет различий между двумя старыми тегами - 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
Ниже команды работали для меня.
Если вы хотите, чтобы разница файлов изменялась при последнем коммите:
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^)
У меня тоже была такая же проблема. Решение @NicolasDermine не сработало, поскольку между сравниваемыми коммитами изменилось слишком много файлов. Я получил ошибку, что аргументы оболочки слишком длинные.
Как следствие, я добавил реализацию на Python. Это можно установить через а затем выполнен с
python -m gitzip export.zip <commit id> <commit id>
в корне репозиториев, создавая
export.zip
файл, содержащий все измененные файлы, сохраняющие структуру каталогов.
Может кому-то это тоже нужно, поэтому решил поделиться здесь.
Отказ от ответственности: я являюсь автором модуля
pip install gitzip
gitzip .
Я сделал PHP-скрипт для экспорта измененных файлов в Windows. Если у вас есть сервер разработки localhost с настроенным php, вы можете легко его запустить. Он будет помнить ваш последний репозиторий и экспортировать всегда в одну и ту же папку. Папка экспорта всегда очищается перед экспортом. Вы также увидите удаленные файлы красным, чтобы вы знали, что удалять на сервере.
Это всего лишь два файла, поэтому я опубликую их здесь. Предположим, что ваши репозитории находятся в папке c: / www в их собственных папках и что http://localhost/ также указывает на c: / www и поддерживает php. Давайте поместим эти 2 файла в 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, так что команда git находится в вашем PATH - это можно настроить при запуске установщика Git в Windows.
Вот небольшой сценарий 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
Создайте файл с именем ~/Scripts/copy-commit.sh и предоставьте ему права на выполнение:
chmod a+x ~/Scripts/copy-commit.sh
Затем из корня репозитория git:
~/Scripts/copy-commit.sh COMMIT_KEY ~/Existing/Destination/Folder/
Чтобы экспортировать измененные файлы, начиная с даты:
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"
git-архив -o package.zip HEAD $(git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT <comit_id>)
Я также сталкивался с подобной проблемой раньше. Я написал простой сценарий Shell.
$git log --reverse commit_HashX^..commit_HashY --pretty=format:'%h'
Приведенная выше команда отобразит Commit Hash(Revision) от commit_HashX до commit_HashY в обратном порядке.
456d517 (second_hash)
9362d03
5362d03
226x47a
478bf6b (six_hash)
Теперь основной Shell Script использует вышеуказанную команду.
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 в скрипте.Надеюсь, поможет..!
Это работает для меня как для Unix, так и для Windows:
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT __1__.. | xargs cp --parents -t __2__
В команде есть два заполнителя. Вам необходимо заменить их для вашей цели:
__1__: замените идентификатором коммита коммита прямо перед всеми коммитами, которые вы хотите экспортировать (например, 997cc7b6 - не забудьте сохранить это двойное число после идентификатора коммита - это означает "задействовать все коммиты новее, чем этот коммит")
__2__: заменить существующим путем, куда вы хотите экспортировать ваши файлы (например../export_path/)
В результате вы получите ваши файлы в структуре папок (без zips/tars...), так как кто-то может привыкнуть к использованию экспорта черепахи svn в репозитории svn.
Это, например, очень полезно, когда вы хотите выполнить ручное развертывание добавленных / измененных файлов нескольких последних коммитов. Таким образом, вы можете просто скопировать эти файлы через FTP-клиент.