2011-01-25 33 views
96

Tôi muốn hoàn nguyên một cam kết cụ thể trong git. Thật không may, tổ chức của chúng tôi vẫn sử dụng CVS như một tiêu chuẩn, vì vậy khi tôi cam kết trở lại CVS, nhiều cam kết git được cuộn thành một. Trong trường hợp này, tôi rất thích tách ra cam kết git ban đầu, nhưng điều đó là không thể.Hoàn nguyên một phần của cam kết với git

Có cách tiếp cận tương tự như git add --patch cho phép tôi chỉnh sửa chọn lọc các khác biệt để quyết định phần nào của cam kết hoàn nguyên không?

+0

Các giải pháp khác [ở đây] (http://stackoverflow.com/q/5669358/470844), nhưng tập trung giới hạn một phần hoàn nguyên về các tệp cụ thể. – ntc2

Trả lời

160

Sử dụng tùy chọn --no-commit (-n) để git revert, sau đó unstage những thay đổi, sau đó sử dụng git add --patch:

$ git revert -n $bad_commit # Revert the commit, but don't commit the changes 
$ git reset HEAD .    # Unstage the changes 
$ git add --patch .   # Add whatever changes you want 
$ git commit     # Commit those changes 

Lưu ý: Các tập tin bạn thêm sử dụng git add --patch là những dữ liệu mà bạn muốn phục hồi, không phải các tệp bạn muốn giữ.

+12

Có thể đáng giá thêm lệnh cuối cùng cần thiết, cho những người không quen thuộc với git: sau khi cam kết, 'git reset --hard' để loại bỏ các thay đổi khác mà bạn không muốn hoàn nguyên. – tremby

+10

'git reset --hard' là nguy hiểm đối với người mới, vì nó có thể mất các chỉnh sửa. Thay vào đó được sử dụng để 'git status', gợi ý này cho' git checkout - FILE..' để hoàn nguyên mọi thứ một cách an toàn hơn. – Tino

+0

Sự thiếu sót trong git'; 'git revert' chỉ cần tham số' --patch'. – Kaz

1

Bạn có thể sử dụng git-revert -n, sau đó sử dụng add --patch để chọn các khối.

32

Tôi đã sử dụng thành công sau.

Trước hết hãy hoàn nguyên cam kết đầy đủ (đặt nó vào chỉ mục) nhưng không cam kết.

git revert -n <sha1> # -n is short for --no-commit 

Sau đó, một cách tương tác xóa các thay đổi TỐT quay trở từ chỉ số

git reset -p   # -p is short for --patch 

Sau đó cam kết diff ngược những thay đổi xấu

git commit -m "Partially revert <sha1>..." 

Cuối cùng những thay đổi TỐT nhượng lại (đã được unstaged bởi lệnh reset) vẫn còn trong cây đang hoạt động. Họ cần phải được làm sạch. Nếu không có thay đổi không bị giam khác còn lại trong cây làm việc, điều này có thể được thực hiện bằng

git reset --hard 
+5

Đây có phải là một giải pháp thay thế cho câu trả lời được chấp nhận (sử dụng 'reset HEAD''), vì nó không yêu cầu dọn dẹp thư mục làm việc cuối cùng? –

+2

Câu trả lời này vượt trội hơn, vì 'reset -p' ngắn hơn' reset HEAD' theo sau là 'add -p'. Nhưng nó vẫn yêu cầu dọn dẹp, vì những "hunks" tốt đã được thiết lập lại vẫn còn trong thư mục làm việc sau khi commit. –

+0

Câu trả lời này không cao hơn vì việc loại bỏ các thay đổi bạn ** muốn ** thường gây nhầm lẫn và dễ xảy ra lỗi --- đặc biệt nếu có yêu cầu chỉnh sửa. – Kaz

4

Giải pháp:

git revert --no-commit <commit hash> 
git reset -p  # every time choose 'y' if you want keep the change, otherwise choose 'n' 
git commit -m "Revert ..." 
git checkout -- . # Don't forget to use it. 
+0

Nó sẽ giúp mọi người nếu bạn nói nó khác với giải pháp được chấp nhận như thế nào – CharlesB

+1

@Krzysztof Tại sao việc thanh toán ở phần cuối quan trọng và tại sao giải pháp này khác với giải pháp của user1338062? – martin

3

Cá nhân, tôi thích phiên bản này, mà tái sử dụng được thông báo tự động tạo ra cam kết và đưa ra người dùng có cơ hội chỉnh sửa và dán từ "một phần" vào trước khi cuối cùng cam kết.

# generate a revert commit 
# note the hash printed to console on success 
git revert --no-edit <hash to revert> 

# undo that commit, but not its changes to the working tree 
# (reset index to commit-before-last; that is, one graph entry up from HEAD) 
git reset HEAD~1 

# interactively add reversions 
git add -p 

# commit with pre-filled message 
git commit -c <hash from revert commit, printed to console after first command> 

# reset the rest of the current directory's working tree to match git 
# this will reapply the excluded parts of the reversion to the working tree 
# you may need to change the paths to be checked out 
# be careful not to accidentally overwrite unsaved work 
git checkout -- . 
Các vấn đề liên quan