2010-12-27 28 views
59

Tôi muốn nhận danh sách các tệp được sửa đổi và thêm vào trong một cam kết cụ thể để tôi có thể xuất chúng và tạo một gói có cấu trúc tệp.Chỉ xuất các tệp đã sửa đổi và được thêm vào với cấu trúc thư mục trong Git

Ý tưởng là lấy gói và giải nén nó trên máy chủ. Vì nhiều lý do tôi không thể tạo ra một cái móc để kéo repo tự động và cách dễ nhất mà tôi phải giữ cho máy chủ được cập nhật là tạo ra gói này.

Trả lời

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

    Hãy diff của trao cam kết mẹ của nó (s) (bao gồm tất cả các thư mục con, không chỉ các thư mục trên cùng).

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

    Đừng đầu ra cam kết SHA1. Chỉ xuất ra tên của các tệp bị ảnh hưởng thay vì một tệp đầy đủ.

  3. --diff-filter=ACMRT:

    Chỉ hiển thị tập tin thêm vào, sao chép, sửa đổi, đổi tên hoặc đã loại họ thay đổi trong cam kết này (ví dụ như tập tin → liên kết tượng trưng.). Thao tác này sẽ xóa các tệp đã xóa.

+0

Bây giờ tôi chỉ phải tìm ou một cách để dán kết quả của lệnh này với tar! Cảm ơn bạn! –

+4

@Taverneiro Bạn có thể đặt nó vào lệnh [tar được đưa ra trong câu trả lời này] (http://stackoverflow.com/questions/2597875/how-can-i-build-a-tar-from-stdin), ví dụ: đối với tệp tgz: 'git diff-tree -r --no-cam-id - chỉ -name -diff-filter = ACMRT $ commit_id | tar -zf file.tgz -T -' –

2

Tôi đã tạo một tập lệnh php để xuất các tệp đã thay đổi trên Windows. Nếu bạn có một máy chủ phát triển localhost với php được thiết lập thì bạn có thể chạy nó một cách dễ dàng. Nó sẽ nhớ kho lưu trữ cuối cùng của bạn và xuất luôn vào cùng một thư mục. Thư mục xuất luôn được dọn sạch trước khi xuất. Bạn cũng sẽ thấy các tệp đã xóa màu đỏ để bạn biết những gì cần xóa trên máy chủ.

Đây chỉ là hai tệp để tôi sẽ đăng chúng ở đây. Giả sử các kho lưu trữ của bạn được đặt dưới thư mục c:/www trong các thư mục riêng của chúng và rằng http://localhost cũng trỏ tới c:/www và được bật php. Hãy đặt những 2 file trong c:/www/git khẩu -

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 

Và bây giờ tải localhost/git- xuất/trong trình duyệt. Tập lệnh được thiết lập để xuất luôn vào c:/www/export - thay đổi tất cả các đường dẫn cho phù hợp với môi trường của bạn hoặc sửa đổi kịch bản cho phù hợp với nhu cầu của bạn.

Điều này sẽ hoạt động nếu bạn đã cài đặt Git sao cho lệnh git nằm trong PATH của bạn - điều này có thể được định cấu hình khi bạn chạy trình cài đặt Git của Windows.

+0

mã này rất tuyệt, nhưng tôi muốn xuất các tập tin và thư mục với submodules mã của bạn chỉ làm việc với kho lưu trữ chính và nếu submodules thay đổi mã của bạn nói submodule thư mục bị xóa! –

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

Để làm tròn điều này, đây là lệnh được chuyển tới tar. Điều này xuất khẩu các tập tin vào một kho lưu trữ tar.

+2

thật tuyệt vời! – LeandroCR

+0

Điều này có thể được thực hiện cho nhiều cam kết thành một tệp tar không? – evolutionxbox

+3

Khi cố gắng thêm nhiều commit vào cùng một tập tin tar, đôi khi tar tạo filename.ext lại với tên khác (filename1.ext). Tôi nhận thấy rằng nếu tôi sử dụng mã zip, tôi có thể thêm và ghi đè tệp nếu nó tồn tại trong zip ... Bạn chỉ cần thay thế các xarg bằng xargs zip -r0 myzipfile.zip $ 1 –

37

Đây là lệnh một dòng hoạt động trên Windows 7. Chạy lệnh này từ thư mục cấp cao nhất của kho lưu trữ của bạn.

cho/f "usebackq tokens = *"% A in (`git diff-tree -r --no-cam-id -name-only --diff-filter = ACMRT HEAD ~ 1 HEAD`) làm vang FA | xcopy "% ~ fA" "C: \ git_changed_files \% A"

  • vang FA trả lời câu hỏi xcopy không thể tránh khỏi về việc liệu bạn đang sao chép một tập tin hoặc một thư mục (tập tin) và câu hỏi có thể về ghi đè tệp (ghi đè Tất cả)
  • usebackq cho phép chúng tôi sử dụng outpu t từ lệnh git của chúng tôi là đầu vào để làm điều khoản của chúng tôi
  • ĐẦU ~ 1 TRỤ được tất cả sự khác biệt giữa trước cam kết và các HEAD hiện
  • % ~ fA biến đổi đầu ra git vào đường dẫn đầy đủ (cần thiết để thay đổi dấu gạch chéo để gạch chéo ngược)
  • C: \ git_changed_files \ là nơi bạn sẽ tìm thấy tất cả các tập tin khác nhau
+0

Khi tôi thấy sự lộn xộn của các biểu tượng tôi không mong đợi nó hoạt động mà không cần chỉnh sửa rộng rãi ... nhưng nó đã làm việc trong lần thử đầu tiên, cảm ơn. –

+0

Thật tuyệt vời, hoạt động như sự quyến rũ! –

+2

một đầu nhỏ cho tất cả những người (giống như tôi) không phải rất quen thuộc với các tập tin batch windows: Nếu bạn muốn sử dụng lệnh trên trong một tập tin batch, bạn sẽ cần phải thay thế% A bằng %% A bên trong cho vòng lặp – buddybubble

25

nếu bạn cam kết băm là ví dụ a9359f9, lệnh này:

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

sẽ trích xuất các tập tin sửa đổi trong cam kết và đặt chúng trong patch.zip trong khi vẫn giữ cấu trúc thư mục dự án còn nguyên vẹn.

một chút chi tiết, băm cam kết được đề cập ba lần, nhưng dường như nó hoạt động đối với tôi.

đã nhận nó ở đây: http://tosbourn.com/2011/05/git/using-git-to-create-an-archive-of-changed-files/

+0

Tôi nghĩ tôi có thể sử dụng 'hàm' trong * PowerShell * để giảm lệnh chỉ thành tên hàm và sử dụng' $ args' để chuyển vào hash băm chỉ một lần . Trong * nix, bạn có thể sử dụng shell-scripting để đạt được hiệu quả tương tự. – ADTC

+0

Người đàn ông ... Tôi sở hữu một ly bia của bạn :) – deanpodgornik

