git stash blunder: git stash pop và kết thúc bằng xung đột hợp nhất


200

Tôi đã làm một git stash popvà kết thúc với xung đột hợp nhất. Tôi đã xóa các tệp khỏi hệ thống tệp và thực hiện git checkoutnhư dưới đây, nhưng nó nghĩ rằng các tệp vẫn chưa được trộn. Sau đó tôi đã thử thay thế các tập tin và thực hiện git checkoutlại và kết quả tương tự. Tôi đã cố gắng buộc nó bằng -fcờ. Bất kỳ trợ giúp sẽ được đánh giá cao!

chirag-patels-macbook-pro:haloror patelc75$ git status
app/views/layouts/_choose_patient.html.erb: needs merge
app/views/layouts/_links.html.erb: needs merge
# On branch prod-temp
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   db/schema.rb
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       unmerged:   app/views/layouts/_choose_patient.html.erb
#       unmerged:   app/views/layouts/_links.html.erb

chirag-patels-macbook-pro:haloror patelc75$ git checkout app/views/layouts/_choose_patient.html.erb
error: path 'app/views/layouts/_choose_patient.html.erb' is unmerged
chirag-patels-macbook-pro:haloror patelc75$ git checkout -f app/views/layouts/_choose_patient.html.erb
warning: path 'app/views/layouts/_choose_patient.html.erb' is unmerged

Lưu ý: khôi phục lại trạng thái trước khi các git stash apply/popnên dễ dàng hơn với Git 2,5 (Q2 2015), kể từ khi cây làm việc bây giờ cần phải được làm sạch: xem câu trả lời của tôi dưới đây
VonC

Câu trả lời:


219

Xem người đàn ông git merge ( CÁCH GIẢI QUYẾT CONFLICTS ):

Sau khi thấy một cuộc xung đột, bạn có thể làm hai điều:

  • Quyết định không hợp nhất. Việc dọn dẹp duy nhất bạn cần là đặt lại tệp chỉ mục thành cam kết CHÍNH để đảo ngược 2. và dọn sạch các thay đổi của cây làm việc được thực hiện bởi 2. và 3.; git-reset - có thể được sử dụng cho việc này.

  • Giải quyết các xung đột. Git sẽ đánh dấu các xung đột trong cây làm việc. Chỉnh sửa các tập tin thành hình dạng và git thêm chúng vào chỉ mục. Sử dụng cam kết git để đóng dấu thỏa thuận.

Và theo TRUE MERGE (để xem những gì 2. và 3. đề cập đến):

Khi không rõ ràng làm thế nào để điều hòa các thay đổi, điều sau đây xảy ra:

  1. Con trỏ CHÍNH giữ nguyên.

  2. Tham chiếu MERGE_HEAD được đặt để trỏ đến đầu chi nhánh khác.

  3. Các đường dẫn được hợp nhất sạch sẽ được cập nhật cả trong tệp chỉ mục và trong cây làm việc của bạn.

  4. ...

Vì vậy: sử dụng git reset --hardnếu bạn muốn loại bỏ các thay đổi stash khỏi cây làm việc của bạn hoặc git resetnếu bạn muốn làm sạch chỉ mục và để lại các xung đột trong cây làm việc của bạn để hợp nhất bằng tay.

Trong man git stash ( TÙY CHỌN, pop ) bạn có thể đọc thêm:

Áp dụng nhà nước có thể thất bại với xung đột; trong trường hợp này, nó không bị xóa khỏi danh sách stash. Bạn cần giải quyết xung đột bằng tay và gọi git stash drop bằng tay sau đó.


9
Trên thực tế, ngay cả sau khi bạn thả stash, vẫn có thể (mặc dù khó khăn hơn) để lấy lại, vì bộ thay đổi vẫn tồn tại trong kho lưu trữ. stackoverflow.com/search?q=git+recover+dropping+stash
phils

3
@nalply: tốt hay xấu? Bạn được hoan nghênh cải thiện câu trả lời của tôi, nơi bạn không hiểu nó ngay từ đầu ...
tanascius

1
Tôi nghĩ rằng sửa đổi mã nguồn là một vấn đề phức tạp. Nó rất dễ bị nhầm lẫn. Tôi vẫn nghĩ rằng câu trả lời của bạn là tốt bởi vì nó xác nhận lại cách tiếp cận của tôi.
nalply

1
Nó không chỉ giúp tôi rất nhiều để nhận ra rằng stash đã không bị xóa như tôi đã nghĩ, nhưng điều này giải thích tại sao stash của tôi tiếp tục phát triển ngay cả khi tôi chắc chắn rằng tôi đã không quên lấy lại mọi thứ từ nó.
Thor84no

11
"Áp dụng trạng thái có thể thất bại với xung đột; trong trường hợp này, nó không bị xóa khỏi danh sách stash." Đây là phần quan trọng nhất của bài viết, theo ý kiến ​​của tôi. Cân nhắc chỉnh sửa câu trả lời của bạn để đưa nó lên phía trước cùng với dòng chữ KHÔNG ĐƯỢC PANIC bằng chữ lớn, thân thiện. (+1 đã mặc dù.) Cảm ơn.
Patrick M

42

Tôi đã có một điều tương tự xảy ra với tôi. Tôi chưa muốn tạo các tập tin ngay bây giờ vì vậy tôi đã thêm chúng vào git addvà sau đó mới làm git reset. Điều này về cơ bản chỉ cần thêm và sau đó không thay đổi các thay đổi của tôi nhưng đã xóa các đường dẫn không được trộn lẫn.


4
Điều này có vẻ tốt hơn so với việc sử dụng reset --hardvì nó không ghi đè lên các tệp của bạn (ngoại trừ các tệp có vấn đề hợp nhất). Cảm ơn!
sinelaw

