2013-03-06 33 views
33
git filter-branch --env-filter ' 
export GIT_AUTHOR_EMAIL="[email protected]" 
export GIT_AUTHOR_NAME="foo"' -- commita..commitb 

Kết quả trong Which ref do you want to rewrite?Chạy filter-branch qua một loạt các cam kết

Vì vậy, có vẻ như filter-branch không cho phép phạm vi ký hiệu bạn sử dụng sử dụng một phạm vi giữa hai refs tùy ý.

con đường phía trước thẳng nhất của chạy một bộ lọc trên một loạt các cam kết liên tiếp (nơi nào đó trong lịch sử của một chi nhánh) nếu phương pháp này là không thể thực hiện là gì.

+10

Nghiêm túc, ai đã phát minh ra thông báo lỗi là vô ích như vậy? Việc sử dụng duy nhất cho thông điệp đó dường như là nhập nó vào Google ... Một cái gì đó như "sự kết thúc của phạm vi cần phải là một tham chiếu, không phải là ID của một cam kết" (thx để @qqx) sẽ xuất hiện để được hữu ích hơn . – oliver

Trả lời

22

Giải pháp sạch nhất tôi thấy là phải làm như sau:

  1. Tạo một chi nhánh tạm thời tại refb.
  2. Áp dụng bộ lọc chi nhánh trên refa..temp.
  3. Rebase vào nhánh tạm thời và xóa nó.

tức là.

git branch temp refb 

git filter-branch --env-filter ' 
export GIT_AUTHOR_EMAIL="[email protected]"' refa..temp 

git rebase temp 
git branch --delete temp 
+1

+1 - mẹo hay, nhưng tôi nghĩ rằng nhánh lọc cần được chạy trên 'refa..temp' và lệnh rebase của bạn phải là 'git rebase --onto temp refa refb' – Chronial

8

git filter-branchkhông chấp nhận ký hiệu phạm vi, nhưng kết thúc phạm vi cần phải là tham chiếu, chứ không phải ID của cam kết.

git checkout -b tofilter commitb 
git filter-branch .... commita..tofilter 

Nếu được chỉ cam kết, nó sẽ không biết cần cập nhật gì với nhánh đã lọc.

+0

Trường hợp này xảy ra, làm cách nào để ngăn chặn tập lệnh bộ lọc của tôi được áp dụng cho các cam kết trước khi thực hiện và cam kết sau khi cam kết? – Acorn

2

Bạn có thể không chỉ ghi đè lên các cam kết trong một trung tâm của lịch sử, bởi vì sha1 của một cam kết phụ thuộc vào một phụ huynh. Vì vậy, git không biết nơi nào bạn muốn điểm tham chiếu HEAD của bạn sau khi lọc. Vì vậy, bạn nên viết lại tất cả lên đến HEAD.

Ví dụ:

A---B---C---D---E---F master 
      \ 
      \--G---H branch 

nếu bạn muốn lọc cam B và C bạn cũng nên lọc tất cả các cam kết sau: D, E, F, G, H. Vì vậy, đó là lý do tại sao git cho bạn sử dụng một ref ở cuối phạm vi, để nó không kết thúc với một đầu tách rời.

Sau khi bạn sửa đổi B và C cam kết và dừng lại sẽ trông như thế này:

A---B---C---D---E---F master 
\   \ 
\   \--G---H branch 
    \-B'--C'  (HEAD or a temporary TAG?..)  

Vì vậy, masterbranch sẽ bị ảnh hưởng. Tôi không nghĩ rằng điều này là bạn muốn. Điều đó có nghĩa là bạn phải ghi đè tất cả các cam kết. Lịch sử sẽ sau đó:

A---B---C---D---E---F (loose end, will be garbage collected one day) 
\   \ 
\   \--G---H (loose end, will be garbage collected one day) 
    \-B'--C'--D'--E'--F' master 
      \ 
      \--G'--H' branch 
+0

Vậy bạn nghĩ cách tiếp cận tốt nhất là gì nếu tôi không muốn áp dụng bộ lọc của mình để cam kết sau 'C'? Tôi có thể tạo một TAG tạm thời không? – Acorn

+0

