Yalnızca değiştirilmiş ve eklenen dosyaları Git'te klasör yapısıyla dışa aktarın


83

Belirli bir kaydetmede değiştirilmiş ve eklenen dosyaların bir listesini almak istiyorum, böylece onları dışa aktarabilir ve dosya yapısıyla bir paket oluşturabilirim.

Buradaki fikir, paketi alıp sunucuya çıkarmaktır. Pek çok nedenden dolayı depoyu otomatik olarak çekmek için bir kanca oluşturamıyorum ve sunucuyu güncel tutmanın en kolay yolu bu paketi oluşturmaktır.

Yanıtlar:


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

    Verilen commit'den üstlerine bir fark alın (sadece üst dizin değil, tüm alt dizinler dahil).

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

    SHA1 kaydetme çıktısını vermeyin. Tam fark yerine yalnızca etkilenen dosyaların adlarını çıktılar.

  3. --diff-filter=ACMRT:

    Bu işlemede yalnızca eklenen, kopyalanan, değiştirilen, yeniden adlandırılan veya türleri değiştirilen dosyaları (örn. Dosya → sembolik bağlantı) göster. Bu, silinen dosyaları dışarıda bırakır.


YORUMDAN GÜNCELLEME:
Soru bağlamına ve aşağıdaki yorumlara dayanarak aşağıdaki komut ile ACMRTdosyaları .tarklasör yapıları ile dosya olarak alabilirsiniz .

git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $commit_id | tar -czf file.tgz -T -

Şimdi bu komutun sonucunu katranla yapıştırmanın bir yolunu bulmalıyım! Teşekkür ederim!
Michael Kuhinica

8
@Taverneiro Bu cevapta verilen tar komutuna yönlendirebilirsiniz , örn. tgz dosyası için:git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $commit_id | tar -czf file.tgz -T -
Matthieu Sadouni

68
git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT $commit_id | xargs tar -rf mytarfile.tar

Sırf bunu tamamlamak için, işte, tar'a yönlendirilen komut. Bu, dosyaları bir tar arşivine aktarır.


1
Bu, tek bir tar dosyasında birden çok işlem için yapılabilir mi?
evolutionxbox

4
Aynı tar dosyasına birden fazla kaydetme eklemeye çalışırken, bazen tar, başka bir adla (dosyaadı1.uzantı) yeniden dosyaadı.ext oluşturur. Zip kullanırsam, zip içinde varsa dosyayı ekleyip üzerine yazabileceğimi fark ettim ... xargs'i xargs zip -r0 myzipfile.zip $ 1 ile değiştirmeniz yeterli
Ricardo Martins

Burada xargs gerekli mi? Rm gibi şeyler için olduğunu biliyorum, ama tar'ın istediğiniz kadar dosyayı işleyebileceğini düşündüm.
Erdal G.

1
Bu cevapla dikkatli olun, bu diff dosyalarını alın, ancak mevcut şubenin mevcut sürümü olarak
mems

1
Windows bağımlı makinede bu komutu çalıştırırken, "'xargs' dahili veya harici bir komut, çalıştırılabilir program veya toplu iş dosyası olarak tanınmıyor" hatasını alıyorum.
Navin prasad

40

İşte Windows 7'de çalışan tek satırlık bir komut. Bunu deponuzun en üst düzey klasöründen çalıştırın.

/ f "usebackq tokens = *" için% A in (`git diff-tree -r --no-commit-id - sadece ad --diff-filter = ACMRT HEAD ~ 1 HEAD`) yapmak echo FA | xcopy "% ~ fA" "C: \ git_changed_files \% A"

  • echo FA , bir dosyayı mı yoksa bir dizini (dosya) mı kopyaladığınızla ilgili kaçınılmaz xcopy sorusunu ve bir dosyanın üzerine yazma (Tümünün üzerine yaz) hakkındaki olası soruyu yanıtlar.
  • usebackq , git komutumuzun çıktısını do cümlemizin girdisi olarak kullanmamıza izin verir
  • HEAD ~ 1 HEAD , önceki commit ile mevcut HEAD arasındaki tüm farkları alır
  • % ~ fA , git çıktısını tam nitelikli yollara dönüştürür (eğik çizgileri ters eğik çizgilere dönüştürmek için gereklidir)
  • C: \ git_changed_files \ , farklı olan tüm dosyaları bulacağınız yerdir

1
Bu sembol karmaşasını gördüğümde, kapsamlı ince ayar yapmadan çalışmasını beklemiyordum ... ama ilk denemede işe yaradı, teşekkürler.
Nathan Fig

3
(benim gibi) windows toplu iş dosyalarına pek aşina olmayanlar için biraz uyarı: Yukarıdaki komutu bir toplu iş dosyasında kullanmak istiyorsanız, for döngüsü içinde% A'yı %% A ile değiştirmeniz gerekecektir.
buddybubble

