2012-01-25 17 views
19

Chúng tôi đã làm điều gì đó xấu.`git stash` trong một cuộc xung đột hợp nhất

Chúng tôi chạy git stash save trong khi xung đột hợp nhất và giờ chúng tôi không thể khôi phục công việc của mình.

Những điều chúng tôi đã cố gắng:

git pull -Xours origin master 
git stash apply --index 

Và:

git pull origin master 
git stash save --keep-index "merge conflicts" 
git stash apply [email protected]{1} 

Xin giúp!

+0

Bạn có thực sự làm điều gì quan trọng không? (Bạn có thực sự cần phải khôi phục các thay đổi đã lưu trữ không?) Bạn có thể chỉ cần đặt lại hợp nhất đã cố gắng và thực hiện lại không? – Cascabel

+1

Có và không, tương ứng. Các thay đổi bao gồm nhiều hơn một ngày giải quyết xung đột hợp nhất. – bukzor

+3

@bukzor: Nếu bạn cần nhiều hơn thì một ngày để giải quyết xung đột hợp nhất có thể là lúc phải suy nghĩ lại chính sách của bạn về xử lý chi nhánh và phân phối công việc (hoặc tần suất hợp nhất). Độ phân giải hợp nhất dài như vậy là sau một nguồn tốt đẹp của khó tìm lỗi do số lượng thay đổi được thực hiện trong một cam kết – Grizzly

Trả lời

0

Khi bạn ở trạng thái mâu thuẫn (chỉ mục và thư mục làm việc), bạn sẽ không thể thực hiện git stash - nó sẽ cung cấp lỗi khi tìm các mục nhập chưa được nhấn.

Hãy chắc chắn rằng bạn đã thực sự thực hiện một stash. Xem sản phẩm của git stautsgit stash show

+0

Trước 'git stash', tôi đã giải quyết các xung đột và tiến hành sử dụng' git add'. Đó là sau khi tôi có 'git add' các nghị quyết của tôi, tôi đã thực hiện các chỉnh sửa tiếp theo và sau đó thực hiện một' git stash save msg'. Vì vậy, điều đó đã thành công. –

+0

@bukzor thực sự, tôi chỉ thử nghiệm này với msysgit 1.8.3 trên Windows 7. Nếu tệp bị trái xung đột (tức là không cố gắng giải quyết xung đột hợp nhất đã được thực hiện), thì 'git stash save' thực sự hủy bỏ, mà không stashing các tập tin mâu thuẫn. Vì vậy, *** này thực sự là chính xác, nó không phải là sai ***. –

18

Vấn đề này dường như là git stash không lưu một tham chiếu đến các chi nhánh bạn đang cố gắng hợp nhất trong. Trong một hợp nhất, điều này được lưu trữ trong một ref tên MERGE_HEAD.

Để khắc phục và quay lại trạng thái trước đó, bạn cần tìm bản sửa đổi (giả sử nó là d7a9884a380f81b2fbf002442ee9c9eaf34ff68d) mà bạn đang cố hợp nhất và đặt MERGE_HEAD thành nó sau khi bạn áp dụng dấu gạch chéo.

Sau đó, bạn có thể áp dụng stash (với --index lại sân khấu tất cả những gì đã được dàn dựng trước đó), và thiết lập MERGE_HEAD của bạn:

git stash apply --index 
git update-ref MERGE_HEAD d7a9884a380f81b2fbf002442ee9c9eaf34ff68d 
+0

Trong khi ở trên có vẻ đúng với tôi, tôi không hoàn toàn tự tin rằng chỉ cần thiết lập MERGE_HEAD và unstashing là đủ để khôi phục lại tình trạng hợp nhất. Tôi sẽ tránh xa việc sử dụng git stash trong các cuộc xung đột, nếu có thể. – user1338062

+1

Tôi cũng sẽ, nhưng đó là hindsight vào thời điểm này. – bukzor

1

Với chú thích cuối cùng của bạn: bạn có thể sử dụng

git stash megre --no-commit <branch> 

để đặt chỉ mục trong một "hợp nhất" nhà nước mà không cam kết những thay đổi

sau đó sửa đổi nó với những gì bạn muốn:

nếu bạn đã làm việc ra merge của bạn trong stash:

git reset #to remove the "conflicts" flags 
git checkout <initial commit> -- ./ #to revert everything to the previous working state, 
git stash apply #apply your changes 

và một khi mọi thứ đều trong tình trạng mong muốn, git commit


Về bình luận bukzor 's: có thực sự là một lớn sự khác biệt giữa git checkout <tree-ish>git checkout <tree-ish> -- <files>.

Từ reference trên git checkout:

  • git checkout <branch>: Hình thức này chuyển sang chi nhánh bằng cách cập nhật các chỉ mục, làm việc cây, và HEAD để phản ánh các chi nhánh theo quy định hoặc cam kết.

  • git checkout [-p|--patch] <tree-ish> -- <pathspec>: Khi < đường dẫn > hoặc --patch được cung cấp, thanh toán git không chuyển nhánh. Nó cập nhật các đường dẫn có tên trong cây làm việc từ tệp chỉ mục hoặc từ một tên là < tree-ish > (thường là một cam kết).