@Acorn Nếu bạn muốn giữ cam kết sau khi lọc C (tôi gọi nó là 'C''), bạn phải lọc tất cả chúng ít nhất để thay đổi tổ tiên của chúng từ' C' thành 'C'', nếu không, chỉ cần thả chúng di chuyển nhánh chính sang 'C''. Không có tùy chọn. Cam kết có tất cả lịch sử trước khi nó được mã hóa trong id SHA1 của nó, vì vậy mỗi cam kết được bảo vệ bằng mật mã, bạn không thể thay đổi lịch sử mà không bị chú ý. – kan

+0

Phải, vì vậy tôi có ấn tượng rằng tôi phải đưa ra quyết định có áp dụng thay đổi tác giả/email trong tập lệnh bash của tôi hay không. Làm cách nào tôi có thể biết liệu tôi có nằm trong phạm vi từ đó không? – Acorn

5

Kèm theo các lệnh lọc trong câu lệnh if để kiểm tra phạm vi đó. Bạn có thể kiểm tra xem một cam kết là trong một phạm vi nhất định với lệnh này:

git rev-list start..end | grep **fullsha** 

hiện nay cam kết sẽ được lưu trữ trong $GIT_COMMIT trong bộ lọc của bạn.Vì vậy, bộ lọc của bạn trở thành:

git filter-branch --env-filter ' 
    if git rev-list commita..commitb | grep $GIT_COMMIT; then 
    export GIT_AUTHOR_EMAIL="[email protected]" 
    export GIT_AUTHOR_NAME="foo" 
    fi' -- ^commita --all 

Nếu bạn chỉ muốn viết lại chi nhánh hiện tại của bạn, thay thế --all với HEAD

16

Bạn không thể áp dụng các filter-branch ở giữa lịch sử, như đã nói bởi @kan. Bạn phải áp dụng từ cam kết đã biết của bạn cho đến cuối lịch sử

git filter-branch --env-filter '...' SHA1..HEAD 

Chi nhánh lọc có thể chọn thay đổi hoặc không thực hiện cam kết, vì vậy có nhiều cách để thực hiện những gì bạn muốn, xem http://git-scm.com/book/ch6-4.html, hãy tìm "Thay đổi E-mail Addresses toàn cầu"

Hãy nhớ rằng: nếu bạn đã đẩy các cam kết đến một kho lưu trữ công cộng bạn không nên sử dụng filter-branch

+0

* PSA: * Nó không thể viết lại giữa lịch sử, vì nó sẽ làm mất hiệu lực trường gốc của đầu đuôi được gắn vào giữa. – cdosborn

4

tôi làm điều đó theo cách này.

Giả sử bạn muốn lọc nội dung của chi nhánh có tên là nhánh bạn đang lọc.

Giả sử rằng có một tổ tiên cam kết với nhánh đó, với một ref được gọi là ref-for-commit-to-stop-at.

git filter-branch --commit-filter 'YOUR_FILTER_COMMANDS' branch-you-are-filtering...ref-for-commit-to-stop-at 

Sau khi thực hiện, cam kết tại cam kết tiếp tục dừng sẽ không bị thay đổi. Tất cả các commit đã thay đổi được lọc trong nhánh branch-you-are-filtering sẽ được dựa trên ref-for-commit-to-stop-at.

Có hay không bạn đang sử dụng - bộ lọc đồng bộ hoặc nội dung nào khác tùy thuộc vào bạn.

-1

Giải pháp từ @Acron có vẻ sai với tôi. Tôi sẽ đề nghị sau đây để thay đổi giữa refa và refb bao gồm cả băm:

  1. git tag master.bak
  2. git reset --hard refa
  3. git filter-branch --env-filter ' export GIT_AUTHOR_EMAIL="[email protected]"' refa^..master
  4. git cherry-pick refb..master.bak
  5. git tag -d master.bak
-1

Sử dụng filter-branch của --setup parm và một số sức mạnh vỏ:

git filter-branch --setup ' 
for id in `git rev-list commitA..commitB`; do 
     eval filterfor_$id=rewrite 
done 
rewrite() { 
     GIT_AUTHOR_NAME="Frederick. O. Oosball" 
     [email protected] 
} 
' --env-filter 'eval \$filterfor_$GIT_COMMIT' 
Các vấn đề liên quan