Hoàn nguyên một phần của cam kết với git


142

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 làm tiêu chuẩn, vì vậy khi tôi cam kết trở lại CVS, nhiều cam kết git được đưa vào một. Trong trường hợp này, tôi rất thích sử dụng cam kết git ban đầu, nhưng điều đó là không thể.

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


Nhiều giải pháp hơn ở đây , nhưng tập trung vào việc giới hạn một phần hoàn nguyên vào các tệp cụ thể.
ntc2

Câu trả lời:


225

Sử dụng tùy chọn --no-commit( -n) để git revert, sau đó bỏ qua các 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 bạn thêm bằng git add --patch là các tệp bạn muốn hoàn nguyên, không phải các tệp bạn muốn giữ.


13
Có thể đáng để thêm lệnh bắt buộc cuối cùng, đối với những người không quen thuộc với git: sau khi cam kết, git reset --hardloại bỏ các thay đổi khác mà bạn không muốn hoàn nguyên.
run rẩy

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

Thật là một thiếu sót trong việc git; git revertchỉ nên --patchtranh luận
Kaz

@Kaz: git revertđược sử dụng để hoàn nguyên toàn bộ cam kết. Bạn có thể sử dụng git checkout -pđể tương tác chọn bit để hoàn nguyên.
mipadi

1
Tôi cũng muốn thêm (có lẽ) rõ ràng, trước tiênlưu công việc của bạn . Hoặc là commitđầu tiên, hoặc stash, sau đó thử revert.
Felipe Alvarez

39

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

Đầu tiên hoàn nguyên cam kết đầy đủ (đặt nó trong chỉ mục) nhưng không cam kết.

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

Sau đó, tương tác loại bỏ các thay đổi TỐT được hoàn nguyên khỏi chỉ mục

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

Sau đó cam kết ngược lại các thay đổi xấu

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

Cuối cùng, các thay đổi TỐT được hoàn nguyên (đã không được thực hiện bằng lệnh đặt lại) vẫn còn trong cây làm việc. Họ cần được làm sạch. Nếu không có thay đổi không được cam kết nào khác 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 thay thế vượt trội cho câu trả lời được chấp nhận (sử dụng reset HEAD .), bởi vì nó không yêu cầu dọn dẹp cuối cùng của thư mục làm việc?
Steven Lu

2
Câu trả lời này là vượt trội, bởi vì reset -pngắn hơn reset HEADtheo sau add -p. Nhưng nó vẫn đòi hỏi phải dọn sạch, vì các hunk "tốt" đã được thiết lập lại vẫn nằm trong thư mục làm việc sau khi xác nhận.
Chiel ten Brinke

Câu trả lời này không vượt trội vì loại bỏ tương tác các thay đổi bạn muốn thường gây nhầm lẫn và dễ bị lỗi --- đặc biệt là nếu bất kỳ trong số chúng yêu cầu chỉnh sửa.
Kaz

5

Cá nhân, tôi thích phiên bản này, sử dụng lại thông điệp cam kết được tạo tự động và cung cấp cho người dùng 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 -- .

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.

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 thanh toán ở cuối lại quan trọng và tại sao giải pháp này khác với user1338062?
martin

3

Một cách khác (nếu phiên bản hiện tại của tệp của bạn không quá xa so với phiên bản bạn đang cố hoàn nguyên) là lấy hàm băm của cam kết ngay lập tức trước khi bạn muốn hoàn nguyên một phần (từ git log). Sau đó, lệnh của bạn trở thành:

$ git checkout -p <hash_preceding_commit_to_revert> -- file/you/want/to/fix.ext

Điều này không thay đổi các tệp trong cây làm việc của bạn nhưng không tạo ra các cam kết, vì vậy nếu bạn thực sự nhồi nhét, bạn có thể bắt đầu lại với git reset --hard -- file/you/want/to/fix.ext.


1

Bạn có thể sử dụng git-Revert -n, sau đó sử dụng add --patch để chọn hunk.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.