+0

chỉ là một lưu ý rằng kho lưu trữ git không hoạt động đối với một loạt các sửa đổi –

7

tôi cần phải cập nhật máy chủ thử nghiệm của tôi và thêm các tập tin đã thay đổi kể từ phiên bản 2.1.
Đối với tôi làm việc giải pháp tương tự như James Ehly được đăng, nhưng trong trường hợp của tôi, tôi muốn xuất để lưu trữ gói khác biệt giữa hai thẻ cũ hơn - tag_ver_2.1 và tag_ver_2.2 không phải là cam kết duy nhất.

Ví dụ:

tag_ver_2.1 = 1f72b38ad
tag_ver_2.2 = c1a546782

Đây được sửa đổi Ví dụ:

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

Tôi vừa phát hiện ra một vấn đề WEIRD: nếu tôi thử đoạn mã ở trên, nó hoạt động như một sự quyến rũ. Nhưng tôi thay đổi test.tar tar -rf cho tar -zcf test.tar.gz, sau đó tệp kết quả thiếu một vài tệp. Điều gì có thể gây ra sự khác biệt này trong kết quả? –

7

Bạn có thể xuất khác sử dụng Tortoise Git để MS Windows:

tôi nhấp chuột phải và chọn TortoiseGit>Hiển thị Nhật kýThông báo tường trình sẽ mở ra.

Chọn hai bản chỉnh sửa và so sánh nó. Sự khác biệt giữa sẽ được mở.

Chọn tệp và Xuất lựa chọn thành ... vào một thư mục!

enter image description here

+0

Sau khi đấu tranh với các lệnh, điều này đã hoàn thành công việc. – SwampyFox

0

Để xuất file sửa đổi bắt đầu với một ngày:

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

Shortcut (sử dụng bí danh)

git exportmdf 2016-11-01 11.tar 

Bí danh trong .gitconfig

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

Đây là một bash nhỏ (Unix) kịch bản mà tôi đã viết rằng sẽ sao chép các file cho một định cam kết băm với cấu trúc thư mục:

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 

Tạo một file có tên '~/Scripts/copy-commit.sh' rồi cung cấp cho nó quyền thực hiện:

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

Sau đó, từ thư mục gốc của kho git:

~/Scripts/copy-commit.sh COMMIT_KEY ~/Existing/Destination/Folder/ 
Các vấn đề liên quan