web-dev-qa-db-fra.com

Exporter uniquement les fichiers modifiés et ajoutés avec une structure de dossiers dans Git

Je souhaite obtenir une liste des fichiers modifiés et ajoutés dans un commit spécifique afin de pouvoir les exporter et générer un package avec la structure de fichiers.

L'idée est d'obtenir le package et de l'extraire sur le serveur. Pour de nombreuses raisons, je ne peux pas créer de hook pour tirer automatiquement le dépôt et la façon la plus simple de garder le serveur à jour est de générer ce package.

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

    Prenez un diff du commit donné à ses parents (y compris tous les sous-répertoires, pas seulement le répertoire supérieur).

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

    Ne sortez pas le SHA1 de validation. N'afficher que les noms des fichiers concernés au lieu d'un diff complet.

  3. --diff-filter=ACMRT:

    Afficher uniquement les fichiers ajoutés, copiés, modifiés, renommés ou dont le type a été modifié (par exemple, fichier → lien symbolique) dans ce commit. Cela laisse de côté les fichiers supprimés.


MISE À JOUR DU COMMENTAIRE:
Sur la base du contexte de la question et des commentaires ci-dessous, avec la commande suivante, vous pouvez obtenir les fichiers ACMRT en tant que .tar fichier avec leur structure de dossiers.

git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $commit_id | tar -czf file.tgz -T -
94
Aristotle Pagaltzis
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $commit_id | xargs tar -rf mytarfile.tar

Juste pour compléter ceci, voici la commande canalisée vers tar. Cela exporte les fichiers dans une archive tar.

66
James Ehly

Voici une commande sur une seule ligne qui fonctionne sous Windows 7. Exécutez-la à partir du dossier de niveau supérieur de votre référentiel.

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 répond à la question xcopy inévitable de savoir si vous copiez un fichier ou un répertoire (fichier), et à la question possible sur l'écrasement d'un fichier (écraser tout)
  • sebackq nous permet d'utiliser la sortie de notre commande git comme entrée de notre clause do
  • HEAD ~ 1 HEAD récupère toutes les différences entre le commit précédent et le HEAD actuel
  • % ~ fA transforme la sortie git en chemins entièrement qualifiés (nécessaire pour changer les barres obliques en barres obliques inverses)
  • C:\git_changed_files \ est l'endroit où vous trouverez tous les fichiers différents
38
MM.

Vous pouvez exporter diff en utilisant Tortoise Git vers MS Windows:

Je fais un clic droit et sélectionne TortoiseGit > Afficher le journal et Les messages de journal seront ouverts.

Sélectionnez deux révisions et comparez-les. La différence entre sera ouverte.

Sélectionnez les fichiers et Exportez la sélection vers ... vers un dossier!

enter image description here

19
Wendel

J'avais besoin de mettre à jour mon serveur de test et d'ajouter des fichiers modifiés depuis la version 2.1.
Pour moi, j'ai travaillé sur une solution similaire à celle de James Ehly, mais dans mon cas, je voulais exporter vers un package d'archives de différence entre deux balises plus anciennes - tag_ver_2.1 et tag_ver_2.2 pas le seul commit.

Par exemple:

tag_ver_2.1 = 1f72b38ad
tag_ver_2.2 = c1a546782

Voici un exemple modifié:

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

Les commandes ci-dessous ont fonctionné pour moi.

Si vous voulez que la différence des fichiers soit modifiée par le dernier commit:

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

ou si vous voulez une différence entre deux commits spécifiques:

git archive -o update.Zip 4d50f1ee78bf3ab4dd8e66a1e230a64b62c49d42 $(git diff --name-only 07a698fa9e5af8d730a8c33e5b5e8eada5e0f400)

ou si vous avez des fichiers non validés, souvenez-vous que git est de tout commettre, les branches sont bon marché:

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^)
2
Ashutosh Tripathy

J'ai créé un script php pour exporter les fichiers modifiés sur Windows. Si vous avez un serveur de développement localhost avec php configuré, vous pouvez l'exécuter facilement. Il se souviendra de votre dernier référentiel et exportera toujours vers le même dossier. Le dossier d'exportation est toujours vidé avant l'exportation. Vous verrez également les fichiers supprimés en rouge afin que vous sachiez quoi supprimer sur le serveur.

Ce ne sont que deux fichiers donc je les posterai ici. Supposons que vos référentiels se trouvent sous c:/www dans leurs propres dossiers et que http: // localhost pointe également vers c:/www et soit compatible php. Mettons ces 2 fichiers dans 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

Et maintenant, chargez localhost/git-export/dans un navigateur. Le script est configuré pour exporter toujours vers c:/www/export - changez tous les chemins d'accès en fonction de votre environnement ou modifiez le script en fonction de vos besoins.

Cela fonctionnera si vous avez installé Git afin que la commande git soit dans votre PATH - cela peut être configuré lorsque vous exécutez le programme d'installation de Windows Git.

2
Lemon Juice

Pour exporter des fichiers modifiés commençant par une date:

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

Raccourci (utiliser un alias)

  git exportmdf 2016-11-01 11.tar

Alias ​​dans .gitconfig

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

Cela fonctionne pour moi pour Unix et Windows:

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

Il existe deux espaces réservés dans la commande. Vous devez les remplacer pour votre usage:

  • __ 1 __: remplacer par id de validation de la validation juste avant toutes les validations que vous souhaitez exporter (par exemple 997cc7b6 - n'oubliez pas de conserver ce doubledot après l'ID de validation - cela signifie "impliquer toutes les validations plus récentes que cette validation")

  • __ 2 __: remplacez par chemin existant où vous souhaitez exporter vos fichiers (par exemple ../export_path/)

En conséquence, vous obtiendrez vos fichiers dans une structure de dossiers (pas de zips/goudrons ...) car quelqu'un pourrait être habitué à utiliser tortue svn exports dans les dépôts svn.

Ceci est par exemple assez utile lorsque vous souhaitez effectuer un déploiement manuel de fichiers ajoutés/modifiés de quelques dernières validations. Vous pouvez donc simplement copier ces fichiers via le client ftp.

0
Skybamar

J'ai également rencontré un problème similaire auparavant. J'ai écrit un simple script Shell.

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

La commande ci-dessus affichera Commit Hash (révision) de commit_HashX à commit_HashY dans l'ordre inverse.

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

Maintenant, le script Shell principal utilisant la commande ci-dessus.

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

Ajoutez ce code à export_changes.sh. Maintenant, passez le fichier et validez les hachages dans le script.

Assurez-vous que commit_hash initial doit être le premier argument puis le dernier commit_hash vers lequel vous souhaitez exporter les modifications.

Exemple:

$ sh export_changes.sh hashX hashY

Placez ce script dans le répertoire local git ou définissez le chemin du répertoire local git dans le script. J'espère que ça aide ..!

0
Raj Hawaldar

Voici un petit script bash (Unix) que j'ai écrit qui copiera les fichiers pour un hachage de validation donné avec la structure de dossiers:

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

Créez un fichier nommé '~/Scripts/copy-commit.sh' puis donnez-lui les privilèges d'exécution:

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

Ensuite, à partir de la racine du référentiel git:

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