Hoàn tác một phần của những thay đổi chưa được chỉnh sửa trong git


157

Làm cách nào để hoàn tác các phần của thay đổi chưa được chỉnh sửa của tôi trong git nhưng giữ phần còn lại là không thay đổi? Cách tôi tìm ra là:

git commit --interactive
# Choose the parts I want to delete
# Commit the changes
git stash
git rebase -i master # (I am an ancestor of master)
# Delete the line of the most recent commit
git stash apply

Điều này hoạt động, nhưng sẽ tốt hơn nếu có một cái gì đó giống như git commit --interactivechỉ để hoàn nguyên các thay đổi. Phương pháp nào tốt hơn?

Câu trả lời:


264

Bạn có thể sử dụng git checkout -p, cho phép bạn chọn các khối riêng lẻ từ khác biệt giữa bản sao và chỉ mục làm việc của bạn để hoàn nguyên. Tương tự như vậy, git add -pcho phép bạn chọn các hunk để thêm vào chỉ mục và git reset -pcho phép bạn chọn các hunk riêng lẻ từ khác biệt giữa chỉ mục và HEAD để thoát ra khỏi chỉ mục.

$ git checkout -p file/to/partially/revert
# or ...
$ git checkout -p .

Nếu bạn muốn chụp nhanh kho lưu trữ git của mình trước để bảo toàn những thay đổi này trước khi hoàn nguyên chúng, tôi muốn làm:

$ git stash; git stash apply

Nếu bạn sử dụng thường xuyên, bạn có thể muốn bí danh nó:

[alias]
    checkpoint = !git stash; git stash apply

Việc hoàn nguyên các dòng hoặc dòng riêng lẻ thậm chí có thể dễ dàng hơn nếu bạn sử dụng chế độ chỉnh sửa hoặc plugin tốt, có thể cung cấp hỗ trợ cho việc chọn các dòng trực tiếp để hoàn nguyên, vì đôi khi -pcó thể hơi vụng về khi sử dụng. Tôi sử dụng Magit , chế độ Emacs rất hữu ích khi làm việc với Git. Trong Magit, bạn có thể chạy magit-status, tìm các khác biệt cho các thay đổi mà bạn muốn hoàn nguyên, chọn các dòng bạn muốn hoàn nguyên (hoặc chỉ cần đặt con trỏ lên các khối mà bạn muốn hoàn nguyên nếu bạn muốn hoàn nguyên một hunk tại một thời điểm thay vì một dòng tại một thời điểm) và nhấn kđể hoàn nguyên các dòng cụ thể đó. Tôi đánh giá cao Magit nếu bạn sử dụng Emacs.


Tôi nghĩ rằng điều này phức tạp như giải pháp ban đầu tôi đã đưa ra, nhưng tôi nghĩ giải pháp ban đầu của tôi có lợi ích là lưu các dòng bị xóa trong 30 ngày vì chúng được cam kết. Tôi nghĩ rằng có lẽ sẽ rất tốt nếu có một kịch bản shell được viết xung quanh nó.
asmeker

1
Xin lỗi, tôi chỉ nhận ra rằng git checkoutcũng có một -plá cờ, thực hiện chính xác những gì bạn đang yêu cầu trong một lệnh duy nhất. Xin lỗi cho các bước phức tạp trước đó; bạn chỉ có thể sử dụng git checkout -p. Theo như tiết kiệm, trước khi làm điều gì đó có khả năng phá hủy, tôi thường làm một git stash; git stash apply(hoặc tạo một bí danh làm điều đó git checkpointhoặc một cái gì đó) để ghi lại cây hiện tại trong một stash để tôi có thể quay lại nếu có sự cố.
Brian Campbell

Đến đó đi, đó là giải pháp! Theo như bí danh, tôi đang nghĩ một cái gì đó như thế git commit -a -m "Backup Commit" --edit; git reset HEAD^ sẽ tốt hơn, bởi vì sau đó nó sẽ không làm bẩn trạng thái stash của tôi, mà tôi có thể đang sử dụng cho thứ khác. Sau đó, miễn là bạn có SHA1, bạn có thể chọn nó trong vòng 30 ngày tới. --Edit cho phép bạn thêm thông tin vào thông điệp cam kết để hỗ trợ bạn trong việc tìm kiếm SHA1 sau nếu bạn muốn. Mặt khác, điều này sẽ làm bẩn glog reflog, vì vậy tôi đoán đó là một sự đánh đổi dựa trên những gì bạn làm.
asmeker

