2012-10-11 36 views
9

Tôi muốn truy xuất tất cả phiên bản trước của tệp cụ thể trong kho lưu trữ git.git - nhận TẤT CẢ phiên bản trước của một tệp/thư mục cụ thể

Tôi thấy có thể nhận được một phiên bản cụ thể với lệnh thanh toán, nhưng tôi muốn tất cả. Và lệnh git clone với tùy chọn chiều sâu dường như không cho phép tôi sao chép thư mục con ("không phải tên kho lưu trữ hợp lệ").

Bạn có biết điều đó có thể thực hiện được không?

Cảm ơn bạn

Trả lời

9

OP muốn truy xuất tất cả các phiên bản nhưng câu trả lời sẽ không phân phối. Đặc biệt nếu tệp có hàng trăm bản sửa đổi (tất cả các đề xuất đều quá thủ công).Giải pháp nửa làm việc duy nhất đã được đề xuất bởi @Tobias trong các ý kiến, nhưng đề nghị bash loop sẽ xây dựng các tập tin theo thứ tự ngẫu nhiên cũng như nó tạo ra hàng trăm tập tin rỗng khi được sử dụng chống lại repos của chúng tôi. Một trong những lý do là "rev-list --all --objects" sẽ liệt kê các đối tượng khác nhau (cây bao gồm - nhưng vô ích cho mục đích của chúng tôi).

Tôi bắt đầu với giải pháp của Tobias, thêm bộ đếm, dọn dẹp một chút và kết thúc việc phát minh lại bánh xe dưới dạng tập lệnh bash được liệt kê bên dưới.

Các kịch bản sẽ:
- trích xuất tất cả phiên bản tập tin vào/tmp/all_versions_exported
- mất 1 đối số - đường dẫn tương đối đến tập tin bên trong git repo
- cho kết quả tên tập tin tiền tố số (sắp xếp được)
- đề cập đến tên tệp được kiểm tra trong tệp kết quả (để nói táo ngoài cam)
- đề cập ngày cam kết trong tên tệp kết quả (xem ví dụ đầu ra bên dưới)
- không tạo tệp kết quả rỗng

mèo/usr/local/bin/git_export_all_file_versions

#!/bin/bash 

# we'll write all git versions of the file to this folder: 
EXPORT_TO=/tmp/all_versions_exported 

# take relative path to the file to inspect 
GIT_PATH_TO_FILE=$1 

# ---------------- don't edit below this line -------------- 

USAGE="Please cd to the root of your git proj and specify path to file you with to inspect (example: $0 some/path/to/file)" 

# check if got argument 
if [ "${GIT_PATH_TO_FILE}" == "" ]; then 
    echo "error: no arguments given. ${USAGE}" >&2 
    exit 1 
fi 

# check if file exist 
if [ ! -f ${GIT_PATH_TO_FILE} ]; then 
    echo "error: File '${GIT_PATH_TO_FILE}' does not exist. ${USAGE}" >&2 
    exit 1 
fi 

# extract just a filename from given relative path (will be used in result file names) 
GIT_SHORT_FILENAME=$(basename $GIT_PATH_TO_FILE) 

# create folder to store all revisions of the file 
if [ ! -d ${EXPORT_TO} ]; then 
    echo "creating folder: ${EXPORT_TO}" 
    mkdir ${EXPORT_TO} 
fi 

## uncomment next line to clear export folder each time you run script 
#rm ${EXPORT_TO}/* 

# reset coutner 
COUNT=0 

# iterate all revisions 
git rev-list --all --objects -- ${GIT_PATH_TO_FILE} | \ 
    cut -d ' ' -f1 | \ 
while read h; do \ 
    COUNT=$((COUNT + 1)); \ 
    COUNT_PRETTY=$(printf "%04d" $COUNT); \ 
    COMMIT_DATE=`git show $h | head -3 | grep 'Date:' | awk '{print $4"-"$3"-"$6}'`; \ 
    if [ "${COMMIT_DATE}" != "" ]; then \ 
     git cat-file -p ${h}:${GIT_PATH_TO_FILE} > ${EXPORT_TO}/${COUNT_PRETTY}.${COMMIT_DATE}.${h}.${GIT_SHORT_FILENAME};\ 
    fi;\ 
done  

# return success code 
echo "result stored to ${EXPORT_TO}" 
exit 0 


Cách sử dụng Ví dụ:

cd /home/myname/my-git-repo 

