Làm thế nào để đảo ngược áp dụng một stash?


233

Tôi có một bản vá nhỏ được lưu trong stit git của tôi. Tôi đã áp dụng nó cho bản sao làm việc của tôi bằng cách sử dụng git stash apply. Bây giờ, tôi muốn sao lưu những thay đổi đó bằng cách áp dụng ngược lại bản vá (giống như những gì git revertsẽ làm nhưng chống lại stash).

Có ai biết cách để làm điều này không?

Làm rõ: Có những thay đổi khác trong bản sao làm việc của tôi. Trường hợp cụ thể của tôi là khó để mô tả nhưng bạn có thể tưởng tượng một số mã gỡ lỗi hoặc thử nghiệm trong stash. Bây giờ nó được trộn lẫn trong bản sao làm việc của tôi với một số thay đổi khác và tôi muốn thấy hiệu ứng có và không có thay đổi từ bản gốc.

Hiện tại có vẻ như stash không hỗ trợ điều này, nhưng đây git stash apply --reversesẽ là một tính năng hay.


1
Không thể chỉ tạo một bản vá đảo ngược bằng cách khác nhau giữa sửa đổi hiện tại và trước đây? Rồi áp dụng cái đó?
ralphtheninja

Có những thay đổi trong cây làm việc khác với stash được áp dụng không?
Greg Bacon

Thêm điều này vào đây, ... được cho là Câu hỏi thường gặp không phải là câu hỏi ... stackoverflow.com/questions/59973103/ mẹo
Don Thomas Boyle

Câu trả lời:


188

Theo trang chủ git-stash , "Stash được biểu diễn dưới dạng một xác nhận có cây ghi lại trạng thái của thư mục làm việc và cha mẹ đầu tiên của nó là cam kết HEADkhi stash được tạo ra" và git stash show -pcung cấp cho chúng ta "những thay đổi được ghi lại trong stash như là một khác biệt giữa trạng thái stash và cha mẹ ban đầu của nó.

Để giữ nguyên các thay đổi khác của bạn, hãy sử dụng git stash show -p | patch --reversenhư sau:

$ git init
Initialized empty Git repository in /tmp/repo/.git/

$ echo Hello, world >messages

$ git add messages

$ git commit -am 'Initial commit'
[master (root-commit)]: created 1ff2478: "Initial commit"
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 messages

$ echo Hello again >>messages

$ git stash

$ git status
# On branch master
nothing to commit (working directory clean)

$ git stash apply
# On branch master
# 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:   messages
#
no changes added to commit (use "git add" and/or "git commit -a")

$ echo Howdy all >>messages

$ git diff
diff --git a/messages b/messages
index a5c1966..eade523 100644
--- a/messages
+++ b/messages
@@ -1 +1,3 @@
 Hello, world
+Hello again
+Howdy all

$ git stash show -p | patch --reverse
patching file messages
Hunk #1 succeeded at 1 with fuzz 1.

$ git diff
diff --git a/messages b/messages
index a5c1966..364fc91 100644
--- a/messages
+++ b/messages
@@ -1 +1,2 @@
 Hello, world
+Howdy all

Biên tập:

Một cải tiến nhẹ cho điều này là sử dụng git applythay thế cho bản vá:

git stash show -p | git apply --reverse

Ngoài ra, bạn cũng có thể sử dụng git apply -Rnhư một tốc ký git apply --reverse.

Gần đây tôi đã tìm thấy thứ này rất tiện dụng ...


2
Thật sự cảm ơn. Có vẻ như đây có thể là một tính năng hay cho stash.
Pat Notz

5
Vâng, git apply -Rlà một sự cải tiến, ít nhất là đối với tôi trên hộp windows của tôi với git bash vì patch --reversecó vấn đề trong việc xác định vị trí tệp để vá (không có manh mối thực sự tại sao giải pháp thay thế hoạt động). +1 và giải thích tốt
hakre

Sẽ tốt hơn nếu thêm --indexnhư thế này git stash show -p | git apply --reverse --index. Bởi vì bạn không còn cần phải thêm vào chỉ mục những thay đổi được hoàn nguyên.
theUn Unknown777

3
@Greg Bacon, này, tôi đã cố gắng xem qua kịch bản mà bạn đã phác thảo, nhưng bản vá không thành công khi tôi chạy git stash show -p | git apply -R -vvới thông báo : Checking patch messages... error: while searching for: Hello, world Hello again error: patch failed: messages:1. Bạn có biết những gì có thể sai?
Max Koretskyi

5
Tôi gặp lỗi: patch không thành công: /src/filename.java:46 error: src / filename.java patch không áp dụng
Tim Boland

83

git stash[save]đưa trạng thái thư mục làm việc của bạn và trạng thái chỉ mục của bạn và bỏ chúng đi, đặt chỉ mục và vùng làm việc thành HEADphiên bản.

git stash applymang lại những thay đổi đó, vì vậy git reset --hardsẽ loại bỏ chúng một lần nữa.

git stash popmang lại những thay đổi đó và loại bỏ thay đổi được lưu trữ hàng đầu, do đó git stash [save]sẽ trở về trạng thái trước đó (pre-pop) trong trường hợp này.



22

