开发者

Export only modified and added files with folder structure in Git

开发者 https://www.devze.com 2023-02-01 22:13 出处:网络
I would like to get a list of modified and added files in an specific commit开发者_StackOverflow so that I can export them and generate a package with the file structure.

I would like to get a list of modified and added files in an specific commit开发者_StackOverflow so that I can export them and generate a package with the file structure.

The idea is to get the package and extract it on the server. For many reasons I can't create a hook to pull the repo automatically and the easiest way I have to keep the server updated is generating this package.


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

    Take a diff of the given commit to its parent(s) (including all subdirectories, not just the top directory).

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

    Do not output the commit SHA1. Output only the names of the affected files instead of a full diff.

  3. --diff-filter=ACMRT:

    Only show files added, copied, modified, renamed or that had their type changed (eg. file → symlink) in this commit. This leaves out deleted files.


UPDATE FROM THE COMMENT:
Base on the question context and the comments below, with the following command, you can get the ACMRT files as a .tar file with their folder structure.

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

Just to round this out, here is the command piped to tar. This exports the files into a tar archive.


Here is a one-line command that works on Windows 7. Run it from your repository's top-level folder.

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 answers the inevitable xcopy question about whether you're copying a file or a directory (file), and the possible question about overwriting a file (overwrite All)
  • usebackq allows us to use the output from our git command as the input to our do clause
  • HEAD~1 HEAD gets all differences between the previous commit and the current HEAD
  • %~fA transforms the git output into fully qualified paths (needed to change forward slashes to backslashes)
  • C:\git_changed_files\ is where you will find all the files that are different


if your commit hash is for example a9359f9, this command :

git archive -o patch.zip a9359f9 $(git diff --name-only a9359f9^..a9359f9)

will extract the files modified in the commit and place them in patch.zip while keeping the project directory structure intact.

a bit verbose, the commit hash is mentioned three times, but it seems to work for me.

got it here : http://tosbourn.com/2011/05/git/using-git-to-create-an-archive-of-changed-files/


You can export diff using Tortoise Git to MS Windows:

I right click and select TortoiseGit > Show Log and Log Messages will be open.

Select two revisions and compare it. Difference between will be open.

Select the files and Export selection to ... to a folder!

Export only modified and added files with folder structure in Git


I needed to update my test server and add files that changed since version 2.1.
For me worked similar solution as James Ehly posted, but in my case i wanted to export to archive package of difference between two older tags - tag_ver_2.1 and tag_ver_2.2 not the only one commit.

For example:

tag_ver_2.1 = 1f72b38ad
tag_ver_2.2 = c1a546782

Here is modified example:

git diff-tree -r --no-commit-id --name-only c1a546782 1f72b38ad | xargs tar -rf test.tar


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


I have made a php script to export changed files on Windows. If you have a localhost development server with php set up then you can run it easily. It will remember your last repository and export always to the same folder. The export folder is always emptied before exporting. You will also see deleted files in red so you know what to delete on the server.

These are just two files so I will post them here. Let's assume your repositories are located under c:/www in their own folders and that http://localhost also points to c:/www and is php-enabled. Let's put these 2 files in 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

And now load localhost/git-export/ in a browser. The script is set up to export always to c:/www/export - change all paths to suit your environment or modify the script to suit your needs.

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.


I also had the same problem. The solution of @NicolasDermine didn't work since too many files have changed between the compared commits. I got an error that the shell arguments are too long.

As a consequence I added a python implementation. This can be installed via pip install gitzip and then executed with

python -m gitzip export.zip <commit id> <commit id>

in the repositories root creating an export.zip file containing all changed files retaining the directory structure.

Maybe someone needs it too so I thought to share it here.

Disclaimer: I am the author of the gitzip module.


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.


git archive -o package.zip HEAD $(git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT <comit_id>)

0

精彩评论

暂无评论...
验证码 换一张
取 消