Tôi chưa muốn tạo các tệp ngay bây giờ vì vậy tôi đã thêm chúng - không phải là addnội dung giai đoạn từ cây làm việc đến chỉ mục? Tôi không nghĩ rằng tôi hiểu tại sao câu trả lời của bạn hoạt động từ mô tả.
vẽ Noakes

2
git addkhông giai đoạn họ nhưng git reset, mà tôi làm ngay sau đó, bỏ qua chúng. Về cơ bản, nó dọn sạch những con đường không được trộn lẫn và đưa tôi trở lại cây làm việc bình thường của mình bằng cách giả mạo git ra.
Aaron

3
Bạn không cần phải làm git addnhư vậy git reset. Hiệu git resetquả "hoàn tác" git add. git reset( --mixed<- mặc định) thực sự không chạm vào thư mục làm việc nên chính xác những gì trong thư mục làm việc của bạn, hợp nhất các xung đột và tất cả, chỉ còn lại một mình. Chỉ mục (và về mặt kỹ thuật là đầu chi nhánh) được đặt lại mặc dù (không có ref mà chúng được đặt lại HEAD, điều đó có nghĩa là không có thay đổi nào đối với đầu chi nhánh và hoàn tác bất kỳ git addthực hiện nào đối với chỉ mục, cũng như xóa trạng thái đường dẫn không được trộn lẫn) .
bambams

3
Trình tự , chỉnh sửa / giải quyết , git resetgit stash drophoạt động tốt. Nó làm những gì git stash popsẽ làm mà không có xung đột. Có vẻ như git addkhông cần thiết; Mặc dù nó có thể hữu ích nhưng bạn có nhiều tệp có xung đột. Khi từng được giải quyết , chúng có thể được thêm vào và git statustheo dõi chúng.
tiếng ồn vô nghĩa

13

Nếu, giống như tôi, điều bạn thường muốn là ghi đè lên nội dung của thư mục làm việc với các tệp được lưu và bạn vẫn gặp xung đột, thì điều bạn muốn là giải quyết xung đột bằng cách sử dụng git checkout --theirs -- .từ gốc.

Sau đó, bạn có thể git resetmang tất cả các thay đổi từ chỉ mục vào thư mục làm việc, vì rõ ràng trong trường hợp có xung đột, các thay đổi đối với các tệp không xung đột sẽ nằm trong chỉ mục.

Bạn cũng có thể muốn chạy git stash drop [<stash name>]sau đó, để thoát khỏi stash, vì git stash popkhông xóa nó trong trường hợp có xung đột.


2

Lưu ý rằng Git 2.5 (quý 2 năm 2015) một Git tương lai có thể cố gắng biến kịch bản đó thành không thể.

Xem cam kết ed178ef của Jeff King ( peff), ngày 22 tháng 4 năm 2015.
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết 05c3967 , ngày 19 tháng 5 năm 2015)

Lưu ý: Điều này đã được hoàn nguyên. Xem bên dưới .

stash: yêu cầu một chỉ mục sạch để áp dụng / pop

Vấn đề

Nếu bạn đã phân loại nội dung trong chỉ mục của mình và chạy " stash apply/pop", chúng tôi có thể xảy ra xung đột và đưa các mục mới vào chỉ mục.
Việc khôi phục lại trạng thái ban đầu của bạn rất khó khăn vào thời điểm đó, bởi vì các công cụ như "git reset --keep" sẽ thổi bay mọi thứ được dàn dựng .

Nói cách khác:

" git stash pop/apply" Quên để đảm bảo rằng không chỉ cây làm việc sạch mà cả chỉ số cũng sạch.
Điều thứ hai rất quan trọng vì một ứng dụng stash có thể xung đột và chỉ mục sẽ được sử dụng để giải quyết xung đột.

Giải pháp

Chúng ta có thể làm cho điều này an toàn hơn bằng cách từ chối áp dụng khi có những thay đổi theo giai đoạn.

Điều đó có nghĩa là nếu trước đây đã có sự hợp nhất vì áp dụng stash trên các tệp đã sửa đổi (đã thêm nhưng không được cam kết), thì bây giờ chúng sẽ không có bất kỳ sự hợp nhất nào vì ứng dụng / pop stash sẽ dừng ngay lập tức với:

Cannot apply stash: Your index contains uncommitted changes.

Buộc bạn phải thực hiện các thay đổi có nghĩa là, trong trường hợp hợp nhất, bạn có thể dễ dàng khôi phục trạng thái ban đầu (trước git stash apply/pop) với a git reset --hard.


Xem cam kết 1937610 (15 tháng 6 năm 2015) và cam kết ed178ef (22 tháng 4 năm 2015) của Jeff King ( peff) .
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết bfb539b , ngày 24 tháng 6 năm 2015)

Cam kết đó là một nỗ lực để cải thiện sự an toàn của việc áp dụng stash, bởi vì quy trình ứng dụng có thể tạo ra các mục chỉ mục bị xung đột, sau đó rất khó để khôi phục trạng thái chỉ mục ban đầu.

Thật không may, điều này làm tổn thương một số quy trình công việc phổ biến xung quanh " git stash -k", như:

git add -p       ;# (1) stage set of proposed changes
git stash -k     ;# (2) get rid of everything else
make test        ;# (3) make sure proposal is reasonable
git stash apply  ;# (4) restore original working tree

Nếu bạn "git commit" giữa các bước (3) và (4), thì điều này chỉ hoạt động. Tuy nhiên, nếu các bước này là một phần của hook pre-commit, bạn không có cơ hội đó (bạn phải khôi phục trạng thái ban đầu bất kể các thử nghiệm đã vượt qua hay thất bại).

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.