Trang git man V1 có một tài liệu tham khảo về việc không áp dụng stash. Đoạn trích dưới đây.

Trang git man V2 mới hơn không bao gồm bất kỳ tài liệu tham khảo nào về việc không áp dụng stash nhưng bên dưới vẫn hoạt động tốt

Hủy áp dụng Stash Trong một số trường hợp sử dụng, bạn có thể muốn áp dụng các thay đổi được lưu, thực hiện một số công việc, nhưng sau đó bỏ áp dụng những thay đổi ban đầu xuất phát từ stash. Git không cung cấp lệnh stash un-application như vậy, nhưng có thể đạt được hiệu quả bằng cách lấy ra bản vá liên quan đến stash và áp dụng ngược lại:

$ git stash show -p stash@{0} | git apply -R

Một lần nữa, nếu bạn không chỉ định stash, Git giả định stash gần đây nhất:

$ git stash show -p | git apply -R

Bạn có thể muốn tạo một bí danh và thêm hiệu quả một lệnh stash-unapply vào Git của bạn. Ví dụ:

$ git config --global alias.stash-unapply '!git stash show -p | git apply -R'
$ git stash apply
$ #... work work work
$ git stash-unapply

1
Vì bất kỳ lý do gì, phần hữu ích này mà bạn đã liên kết "Không áp dụng Stash" đã bị xóa khỏi phiên bản thứ 2 - Phiên bản mới nhất ngay bây giờ là 2.1.146, 2019-04-15- của cuốn sách này V2- Git Tools - Stashing and Cleaning . Có thể là do các tác giả nghĩ rằng có một cách tốt hơn để làm điều này mà tôi dường như không thể tìm thấy.
Nad Alaba

@NadAlaba cảm ơn vì đã ngẩng cao đầu, đã cập nhật câu trả lời để ghi chú về sự khác biệt giữa v1 và v2 ... kỳ lạ là các tác giả git đã xóa phần về việc không áp dụng stash
Choco Smith

13

Điều này đã quá lâu, nhưng nếu tôi giải thích vấn đề một cách chính xác, tôi đã tìm thấy một giải pháp đơn giản, lưu ý, đây là một lời giải thích theo thuật ngữ của riêng tôi:

git stash [save] sẽ lưu lại các thay đổi hiện tại và đặt chi nhánh hiện tại của bạn về "trạng thái sạch"

git stash list đưa ra một cái gì đó như: stash@{0}: On develop: saved testing-stuff

git apply stash@{0}sẽ thiết lập chi nhánh hiện tại như trước stash [save]

git checkout .Sẽ đặt chi nhánh hiện tại như sau stash [save]

Mã được lưu trong stash không bị mất, nó có thể được tìm thấy bởi git apply stash@{0} một lần nữa.

Dù sao, điều này làm việc cho tôi!


Để chắc chắn, tôi đã áp dụng git stash apply --reverseđầu tiên và sau đó chỉ đơn giản là quay lại git stash apply stash@{x}như bạn đề cập. Làm việc không có vấn đề.
Carlos Garcia

3

Làm thế nào để đảo ngược áp dụng một stash?

Ngoài những gì người khác đã đề cập, cách dễ nhất là trước tiên làm

git reset HEAD

và sau đó kiểm tra tất cả các thay đổi cục bộ

git checkout . 

Đây là cách dễ nhất miễn là bạn hoàn toàn không có công việc địa phương nào bạn muốn lưu. Nếu bạn đã áp dụng sai stash cho một nhánh hoặc nhấn các xung đột hợp nhất mà bạn không muốn giải quyết, đây là cách nhanh chóng và dễ dàng để hoàn tác nó bằng cách hoàn toàn thiết lập lại công việc của bạn với cam kết mới nhất của chi nhánh.
Shadoninja

2

Ngoài câu trả lời @Greg Bacon, trong trường hợp các tệp nhị phân đã được thêm vào chỉ mục và là một phần của stash bằng cách sử dụng

git stash show -p | git apply --reverse

có thể dẫn đến

error: cannot apply binary patch to '<YOUR_NEW_FILE>' without full index line
error: <YOUR_NEW_FILE>: patch does not apply

Thêm --binarygiải quyết vấn đề, nhưng tiếc là chưa tìm ra lý do tại sao.

 git stash show -p --binary | git apply --reverse

1

Bạn có thể theo dõi hình ảnh tôi đã chia sẻ để unstash nếu bạn vô tình gõ nhẹ vào stashing.


0

Điều này ngoài các câu trả lời ở trên, nhưng thêm tìm kiếm cho git stash dựa trên thông báo vì số stash có thể thay đổi khi lưu trữ mới. Tôi đã viết một vài hàm bash:

apply(){
  if [ "$1" ]; then
    git stash apply `git stash list | grep -oPm1 "(.*)(?=:.*:.*$1.*)"`
  fi
}
remove(){
  if [ "$1" ]; then
    git stash show -p `git stash list | grep -oPm1 "(.*)(?=:.*:.*$1.*)"` | git apply -R
    git status
  fi
}
  1. Tạo stash với tên (tin nhắn) $ git stash save "my stash"
  2. Để tên $ apply "my stash"
  3. Để loại bỏ stash được đặt tên $ remove "my stash"
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.