1
Ne? LOL. Git arşivini kullanın - git diff combo (Nicolas'ın cevabı). Çok daha kolay ve anlaşılır. (Dürüst olmak gerekirse, burada ne olduğunu bilmiyorum.)
ADTC

1
Uyarı: Bu, dosyalarınızı çalışan kopyanızdan kopyalayacaktır ve bu HEAD'dekiyle (veya onu değiştirdiğiniz her türlü commit karmasıyla) eşleşmeyebilir
Simon East

1
Harika bir şey, ancak yalnızca CMD ile çalışıyor Powershell değil, -v ° v-
Rodion Bykov

33

Kaydetme karmanız örneğin a9359f9 ise, bu komut:

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

commit'de değiştirilen dosyaları ayıklayacak ve proje dizin yapısını sağlam tutarken bunları patch.zip'e yerleştirecektir.

biraz ayrıntılı, commit hash'den üç kez bahsediliyor, ama benim için çalışıyor gibi görünüyor.

burada anladım: http://tosbourn.com/2011/05/git/using-git-to-create-an-archive-of-changed-files/


Ben kullanabilir düşünüyorum functioniçinde PowerShell sadece bir işlev adının komutu azaltmak ve kullanımı $argssadece bir kez karma taahhüt geçmek. * Nix'te, aynı etkiyi elde etmek için muhtemelen kabuk komut dosyası yazmayı kullanabilirsiniz.
ADTC

1
Adamım ... Sana bir bira
sahibim

3
@BenSewards commit1 ve commit2 (sonraki commit dahil, önceki commit hariç; sipariş önemli değil) arasındaki taahhüt aralığı için sadece yapın git archive -o patch.zip HEAD /**or a commit**/ $(git diff --name-only commit1 commit2). archiveKomuta aktarılan yürütme, herhangi bir keyfi işlem (büyük olasılıkla HEAD veya sonraki yürütme) olabilir ve dosyalar, bu kaydetme aşamasında teslim alınmış gibi çekilir. Commit1 ve commit2 geçirilen diffyalnızca çekme dosyaların listesini oluşturmak için kullanılır - çekti dosyaların sürümünü etkilemez.
ADTC

1
Ek ipucu: Birden çok işlem aralığının değiştirilmiş dosyalarını tek bir arşivde birleştirmek istiyorsanız, diffkomutu noktalı virgülle tekrarlayın :git archive -o patch.zip HEAD /**or a commit**/ $(git diff --name-only commit1A commit1B; git diff --name-only commit2A commit2B; git diff --name-only commit3A commit3B)
ADTC

4
Yol isimlerindeki boşluklar nedeniyle git diff -z --name-only commit1 commit2 | xargs -0 git archive -o patch.zip HEAD
NUL'u

27

Tortoise Git'i kullanarak diff'i MS Windows'a aktarabilirsiniz :

Sağ tıklayıp TortoiseGit > Günlüğü Göster'i seçiyorum ve Günlük Mesajları açılacak.

İki revizyon seçin ve karşılaştırın. Aradaki fark açık olacak.

Dosyaları seçin ve seçimi bir klasöre aktarın !

görüntü açıklamasını buraya girin


1
Kesinlikle. Buna verilen pek çok yanıt yalnızca linux komutlarına sahipti ve çoğu çalışan değişiklikleri değil, yalnızca yapılan değişiklikleri yakaladı. Bunun gönderilmesine sevindim!
dythim

8

Test sunucumu güncellemem ve 2.1 sürümünden sonra değişen dosyaları eklemem gerekiyordu.
Benim için James Ehly'nin yayınladığı gibi benzer bir çözüm çalıştı, ancak benim durumumda iki eski etiket arasındaki fark paketini arşivlemek istedim - tag_ver_2.1 ve tag_ver_2.2 tek kayıt değil.

Örneğin:

tag_ver_2.1 = 1f72b38ad
tag_ver_2.2 = c1a546782

İşte değiştirilmiş örnek:

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

Az önce bir WEIRD sorunu tespit ettim: yukarıdaki kodu denersem, harika çalışıyor. Ama tar -rf test.tar dosyasını tar -zcf test.tar.gz için değiştirdim, sonra ortaya çıkan dosyada birkaç dosya eksik. Sonuçta bu farklılığa ne sebep olabilir?
Alberto Alexander Rodriguez

Windows bağımlı makinede bu komutu çalıştırırken, "'xargs' dahili veya harici bir komut, çalıştırılabilir program veya toplu iş dosyası olarak tanınmıyor" hatasını alıyorum.
Navin prasad

4

Aşağıdaki komutlar benim için çalıştı.

Son kaydetme ile değiştirilen dosyaların farkını istiyorsanız:

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

veya iki belirli kaydetme arasında fark istiyorsanız:

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

veya teslim edilmemiş dosyalarınız varsa, git yolunun her şeyi teslim etmek olduğunu unutmayın, şubeler ucuzdur:

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

2

Windows'ta değiştirilen dosyaları dışa aktarmak için bir php komut dosyası yaptım. Php kurulu bir localhost geliştirme sunucunuz varsa, onu kolayca çalıştırabilirsiniz. Son deponuzu hatırlayacak ve her zaman aynı klasöre aktaracaktır. Dışa aktarma klasörü dışa aktarılmadan önce her zaman boşaltılır. Ayrıca, silinen dosyaları kırmızı renkte göreceksiniz, böylece sunucuda neyi sileceğinizi bilirsiniz.

Bunlar sadece iki dosya, bu yüzden onları buraya göndereceğim. Depolarınızın kendi klasörlerinde c: / www altında bulunduğunu ve http: // localhost'un da c: / www'ye işaret ettiğini ve php özellikli olduğunu varsayalım . Bu 2 dosyayı 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

Ve şimdi bir tarayıcıya localhost / git-export / yükleyin. Komut dosyası her zaman c: / www / export - tüm yolları ortamınıza uyacak şekilde değiştirin veya komut dosyasını ihtiyaçlarınıza uyacak şekilde değiştirin.

Git komutunun PATH'inizde olması için Git yüklüyse bu işe yarar - bu, Windows Git yükleyicisini çalıştırdığınızda yapılandırılabilir.


bu kod harika, ancak alt modülleri olan dosyaları ve dizinleri dışa aktarmak istiyorum, kodunuz yalnızca ana depoda çalışıyor ve alt modüller kodunuzu değiştirdiyse, alt modül klasörü silindi diyelim!
morteza khadem

1

Bir tarihle başlayarak değiştirilen dosyaları dışa aktarmak için:

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

Kısayol (takma ad kullanın)

  git exportmdf 2016-11-01 11.tar

.Gitconfig içindeki takma ad

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

0

Klasör yapısı ile belirli bir commit karması için dosyaları kopyalayacak yazdığım küçük bir bash (Unix) betiği:

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' adlı bir dosya oluşturun ve ardından ona yürütme ayrıcalıkları verin:

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

Daha sonra git deposunun kökünden:

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

0

Daha önce de benzer bir sorunla karşılaştım. Basit bir Shell komut dosyası yazdım.

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

Yukarıdaki komut, commit_HashX'ten commit_HashY'ye ters sırada Commit Hash (Revizyon) gösterecektir.

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

Şimdi yukarıdaki komutu kullanan ana Kabuk Komut Dosyası.

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

Bu kodu export_changes.sh dosyasına ekleyin. Şimdi dosyayı aktarın ve karmaları betiğe kesin.

İlk commit_hash'in ilk bağımsız değişken olması, ardından değişiklikleri dışa aktarmak istediğiniz son commit_hash olması gerektiğinden emin olun.

Misal:

$ sh export_changes.sh hashX hashY

Bu komut dosyasını git yerel dizinine yerleştirin veya komut dosyasında git yerel dizin yolunu ayarlayın. Umarım yardımcı olur..!


0

Bu benim için hem Unix hem de Windows için çalışıyor:

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

Komutta iki yer tutucu vardır. Bunları amacınız için değiştirmeniz gerekir:

  • __1__ : dışa aktarmak istediğiniz tüm işlemlerden hemen önce commit kimliğini değiştirin (ör. 997cc7b6 - kayıt kimliğinden sonra o doubleledot'u tutmayı unutmayın - bu, "bu commit'den daha yeni olan tüm commit'leri dahil edin" anlamına gelir)

  • __2__ : dosyalarınızı dışa aktarmak istediğiniz mevcut yolla değiştirin (ör. ../Export_path/)

Sonuç olarak , svn depolarında kaplumbağa svn dışa aktarımını kullanmaya alışkın olabileceğinden, dosyalarınızı bir klasör yapısında (fermuar / tarak yok ...) alacaksınız .

Bu, örneğin, son birkaç kaydetmeden eklenen / değiştirilen dosyaların manuel dağıtımını gerçekleştirmek istediğinizde oldukça kullanışlıdır. Böylece bu dosyaları ftp istemcisi aracılığıyla kopyalayabilirsiniz.


0

Ben de aynı sorunu yaşadım. Karşılaştırılan kayıtlar arasında çok fazla dosya değiştiği için @NicolasDermine çözümü işe yaramadı. Kabuk bağımsız değişkenlerinin çok uzun olduğuna dair bir hata aldım.

Sonuç olarak bir python uygulaması ekledim. Bu, aracılığıyla kurulabilir pip install gitzipve ardından

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

Repositorys kökünde export.zip, dizin yapısını koruyarak tüm değiştirilmiş dosyaları içeren bir dosya oluşturmak .

Belki birinin de buna ihtiyacı vardır, bu yüzden burada paylaşmayı düşündüm.

Feragatname : gitzip modülünün yazarıyım .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.