2009-03-13 42 views
44

Tôi đã thực hiện thay đổi trong tập lệnh và cam kết. Sau đó, tôi đã thực hiện một vài thay đổi khác và đẩy chúng vào một kho lưu trữ từ xa và như vậy.Hoàn tác thay đổi trong git (không phải viết lại lịch sử)

Sau đó, tôi nhận ra rằng thay đổi đầu tiên tôi đã đề cập là ngu ngốc, và muốn hoàn tác nó .. Tôi có thể "không áp dụng" cam kết, mà không sao chép/dán khác biệt theo cách thủ công không?

Ví dụ: Tôi có hai tập tin, a.pyb.py:

Commit 1: 
I delete a function in a.py 

Commit 2: 
I change a few lines in b.py 

Commit 3: 
I change the docstring in a.py 

Tôi có thể lùi lại rằng chức năng xóa, và làm cho nó xuất hiện như "cam kết 4" (chứ không phải xóa cam kết 1)

+13

Oi, đó là "nhận ra", không "nhận ra"! (Tôi không phải người Mỹ ..) – dbr

+3

Chính tả của bạn đã được sửa chữa bởi một người sử dụng bãi và bàn chân để đo lường mọi thứ ... ha ha – FaddishWorm

Trả lời

57

Có, bạn có thể sử dụng git hoàn nguyên cho việc này. Xem git manual section on this để biết thêm thông tin.

Các ý chính là bạn có thể nói:

git revert 4f4k2a 

đâu 4f4k2a là id của cam kết mà bạn muốn undo, và nó sẽ cố gắng để hủy bỏ nó.

+0

Aha, tất nhiên, cảm ơn! – dbr

+0

BTW! Nó sẽ xóa cam kết 1 đối tượng – aatifh

+0

Hm, dường như không xóa cam kết hoàn nguyên .. – dbr

31

Chỉ cần một lời nhận xét:

git revert aCommit 

không phục hồi các tất cả cam kết (như trong "tất cả các file phần của cam kết"):
nó tính một bản vá ngược lại, áp dụng nó trên TRỤ và cam kết.

Vì vậy, hai vấn đề ở đây (người đầu tiên có thể dễ dàng giải quyết):

  • nó luôn cam kết, vì vậy bạn có thể muốn thêm -no-commit tùy chọn: "git revert --no-commit aCommit": đây là hữu ích khi quay trở lại nhiều hơn một hiệu ứng cam kết với chỉ mục của bạn liên tiếp.
  • không áp dụng cho một tệp cụ thể (nếu bạn a.py là một phần của cam kết với 1000 thay đổi khác mà bạn có thể không muốn hoàn nguyên)?
    Cho rằng, nếu bạn muốn trích xuất tập tin cụ thể như trong một cam kết, bạn sẽ thấy git-checkout, đặc biệt là cú pháp git checkout <commit> <filename> (mà không phải là chính xác những gì bạn cần trong trường hợp này mặc dù)

Easy Git (Elijah Newren) đã cố gắng mang lại "hoàn nguyên" hoàn chỉnh hơn cho Git Mailing list; nhưng không thành công nhiều:

Mọi người đôi khi muốn "hoàn nguyên thay đổi".

Bây giờ, điều này có thể là:

  • những thay đổi giữa 32 và 29 phiên bản trước,
  • nó có thể là tất cả những thay đổi kể từ khi cam kết cuối cùng,
  • nó có thể là thay đổi kể từ 3 cam kết trước hoặc
  • nó có thể chỉ là một cam kết cụ thể.
  • Người dùng có thể muốn tập hợp con reversions như vậy để chỉ các tập tin cụ thể,

(eg revertdocumented here, nhưng tôi không chắc chắn nó là một phần của phân phối hiện tại của ví dụ mặc dù)

nhưng tất cả đều được chuyển thành "hoàn nguyên thay đổi" ở cuối.

eg revert --since HEAD~3 # Undo all changes since HEAD~3 
eg revert --in HEAD~8  # much like git revert HEAD~8, but nocommit by default 
eg revert --since HEAD foo.py # Undo changes to foo.py since last commit 
eg revert foo.py    # Same as above 
eg revert --in trial~7 bar.c baz. # Undo changes made in trial~7 to bar.[ch] 

Là những loại "quay trở lại dữ liệu" thực sự rất khác nhau mà ở đó nên cần phải có các lệnh khác nhau, hoặc là một số trong những hoạt động không cần được hỗ trợ bởi các lệnh Revert đơn giản?
Chắc chắn, hầu hết người dùng hầu như chắc chắn sẽ sử dụng biểu mẫu "eg revert FILE1 FILE2..." , nhưng tôi không thấy tác hại trong việc hỗ trợ các khả năng bổ sung.

Ngoài ra ... có điều gì cơ bản để giữ cho git cốt lõi không chấp nhận hành vi như vậy không?

Elijah

Lưu ý: cam kết theo mặc định không có ý nghĩa cho các tổng quát revert lệnh, và "git revert REVISION" sẽ lôi ra với hướng dẫn (cho người dùng để thêm cờ --Trong).


