Làm thế nào để phục hồi các thay đổi không được cam kết


690

Tôi đã có một số thay đổi không được cam kết trong nhánh phát triển của mình và tôi đã sử dụng chúng git stash, nhưng có một số thay đổi rất quan trọng trong số những thay đổi đó. Có cách nào để lấy lại những thay đổi đó không?

Ngoài ra, tôi đã thực hiện một số thay đổi trên đầu các tệp mã được lưu trữ kể từ đó.

Có bất kỳ cơ hội nào tôi có thể truy xuất các thay đổi được lưu trữ cho một nhánh mới nếu có thể không?


7
bạn đã thử sử dụng 'stash pop' chưa?
robert

Không. Thật ra tôi mới dùng git. Vì tôi không nhận thức đầy đủ về tất cả các lệnh nên tôi đã không thử bất cứ điều gì khác! Tôi không muốn mất những thay đổi đó.
Aswathy P Krishnan

33
Nếu bạn không muốn mất các thay đổi được lưu trữ, hãy thử sử dụng 'git stash áp dụng'. Điều này sẽ áp dụng các thay đổi được lưu trữ cho nhánh hiện tại của bạn, trong khi vẫn giữ lại stash. Nếu mọi thứ đều ổn, sau khi áp dụng stash, bạn có thể thả stash, sử dụng 'git stash drop'
robert

2
@robert Cảm ơn bạn đã trả lời đơn giản so với câu trả lời phức tạp khủng khiếp (cho một người mới) được chấp nhận.
Saheel Godhane

Câu trả lời:


1184

Câu trả lời dễ cho câu hỏi dễ là git stash apply

Chỉ cần kiểm tra chi nhánh bạn muốn thay đổi của bạn, và sau đó git stash apply. Sau đó sử dụng git diffđể xem kết quả.

Sau khi bạn hoàn thành xong các thay đổi của mình, applytrông có vẻ tốt và bạn chắc chắn rằng bạn không cần sử dụng bất kỳ loại nào nữa, sau đó sử dụng git stash dropđể loại bỏ nó.

Tôi luôn đề nghị sử dụng git stash applychứ không phải git stash pop. Sự khác biệt là để applylại stash xung quanh để dễ dàng thử lại applyhoặc để xem, v.v. Nếu popcó thể giải nén stash, nó sẽ ngay lập tức dropvà nếu bạn bất ngờ nhận ra rằng bạn muốn trích xuất nó ở đâu đó khác (trong một chi nhánh khác), hoặc với --index, hoặc một số như vậy, điều đó không dễ dàng. Nếu bạn apply, bạn có thể chọn khi nào drop.

Mặc dù vậy, tất cả đều khá nhỏ theo cách này hay cách khác, và đối với một người mới chơi git, nó cũng sẽ giống như vậy. (Và bạn có thể bỏ qua tất cả phần còn lại của điều này!)


Điều gì xảy ra nếu bạn đang làm những thứ cao cấp hơn hoặc phức tạp hơn?