Bí danh điểm kiểm tra không hoạt động đối với tôi: chỉ lệnh đầu tiên được thực thi, không phải lệnh thứ hai. Điều đó thật đáng buồn, vì tôi sẽ thích nó. Tôi đang sử dụng phiên bản git 1.7.10.4.
Fabien

Có cách nào để git checkout -pkhông áp dụng các bản vá cho chỉ mục mà chỉ tạo giai đoạn cho chúng?
Lão máu

27
git diff > patchfile

Sau đó chỉnh sửa patchfile và xóa các phần bạn không muốn hoàn tác, sau đó:

patch -R < patchfile

6
Tuy nhiên, câu trả lời này đặc biệt đáng ngưỡng mộ ở sự đơn giản và dễ sử dụng. +1
tholy

Tạo ra patchfiletrông tuyệt vời trong vim và nó thực sự giúp!
Bily

Hoàn hảo. Có thể xác nhận nó cũng hoạt động trong Windows với Cygwin và Ubuntu bash cho windows.
Checo R

1
Lưu ý bạn cũng có thể sử dụng git apply -Rthay vì patch(chỉ để ở trong vương quốc của git hoặc trong trường hợp không giống như patchkhông có sẵn)
user1556435

patch: **** malformed patch at line 41: @@ -428,9 +443,9 @@ you should place your code here."
HappyFace

5

Bạn có thể làm

git checkout master -- path/to/file

Đối với mỗi tệp bạn muốn đặt lại.


Hoặc sử dụng CHÍNH thay cho chủ nếu làm việc trên một nhánh. Như đã nói trong báo cáo 'trạng thái git' (ít nhất là trong các phiên bản gần đây).
Jonathan Leffler

1

Làm thế nào về

  1. Sao lưu các tệp bị ảnh hưởng với các thay đổi từ chỉ mục
  2. sử dụng git add -pđể chỉ thêm lại những thay đổi mà bạn muốn vào chỉ mục.

1

Khi tôi chạy 'trạng thái git', nó báo:

$ git status
# On branch fr/fr.002
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   makefile
#
no changes added to commit (use "git add" and/or "git commit -a")
$

Vì vậy, để hủy các chỉnh sửa chưa được chỉnh sửa, nó bảo tôi chạy:

git checkout -- makefile

3
Tôi nghĩ rằng anh ấy đã tự hỏi về cách hoàn nguyên từng khối, không phải toàn bộ tập tin tại một thời điểm. Tất nhiên, đây là giải pháp nếu bạn chỉ cần hoàn tác tất cả các thay đổi trong một tệp.
Brian Campbell

Yup - Tôi nghi ngờ bạn đúng. Các tùy chọn 'git checkout -p' và 'git add -p' dường như là những gì bạn muốn - như bạn đã nói.
Jonathan Leffler

1

Câu trả lời của Brian Campbell làm hỏng git của tôi, phiên bản 1.9.2.msysgit.0, vì những lý do chưa biết, vì vậy cách tiếp cận của tôi là để những người đi trên sân khấu tôi muốn giữ, loại bỏ những thay đổi trong bản sao làm việc, sau đó bỏ qua.

$ git add -p
   ... select the hunks to keep
$ git checkout -- .
$ git reset HEAD .

1
Cũng có git stash -p. Bạn có thể làm git stash -p; git reset --hard; git stash pop. Điều này thực sự giống như những gì bạn đang làm ngoại trừ bạn không phải viết một thông điệp cam kết.
asmeurer

@asmeker chúc mừng. Của tôi không yêu cầu một thông điệp cam kết, nhưng nó có ý nghĩa hơn khi sử dụng stash hơn chỉ mục cho việc này.
G-Wiz

0

bạn có thể làm git checkoutvà đặt tên cho tên của các phần bạn muốn hoàn tác.

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.