Programing

Git에서 폴더 구조로 수정 및 추가 된 파일 만 내보내기

lottogame 2020. 10. 28. 07:34
반응형

Git에서 폴더 구조로 수정 및 추가 된 파일 만 내보내기


특정 커밋에서 수정 및 추가 된 파일 목록을 가져 와서 파일을 내보내고 파일 구조로 패키지를 생성하고 싶습니다.

아이디어는 패키지를 가져 와서 서버에서 추출하는 것입니다. 여러 가지 이유로 리포지토리를 자동으로 가져 오는 후크를 만들 수 없으며 서버를 업데이트하는 가장 쉬운 방법은이 패키지를 생성하는 것입니다.


git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $commit_id
  1. git diff-tree -r $commit_id:

    주어진 커밋의 차이를 부모 (들) (상위 디렉토리뿐만 아니라 모든 하위 디렉토리 포함)로 가져갑니다.

  2. --no-commit-id --name-only:

    커밋 SHA1을 출력하지 마십시오. 전체 diff 대신 영향을받는 파일의 이름 만 출력합니다.

  3. --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"

  • 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/


Tortoise Git사용하여 diff 를 MS Windows로 내보낼 수 있습니다 .

나는 오른쪽 버튼으로 클릭하고 TortoiseGit > 로그 표시를 하고 로그 메시지가 공개됩니다.

두 버전을 선택하고 비교하십시오. 차이 가 열립니다.

파일을 선택하고 선택 항목을 ... 폴더로 내보내기 !

여기에 이미지 설명 입력


테스트 서버를 업데이트하고 버전 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

Windows에서 변경된 파일을 내보내는 PHP 스크립트를 만들었습니다. 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로 내보내도록 설정되어 있습니다. 환경에 맞게 모든 경로를 변경하거나 필요에 맞게 스크립트를 수정하십시오.

This will work if you have Git installed so that the git command is in your PATH - this can be configured when you run the windows Git installer.


Below commands worked for me.

If you want difference of the files changed by the last commit:

git archive -o update.zip HEAD $(git diff --name-only HEAD HEAD^)

or if you want difference between two specific commits:

git archive -o update.zip sha1 $(git diff --name-only sha1 sha2)

or if you have uncommitted files, remember git way is to commit everything, branches are cheap:

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^)

To export modified files starting with a date:

  diff --stat @{2016-11-01} --diff-filter=ACRMRT --name-only | xargs tar -cf 11.tar

Shortcut (use alias)

  git exportmdf 2016-11-01 11.tar

Alias in .gitconfig

  [alias]
  exportmdf = "!f() { \
    git diff --stat @{$1} --diff-filter=ACRMRT --name-only | xargs tar -cf $2; \
  }; f"

Here is a small bash(Unix) script that I wrote that will copy files for a given commit hash with the folder structure:

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

Create a file named '~/Scripts/copy-commit.sh' then give it execution privileges:

chmod a+x ~/Scripts/copy-commit.sh

Then, from the root of the git repository:

~/Scripts/copy-commit.sh COMMIT_KEY ~/Existing/Destination/Folder/

I also faced a similar problem before. I wrote a simple Shell script.

$git log --reverse commit_HashX^..commit_HashY --pretty=format:'%h'

The above command will display Commit Hash(Revision) from commit_HashX to commit_HashY in reverse order.

 456d517 (second_hash)
 9362d03
 5362d03
 226x47a
 478bf6b (six_hash)

Now the main Shell Script using above command.

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

Add this code to export_changes.sh. Now pass file and commit hashes to the script.

Make sure that initial commit_hash must be the first argument then last commit_hash up to which you want to export changes.

Example:

$sh export_changes.sh hashX hashY

Put this script into git local directory or set git local directory path in the script. Hope it Helps..!


This works for me for both Unix and Windows:

git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT __1__.. | xargs cp --parents -t __2__

There are two placeholders in the command. You need to replace them for your purpose:

  • __1__: replace with commit id of commit right before all of the commits you want to export (e.g. 997cc7b6 - don't forget to keep that doubledot after commit id - this means "involve all commits newer than this commit")

  • __2__: replace with existing path where you want to export your files (e.g. ../export_path/)

As a result you will get your files in a folder structure (no zips/tars...) as someone might be used to using tortoise svn exports in svn repositories.

This is for example pretty useful when you want to perform manual deploy of added/modified files of few last commits. So you can then just copy these files through ftp client.

참고 URL : https://stackoverflow.com/questions/4541300/export-only-modified-and-added-files-with-folder-structure-in-git

반응형