git_export_all_file_versions docs/howto/readme.txt 
    result stored to /tmp/all_versions_exported 

ls /tmp/all_versions_exported 
    0001.17-Oct-2016.ee0a1880ab815fd8f67bc4299780fc0b34f27b30.readme.txt 
    0002.3-Oct-2016.d305158b94bedabb758ff1bb5e1ad74ed7ccd2c3.readme.txt 
    0003.29-Sep-2016.7414a3de62529bfdd3cb1dd20ebc1a977793102f.readme.txt 
    0004.28-Sep-2016.604cc0a34ec689606f7d3b2b5bbced1eece7483d.readme.txt 
    0005.28-Sep-2016.198043c219c81d776c6d8a20e4f36bd6d8a57825.readme.txt 
    0006.9-Sep-2016.5aea5191d4b86aec416b031cb84c2b78603a8b0f.readme.txt 
    <and so on and on . . .> 

chỉnh sửa: nếu bạn thấy lỗi như thế này:

gây tử vong: Không phải tên đối tượng hợp lệ 3e93eba38b31b8b81905ceaa95eb47bba ed46494: readme.txt

có nghĩa là bạn đã bắt đầu tập lệnh không phải từ thư mục gốc của dự án git.

+0

Câu trả lời được chấp nhận trước đây (@sehe) thực sự không thực hiện trực tiếp việc truy xuất TẤT CẢ các phiên bản cùng một lúc. Như đã đề cập trong bình luận tôi đã sử dụng cả hai lệnh để xây dựng một chương trình java (không phải là một giải pháp chung có thể được tải lên như là) mà đã làm nó. Giải pháp của bạn tốt hơn vì nó mang lại kết quả cuối cùng của chương trình java trong quá khứ của tôi. – max152

+0