git checkout <initial commit> thực sự sẽ hủy thông tin hợp nhất.

git checkout <initial commit> -- ./ (lưu ý thêm -- ./), mặt khác, sẽ giữ thông tin hợp nhất và hoàn nguyên mọi tệp được theo dõi về trạng thái của nó trong <initial commit>.

+0

'git checkout' sẽ xóa trạng thái hợp nhất, phải không?Tôi sẽ kết thúc với một cam kết bình thường mà dups tất cả những thay đổi trong tổng thể. – bukzor

+0

'git stash apply' cũng xóa trạng thái hợp nhất, thiết lập rõ ràng ref MERGE_HEAD như gợi ý trong câu trả lời của Evan đã thực hiện thủ thuật cho tôi –

+0

Trong git 2, không có lệnh nào như' git stash merge' :( – dcorking

1

Tôi đã làm điều tương tự ngày hôm nay, và thực hiện một cách tiếp cận khác (sau khi thử và sai) để quay lại trạng thái ngay trước khi stashing để tôi có thể tiếp tục giải quyết xung đột và hoàn thành hợp nhất.

Trước tiên, sau khi unstashing hợp nhất một phần trong nhánh đích, tôi đã chụp một danh sách các tệp có xung đột còn lại (tệp văn bản hoặc tab trình chỉnh sửa). Đây chỉ là danh sách các tập tin chưa được lưu trữ sau khi unstashing, vì các tập tin có xung đột đã được giải quyết sẽ được tổ chức trước khi stashing.

$ git status 
# Changes not staged for commit: 
# (use "git add <file>..." to update what will be committed) 
# (use "git checkout -- <file>..." to discard changes in working directory) 
# 
# modified: myproject/src/main/java/com/acme/package3/Class3.java 
# modified: myproject/src/main/java/com/acme/package3/Class4.java 
# 

Tiếp theo, tôi đã tạo ra một bản vá và thiết lập lại các chi nhánh trở về trạng thái trước khi hợp nhất:

$ git diff HEAD > ~/merge-with-resolved-conflicts.patch 
$ git reset --hard HEAD 

Sau đó, tôi đã tạo ra một chi nhánh tạm thời (có nguồn gốc từ các chi nhánh địa điểm hợp nhất), và áp dụng các miếng vá:

$ git checkout -b my-temp-branch 
$ git apply ~/merge-with-resolved-conflicts.patch 
$ git commit -a -m "Merge with resolved conflicts" 

Vì vậy, HEAD của nhánh tạm thời chứa tất cả mọi thứ đã được giải quyết và các tệp có xung đột còn lại.

Sau đó, tôi chuyển trở lại chi nhánh gốc, sáp nhập một lần nữa, và nhìn vào tình trạng git

$ git checkout my-branch 
$ git merge other-branch 
$ git status 

Các trạng thái hiển thị danh sách đầy đủ các tập tin với các cuộc xung đột:

# Unmerged paths: 
# (use "git add <file>..." to mark resolution) 
# 
# both modified:  myproject/src/main/java/com/acme/package1/Class1.java 
# both modified:  myproject/src/main/java/com/acme/package2/Class2.java 
# both modified:  myproject/src/main/java/com/acme/package3/Class3.java 
# both modified:  myproject/src/main/java/com/acme/package3/Class4.java 
# 

Bây giờ tôi cần thiết để so sánh hai danh sách tệp này. Bất kỳ tệp nào trong danh sách thứ hai nhưng không phải là tệp đầu tiên đã được giải quyết (trong ví dụ này, Class1.java và Class2.java). Vì vậy, đối với mỗi các tập tin, tôi kéo trong phiên bản với các cuộc xung đột được giải quyết từ các chi nhánh tạm thời (như cherry-pick, nhưng đối với những file riêng biệt chứ không phải là toàn bộ một cam kết):

$ git checkout my-temp-branch myproject/src/main/java/com/acme/package1/Class1.java 
$ git checkout my-temp-branch myproject/src/main/java/com/acme/package2/Class2.java 

Sau khi làm điều này, tôi đã trở lại cho nhà nước trước khi stash, vì vậy tôi có thể tiếp tục giải quyết các xung đột còn lại và cam kết hợp nhất.

0

Giải pháp của tôi để có được ra khỏi đây (stash pop git trong một cuộc xung đột nhập) là:

  • tạo và kiểm mới (địa phương) chi nhánh mytemporarybranch

    git branch mytemporarybranch & & git checkout mytemporarybranch

  • cam kết vào mytemporarybranch này

    git commit -m "merge lộn xộn của tôi và bí"

  • thanh toán myoriginalbranch

    git checkout myoriginalbranch

  • hợp nhất một cách chính xác (không bí pop/áp dụng thời gian này!)

  • hợp nhất mytemporarybranch vào chi nhánh myoriginal

    git merge --squash mytemporarybranch