Có ít nhất ba hoặc bốn "cách sử dụng git stash" khác nhau. Trên đây là "cách 1", "cách dễ dàng":

  1. Bạn đã bắt đầu với một nhánh sạch, đang thực hiện một số thay đổi và sau đó nhận ra rằng bạn đang thực hiện chúng ở nhánh sai. Bạn chỉ muốn thực hiện các thay đổi bạn có bây giờ và "chuyển" chúng sang chi nhánh khác.

    Đây là trường hợp dễ dàng, được mô tả ở trên. Chạy git stash save(hoặc đơn giản git stash, điều tương tự). Kiểm tra các chi nhánh khác và sử dụng git stash apply. Điều này được git hợp nhất trong các thay đổi trước đó của bạn, sử dụng cơ chế hợp nhất khá mạnh mẽ của git. Kiểm tra các kết quả một cách cẩn thận (với git diff) để xem bạn có thích chúng không, và nếu có, hãy sử dụng git stash dropđể thả stash. Bạn đã hoàn tất!

  2. Bạn đã bắt đầu một số thay đổi và cất giấu chúng. Sau đó, bạn chuyển sang một chi nhánh khác và bắt đầu thay đổi nhiều hơn, quên rằng bạn đã có những người bị bỏ rơi.

    Bây giờ bạn muốn giữ, hoặc thậm chí di chuyển, những thay đổi này và cũng áp dụng stash của bạn.

    Thực tế bạn có thể git stash savemột lần nữa, như git stashtạo ra một "chồng" thay đổi. Nếu bạn làm điều đó, bạn có hai stash, một cái chỉ được gọi stashlàbbut, bạn cũng có thể viết stash@{0}một và viết một lỗi chính tả stash@{1}. Sử dụng git stash list(bất cứ lúc nào) để xem tất cả. Mới nhất luôn luôn là số thấp nhất. Khi bạn git stash drop, nó thả cái mới nhất và cái được stash@{1}di chuyển lên đỉnh của ngăn xếp. Nếu bạn có nhiều hơn, cái đã stash@{2}trở thành stash@{1}, và cứ thế.

    Bạn cũng có thể applyvà sau đó droplà một stash cụ thể: git stash apply stash@{2}và như vậy. Bỏ một stash cụ thể, chỉ đổi lại những cái được đánh số cao hơn. Một lần nữa, cái không có số cũng được stash@{0}.

    Nếu bạn chất đống rất nhiều stash, nó có thể trở nên khá lộn xộn (đó là stash tôi muốn stash@{7}hay là vậy stash@{4}? Đợi đã, tôi chỉ đẩy một cái khác, bây giờ là 8 và 5?). Cá nhân tôi thích chuyển những thay đổi này sang một chi nhánh mới, bởi vì các chi nhánh có tên và cleanup-attempt-in-Decembercó ý nghĩa với tôi nhiều hơn stash@{12}. ( git stashLệnh nhận một thông báo lưu tùy chọn và những thông báo này có thể giúp ích, nhưng bằng cách nào đó, tất cả các bản sao của tôi chỉ được đặt tên WIP on branch.)

  3. (Nâng cao) Bạn đã sử dụng git stash save -p, hoặc các bit cụ thể được mã hóa cẩn thận git addvà / hoặc git rm-ed trước khi chạy git stash save. Bạn đã có một phiên bản trong khu vực chỉ mục / dàn dựng và một phiên bản (khác) trong cây làm việc. Bạn muốn bảo tồn tất cả điều này. Vì vậy, bây giờ bạn sử dụng git stash apply --indexvà đôi khi thất bại với:

    Conflicts in index.  Try without --index.
    
  4. Bạn đang sử dụng git stash save --keep-indexđể kiểm tra "những gì sẽ được cam kết". Điều này nằm ngoài phạm vi của câu trả lời này; thay vào đó, hãy xem câu trả lời StackOverflow khác .

Đối với các trường hợp phức tạp, tôi khuyên bạn nên bắt đầu trong thư mục làm việc "sạch" trước, bằng cách cam kết bất kỳ thay đổi nào bạn có ngay bây giờ (trên một nhánh mới nếu bạn muốn). Theo cách đó, "nơi nào đó" mà bạn đang áp dụng chúng, không có gì khác trong đó và bạn sẽ thử các thay đổi được lưu trữ:

git status               # see if there's anything you need to commit
                         # uh oh, there is - let's put it on a new temp branch
git checkout -b temp     # create new temp branch to save stuff
git add ...              # add (and/or remove) stuff as needed
git commit               # save first set of changes

Bây giờ bạn đang ở điểm bắt đầu "sạch". Hoặc có thể nó đi như thế này:

git status               # see if there's anything you need to commit
                         # status says "nothing to commit"
git checkout -b temp     # optional: create new branch for "apply"
git stash apply          # apply stashed changes; see below about --index

Điều chính cần nhớ là "stash" một cam kết, nó chỉ một cam kết hơi "buồn cười / kỳ lạ" không phải là "trên một nhánh". Các applyhình hoạt động vào những gì các cam kết thay đổi, và cố gắng để lặp lại nó bất cứ nơi nào bây giờ bạn đang có. Stash vẫn sẽ ở đó ( applygiữ nó xung quanh), vì vậy bạn có thể nhìn vào nó nhiều hơn, hoặc quyết định đây là vị trí sai cho applynó và thử lại theo cách khác, hoặc bất cứ điều gì.


Bất cứ khi nào bạn có một stash, bạn có thể sử dụng git stash show -pđể xem phiên bản đơn giản hóa của những gì trong stash. (Phiên bản đơn giản hóa này chỉ nhìn vào các thay đổi "cây công việc cuối cùng", chứ không phải thay đổi chỉ mục đã lưu mà --indexkhôi phục riêng.) Lệnh git stash apply, không --index, chỉ cố gắng thực hiện những thay đổi tương tự trong thư mục công việc của bạn ngay bây giờ.

Điều này đúng ngay cả khi bạn đã có một số thay đổi. Các applylệnh là hạnh phúc để áp dụng một stash để một sửa đổi thư mục làm việc (hoặc ít nhất, để cố gắng áp dụng nó). Bạn có thể, ví dụ, làm điều này:

git stash apply stash      # apply top of stash stack
git stash apply stash@{1}  # and mix in next stash stack entry too

Bạn có thể chọn thứ tự "áp dụng" tại đây, chọn ra các gói cụ thể để áp dụng theo một trình tự cụ thể. Tuy nhiên, lưu ý rằng mỗi lần về cơ bản bạn đang thực hiện "git merge" và như tài liệu hợp nhất cảnh báo:

Chạy git merge với những thay đổi không tầm thường không được khuyến khích: trong khi có thể, nó có thể khiến bạn rơi vào trạng thái khó lùi bước trong trường hợp xảy ra xung đột.

Nếu bạn bắt đầu với một thư mục sạch và chỉ đang thực hiện một số git applythao tác, thật dễ dàng để thoát ra: sử dụng git reset --hardđể quay lại trạng thái sạch và thay đổi applythao tác của bạn . (Đó là lý do tại sao tôi khuyên bạn nên bắt đầu trong một thư mục làm việc sạch trước, cho những trường hợp phức tạp này.)


Điều gì về trường hợp xấu nhất có thể xảy ra?

Giả sử bạn đang thực hiện Rất nhiều công cụ Git nâng cao và bạn đã thực hiện một cú ném và muốn git stash apply --index, nhưng không còn có thể áp dụng lưu trữ đã lưu --index, bởi vì chi nhánh đã chuyển hướng quá nhiều kể từ thời điểm bạn lưu nó.

Đây là những gì git stash branchdành cho.

Nếu bạn:

  1. kiểm tra cam kết chính xác bạn đã thực hiện khi bạn thực hiện bản gốc stash, sau đó
  2. tạo một nhánh mới và cuối cùng
  3. git stash apply --index

nỗ lực tạo lại các thay đổi chắc chắn sẽ hoạt động. Đây là những gì không. (Và sau đó nó bỏ stash kể từ khi nó được áp dụng thành công.)git stash branch newbranch


Một số từ cuối cùng về --index(cái quái gì vậy?)

Những gì --indexlàm là đơn giản để giải thích, nhưng một chút phức tạp trong nội bộ:

  • Khi bạn có thay đổi, bạn phải git add(hoặc "giai đoạn") chúng trước khi commiting.
  • Do đó, khi bạn chạy git stash, bạn có thể đã chỉnh sửa cả hai tệp foozorg, nhưng chỉ dàn dựng một trong số đó.
  • Vì vậy, khi bạn yêu cầu lấy lại stash, sẽ rất tuyệt nếu đó git addlà những addthứ ed và không phải git add là những thứ không được thêm vào. Nghĩa là, nếu bạn added foonhưng không zorgtrở lại trước khi bạn đã làm stash, nó có thể là tốt đẹp để có cùng một thiết lập chính xác. Những gì đã được dàn dựng, một lần nữa nên được dàn dựng; những gì đã được sửa đổi nhưng không được dàn dựng, một lần nữa nên được sửa đổi nhưng không được dàn dựng.

Các --indexlá cờ để applycố gắng để thiết lập những điều theo cách này. Nếu cây làm việc của bạn sạch sẽ, điều này thường chỉ hoạt động. Tuy nhiên, nếu cây công việc của bạn đã có công cụ added, bạn có thể thấy làm thế nào có thể có một số vấn đề ở đây. Nếu bạn rời khỏi --index, applyhoạt động không cố gắng duy trì toàn bộ thiết lập theo giai đoạn / không theo giai đoạn. Thay vào đó, nó chỉ gọi máy móc hợp nhất của git, sử dụng cam kết cây công việc trong "túi đựng rác" . Nếu bạn không quan tâm đến việc giữ gìn dàn dựng / không dàn dựng, việc bỏ đi sẽ --indexgiúp bạn thực hiện công việc này dễ dàng hơn rất nhiều git stash apply.


2
Tôi không hiểu bình luận của bạn. Ý bạn là: bạn đã chạy git stash pop? Hay bạn có nghĩa là: bạn đã chỉnh sửa một số tệp, nhưng chưa chạy git stashlại? Hay bạn có ý gì khác hoàn toàn?

1
Đúng. Lưu ý, trong phần chỉnh sửa (dài) của tôi, tôi khuyên bạn nên cam kết những gì bạn có bây giờ trước khi sử dụng applystash. Bạn không cần phải làm điều này, nhưng nó làm cho mọi thứ đơn giản hơn rất nhiều để bạn xem xét. Bạn có thể sử dụng rebase -iđể kết hợp nhiều lần xác nhận hoặc thay đổi cụ thể bằng cherry, hoặc bất cứ điều gì sau này.