Kịch bản này hoạt động, nhưng có một số vấn đề và hành vi có thể không mong muốn. Vui lòng xem [câu trả lời của tôi] (http://stackoverflow.com/a/43747334/1132502) để biết chi tiết và tập lệnh được cập nhật. –

+0

@Nathan, tuyệt vời! vui vì bạn thấy hữu ích +1 –

-2

Tất cả các phiên bản của tệp đã có trong git repo khi bạn git sao chép nó. Bạn có thể tạo các ngành liên quan đến việc thanh toán của một đặc biệt cam kết:

git checkout -b branchname {commit#} 

này có thể đủ cho một sự so sánh thủ công nhanh chóng và dơ bẩn thay đổi:

  • thanh toán cho các chi nhánh
  • Copy to một vùng đệm biên tập viên

Điều này có thể được, nếu bạn chỉ có một vài phiên bản cần quan tâm và không ngại một chút lệnh thủ công, mặc dù được tích hợp sẵn.

Đối với các giải pháp theo kịch bản, đã có một vài giải pháp khác được cung cấp trong các câu trả lời khác.

+0

Cảm ơn bạn! Tôi không biết điều đó (lần đầu tiên tôi sử dụng git). Bây giờ tôi có thể truy xuất tất cả các phiên bản. – max152

4
git rev-list --all --objects -- path/to/file.txt 

danh sách bạn tất cả các đốm màu gắn liền với con đường repo

Để có được một phiên bản cụ thể của một tập tin

git cat-file -p commitid:path/to/file.txt 

(commitid có thể bất cứ điều gì

  • ref tượng trưng (tên chi nhánh, tên thẻ; từ xa quá)
  • băm cam kết
  • một spec sửa đổi như ĐẦU ~ 3, branch1 @ {4}, vv
+0

Ok cảm ơn! Nó đã cho tôi thời gian để hiểu (đó là lần đầu tiên tôi sử dụng git). Bây giờ tôi có thể tạo một tập lệnh sẽ tái tạo lại tất cả các phiên bản. – max152

+0

Mở rộng các chi tiết cụ thể của câu trả lời tổng quát của tôi – gview

+2

@ user1739644 Bạn có cơ hội cố gắng chuyển đổi kho lưu trữ không? Hãy xem 'git fast-export --all errata.html' có định dạng tệp đơn giản, được tài liệu tốt, được hỗ trợ bởi nhiều VCS-es khác. – sehe

0

phiên bản cũ Đôi khi một tập tin chỉ có sẵn thông qua git reflog. Gần đây tôi đã có một tình huống mà tôi cần phải khai thác thông qua tất cả các cam kết, ngay cả những người không còn là một phần của nhật ký vì một sự ghi đè tình cờ trong quá trình rebasing tương tác.

Tôi đã viết tập lệnh Ruby này để xuất tất cả các phiên bản trước đó của tệp để tìm thấy cam kết mồ côi. Nó đã đủ dễ dàng để grep đầu ra của điều này để theo dõi tập tin bị thiếu của tôi. Hy vọng nó sẽ giúp ai đó.

#!/usr/bin/env ruby 
path_to_file = "" 
`git reflog`.split("\n").each do |log| 
    puts commit = log.split(" ").first 
    puts `git show #{commit}:#{path_to_file}` 
    puts 
end 

Điều tương tự có thể được thực hiện với git log.

4

Kịch bản do Dmitry cung cấp thực sự giải quyết được vấn đề, nhưng có một số vấn đề khiến tôi thích ứng với nó phù hợp hơn với nhu cầu của tôi. Cụ thể:

  1. Việc sử dụng git show bị phá vỡ do cài đặt định dạng ngày mặc định của tôi.
  2. Tôi muốn các kết quả được sắp xếp theo thứ tự ngày, không phải theo thứ tự ngược lại.
  3. Tôi muốn có thể chạy nó đối với tệp đã bị xóa khỏi repo.
  4. Tôi không muốn tất cả các bản sửa đổi trên tất cả các chi nhánh; Tôi chỉ muốn các bản sửa đổi có thể truy cập từ HEAD.
  5. Tôi muốn báo lỗi nếu không có trong repo git.
  6. Tôi không muốn phải chỉnh sửa tập lệnh để điều chỉnh các tùy chọn nhất định.
  7. Cách hoạt động không hiệu quả.
  8. Tôi không cần đánh số trong tên tệp đầu ra. (Một ngày được định dạng phù hợp sẽ phục vụ cùng một mục đích.)
  9. tôi muốn "đường dẫn với không gian" an toàn hơn xử lý

Bạn có thể thấy phiên bản mới nhất của sửa đổi của tôi in my github repo hoặc đây là phiên bản như các văn bản này:

#!/bin/sh 

# based on script provided by Dmitry Shevkoplyas at http://stackoverflow.com/questions/12850030/git-getting-all-previous-version-of-a-specific-file-folder 

set -e 

if ! git rev-parse --show-toplevel >/dev/null 2>&1 ; then 
    echo "Error: you must run this from within a git working directory" >&2 
    exit 1 
fi 

if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then 
    echo "Usage: $0 <relative path to file> [<output directory>]" >&2 
    exit 2 
fi 

FILE_PATH="$1" 

EXPORT_TO=/tmp/all_versions_exported 
if [ -n "$2" ]; then 
    EXPORT_TO="$2" 
fi 

FILE_NAME="$(basename "$FILE_PATH")" 

if [ ! -d "$EXPORT_TO" ]; then 
    echo "Creating directory '$EXPORT_TO'" 
    mkdir -p "$EXPORT_TO" 
fi 

echo "Writing files to '$EXPORT_TO'" 
git log --diff-filter=d --date-order --reverse --format="%ad %H" --date=iso-strict "$FILE_PATH" | grep -v '^commit' | \ 
    while read LINE; do \ 
     COMMIT_DATE=`echo $LINE | cut -d ' ' -f 1`; \ 
     COMMIT_SHA=`echo $LINE | cut -d ' ' -f 2`; \ 
     printf '.' ; \ 
     git cat-file -p "$COMMIT_SHA:$FILE_PATH" > "$EXPORT_TO/$COMMIT_DATE.$COMMIT_SHA.$FILE_NAME" ; \ 
    done 
echo 

exit 0 

Một ví dụ về đầu ra :

$ git_export_all_file_versions bin/git_export_all_file_versions /tmp/stackoverflow/demo 
Creating directory '/tmp/stackoverflow/demo' 
Writing files to '/tmp/stackoverflow/demo' 
... 

$ ls -1 /tmp/stackoverflow/demo/ 
2017-05-02T15:52:52-04:00.c72640ed968885c3cc86812a2e1aabfbc2bc3b2a.git_export_all_file_versions 
2017-05-02T16:58:56-04:00.bbbcff388d6f75572089964e3dc8d65a3bdf7817.git_export_all_file_versions 
2017-05-02T17:05:50-04:00.67cbdeab97cd62813cec58d8e16d7c386c7dae86.git_export_all_file_versions 
Các vấn đề liên quan