phép nói rằng bạn có, trong số 50 cam kết, 20 file bạn nhận ra rằng cũ cam kết X giới thiệu những thay đổi mà không nên xảy ra.
Một chút ống nước theo thứ tự.
gì bạn cần là một cách để liệt kê tất cả các tập tin cụ thể mà bạn cần phải trở
(như trong "để hủy bỏ những thay đổi được thực hiện trong phạm X trong khi vẫn giữ tất cả các thay đổi tiếp theo"),
và sau đó, đối với mỗi của họ:

git-merge-file -p a.py X X^ 

Vấn đề ở đây là khôi phục chức năng bị mất mà không làm mất tất cả các thay đổi tiếp theo trong một bạn có thể muốn giữ lại.
Kỹ thuật đó đôi khi được gọi là "hợp nhất âm".

Kể từ git merge-file <current-file> <base-file> <other-file>means:
kết hợp tất cả những thay đổi mà dẫn từ <base-file>-<other-file> vào <current-file>, bạn có thể khôi phục chức năng xóa bằng cách nói bạn muốn kết hợp tất cả thay đổi)

    .
  • từ: X (nơi chức năng đã bị xóa)
  • tới: X^(lần commit trước đó trước khi X, nơi mà các chức năng vẫn còn đó)

Lưu ý: '-p' luận cho phép bạn xem trước những thay đổi mà không cần làm gì cả trên file hiện hành. Khi bạn chắc chắn, hãy xóa tùy chọn đó.

Note: các git merge-filenot that simple: bạn không thể tham khảo các phiên bản trước của tập tin chỉ như thế.
(bạn sẽ phải lặp đi lặp thông điệp bực bội: error: Could not stat X)
Bạn cần phải:

git cat-file blob a.py > tmp/ori # current file before any modification 
git cat-file blob HEAD~2:a.py > tmp/X # file with the function deleted 
git cat-file blob HEAD~3:a.py > tmp/F # file with the function which was still there 

git merge-file a.py tmp/X tmp/F # basically a RCS-style merge 
           # note the inversed commit order: X as based, then F 
           # that is why is is a "negative merge" 
diff -u a.py tmp/ori # eyeball the merge result 
git add a.py 
git commit -m "function restored" # and any other changes made from X are preserved! 

Nếu đây là phải làm cho một số lượng lớn các tập tin trong một trước cam kết ... một số kịch bản là theo thứ tự;)

+0

Tôi không nghĩ bạn cần dấu gạch ngang trong: 'git checkout ' – Paul

5

để phục hồi các thay đổi chỉ có một tập tin trong một cam kết, như VonC chỉ ra, tôi sẽ checkout chi nhánh (thạc sĩ hoặc thân cây hoặc bất cứ điều gì) và sau đó checkout phiên bản của tập tin tôi muốn hoàn nguyên và t reat nó như là một cam kết mới:

$ git checkout trunk 
$ git checkout 4f4k2a^ a.py 
$ git add a.py 
$ git diff    #verify I'm only changing what I want; edit as needed 
$ git commit -m 'recover function deleted from a.py in 4f4k2a' 

Có lẽ một lệnh hệ thống ống nước sẽ làm điều này trực tiếp, nhưng tôi sẽ không sử dụng nó nếu tôi biết điều đó. Nó không phải là tôi không tin tưởng Git, nhưng tôi không tin tưởng bản thân mình - tôi sẽ không tin tưởng rằng tôi biết mà không nhìn những gì đã được thay đổi trong tập tin đó trong cam kết đó và kể từ đó. Và một khi tôi nhìn, nó dễ dàng hơn để xây dựng một cam kết mới bằng cách chỉnh sửa diff. Có lẽ đó chỉ là phong cách làm việc cá nhân.

+1

Hai chú thích: 1/nếu hàm đã bị xóa trong cam kết 4f4k2a cho a.py, bạn không nên checkout a.py từ * commit trước đó *? (một * trước * 4f4k2a, như trong 4f4k2a ^?) 2/Điều đó sẽ không xóa hoàn toàn phiên bản hiện tại của a.py? Nếu tôi muốn giữ các thay đổi tiếp theo thì sao? – VonC

+0

Tôi muốn tạo "hợp nhất âm" với git-merge-file: xem câu trả lời đã hoàn thành – VonC

+0

1) Có. Cảm ơn bạn đã sửa lỗi đánh máy khác. 2) Có - Đó là lý do tại sao tôi phải xem sự khác biệt. Tôi thực sự sử dụng một diffmerge bị tấn công trong chế độ hợp nhất 3 chiều, cho tôi thấy một sự khác biệt hữu ích hơn mà tôi đã từng làm việc với, nhưng git diff có thể sử dụng được. Vấn đề là: Tôi chỉ tự tin nếu tôi đã nhìn vào mã. – Paul

1

Hãy xem this git revert question. Có vẻ như đã xảy ra sự cố khi hoàn nguyên các cam kết cũ hơn nếu không có trong chuỗi liên tiếp bao gồm cả lần commit gần đây nhất.

+0

Việc bỏ phiếu vì điều này hữu ích, nhưng nó thực sự phải là một nhận xét chứ không phải là câu trả lời. – tripleee

Các vấn đề liên quan