1
Có: git stash apply --index(nhớ hai dấu gạch ngang). Nếu bạn rời khỏi --index, không có vấn đề lớn; điểm duy nhất --indexlà giữ cho thiết lập theo giai đoạn / không được dàn dựng. (Bạn có thể không có bất kỳ thiết lập đặc biệt nào ở vị trí đầu tiên.) Sau đó, git statusv.v., và thêm / cam kết như mong muốn, v.v. Khi nào (và chỉ khi nào) bạn hoàn thành với stash, hãy sử dụng git stash dropđể loại bỏ nó.

1
Miễn là bạn giữ (không drophoặc pop) stash, bạn luôn có mã gốc được lưu trữ an toàn trên một cam kết, bởi vì một stash một cam kết! Nếu bạn muốn lấy lại chính xác, nhưng trên một nhánh, hãy sử dụng git stash branch(xem phần đó ở trên hoặc sách Pro Git trong câu trả lời của Shunya ). Sau đó git checkout, bạn có thể chi nhánh đó hoặc git cherry-pickcam kết ra khỏi chi nhánh đó, v.v.

2
@ChuckWolber: Các quy ước đặt tên của Git để lại rất nhiều mong muốn (chúng ta có thể gán bao nhiêu nghĩa khác nhau cho các từ "từ xa", "theo dõi" và "chi nhánh"?!). Tuy nhiên, điều đáng chú ý là bạn có thể áp dụng một stash cho một thứ không liên quan đến stash ban đầu.

57
git stash pop

sẽ lấy lại mọi thứ

như được đề xuất trong các bình luận, bạn có thể sử dụng git stash branch newbranchđể áp dụng stash cho một nhánh mới, giống như đang chạy:

git checkout -b newbranch
git stash pop

Cảm ơn đã giúp đỡ. Tôi có thể có được những thay đổi đó thành một chi nhánh mới không? Ngay bây giờ tôi đang phát triển chi nhánh
Aswathy P Krishnan

3
git stash nhánh newbranch, sẽ tạo ra một nhánh mới với các thay đổi được lưu.
robert

3
@robert: git stash branch newbranchthực sự sẽ làm điều đó; nhưng lưu ý rằng nó tạo ra nhánh mới với phần gốc được đặt thành cam kết HEADtại thời điểm nó stashđược thực hiện. Nói cách khác, đó là khi bạn quay lại sau một phiên hack dài hoặc bất cứ điều gì, nhìn chằm chằm vào mớ hỗn độn và quyết định "Tôi nên đặt nó trên một nhánh, thay vì
đâm

Tôi đã chỉnh sửa câu hỏi của tôi. Tôi muốn có được những thay đổi cho một chi nhánh mới nếu có thể.
Aswathy P Krishnan

1
Đôi khi bạn chỉ muốn câu trả lời TLDR :)
sachinruk

24

Để làm cho điều này trở nên đơn giản, bạn có hai tùy chọn để áp dụng lại stash của mình:

  1. git stash pop - Khôi phục trở lại trạng thái đã lưu, nhưng nó sẽ xóa stash khỏi bộ lưu trữ tạm thời.
  2. git stash apply - Khôi phục trở lại trạng thái đã lưu và để lại danh sách stash để có thể sử dụng lại sau này.

Bạn có thể đọc chi tiết hơn về git stash trong bài viết này.


19

Để kiểm tra nội dung stash của bạn: -

danh sách git stash

áp dụng một stash cụ thể không có trong danh sách stash: -

git stash áp dụng stash @ {2}

hoặc chỉ áp dụng stash đầu tiên: -

git stash pop

Lưu ý: git stash pop sẽ xóa stash khỏi danh sách stash của bạn trong khi git stash sẽ không áp dụng. Vì vậy, sử dụng chúng cho phù hợp.


2

Trên mac điều này làm việc cho tôi:

danh sách git stash (xem tất cả các stash của bạn)

git stash list

git stash áp dụng (chỉ số bạn muốn từ danh sách stash của bạn)

như thế này:

git stash apply 1

0

bạn có thể bỏ qua các thay đổi không được cam kết bằng cách sử dụng "git stash" sau đó thanh toán đến một chi nhánh mới bằng cách sử dụng "git checkout -b" sau đó áp dụng các cam kết được đặt ra "git stash áp dụng"

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.