2010-09-15 31 views
9

git rebase không hoạt động bình thường trong một số trường hợp nhất định tệp được thêm vào kho lưu trữ, sau đó bị xóa khỏi kho lưu trữ, sau đó được thêm vào thư mục làm việc (chứ không phải kho lưu trữ).git rebase, "sẽ bị ghi đè" và "Không thay đổi - bạn đã quên sử dụng 'git add' chưa?"

Dưới đây là một mô tả cụ thể hơn về vấn đề của tôi:

  • nếu một chi nhánh được tạo ra và chuyển sang từ một số thân cây,

  • và một tập tin X được thêm vào và cam kết tại các chi nhánh ,

  • và sau đó X bị xóa và cam kết trong chi nhánh,

  • và X là một lần nữa tạo ra trong thư mục làm việc, nhưng không được thêm hoặc cam,

  • và chi nhánh thân cây tiến bộ,

  • sau đó

  • một rebase thực hiện bằng cách sử dụng tiên tiến thân cây làm cơ sở sẽ không thành công vì nó sẽ từ chối ghi đè X,

  • và rebas e không thể được tiếp tục ngay cả khi thư mục hoạt động X bị xóa hoặc di chuyển ra khỏi đường.

Dưới đây là một kịch bản để tái tạo vấn đề của tôi trên dòng lệnh:

git init 
echo foo > foo.txt 
git add . 
git commit -m 'foo' 
echo foo >> foo.txt 
git add . 
git commit -m 'foo foo' 
git checkout -b topic HEAD^ 
git log 
echo bar > bar.txt 
echo baz > baz.txt 
git add . 
git commit -m 'bar baz' 
git rm bar.txt 
git commit -m '-bar' 
echo bar > bar.txt 
git rebase master 
# the following output is emitted: 
# First, rewinding head to replay your work on top of it... 
# Applying: bar baz 
# Using index info to reconstruct a base tree... 
# Falling back to patching base and 3-way merge... 
# error: Untracked working tree file 'bar.txt' would be overwritten by merge. Aborting 
# Failed to merge in the changes. 
# Patch failed at 0001 bar baz 
# 
# When you have resolved this problem run "git rebase --continue". 
rm bar.txt 
git rebase --continue 
# the following output is emitted: 
# Applying: bar baz 
# No changes - did you forget to use 'git add'? 
# 
# When you have resolved this problem run "git rebase --continue". 
# If you would prefer to skip this patch, instead run "git rebase --skip". 
# To restore the original branch and stop rebasing run "git rebase --abort". 

Tôi biết tôi có thể hủy bỏ rebase sử dụng git rebase --abort, loại bỏ bar.txt, và sau đó git rebase master một lần nữa. Nhưng làm thế nào tôi có thể tiếp tục việc rebase mà không hủy bỏ nó trước?

Trả lời

4

Tôi đã tìm thấy giải pháp: áp dụng bản vá lỗi cam kết gặp khó khăn theo cách thủ công và thêm vào chỉ mục.

$ patch -p1 < .git/rebase-apply/patch 
patching file bar.txt 
patching file baz.txt 
$ git add bar.txt baz.txt 
$ git rebase --continue 
Applying: bar baz 
Applying: -bar 
+1

Tôi đề nghị sử dụng 'git-apply' vì' patch' không hỗ trợ định dạng khác biệt nhị phân Git. –

2

Bạn cần phải cam kết trước khi thử rebase. Nó sẽ làm việc đôi khi nếu bạn không, nhưng bạn không nên làm điều đó.

Nếu bạn không thoải mái cam kết vì một lý do nào đó, bạn ít nhất có thể sử dụng stash (gần giống như vậy).

+0

Được rồi, nhưng nếu trường hợp đó thì thông báo lỗi tôi nhận được vô cùng hữu ích, vì nó ngụ ý rằng có thể tiếp tục việc rebase. –

+0

@Russell Silva: Bạn có thể tiếp tục. Vấn đề là, vì bạn đã xóa 'bar.txt',' rebase' không có việc phải làm trong cam kết đó. 'git rebase --skip' sẽ giải quyết vấn đề, vì bây giờ bạn muốn bỏ qua commit (trống). Đó là một chút bối rối và tôi ngạc nhiên 'git rebase' thậm chí cho phép bạn tiến hành với một cây làm việc bẩn, nhưng sau đó một lần nữa,' git rebase' không dành cho những người yếu tim. – mipadi

+0

@mipadi: Cam kết không trống. Trong ví dụ, 'baz.txt' được thêm vào bởi cùng một commit cho biết thêm' bar.txt'. 'git rebase --skip' làm mất' baz.txt'. –

0

Để GIT tiến hành rebase sau khi xóa tệp, tôi đã thêm thay đổi khoảng trắng và sau đó "git add" tệp với thay đổi đó.

2

git rebase hoạt động chính xác. Nó đang bảo vệ tập tin không được bảo vệ của bạn khỏi bị phá hủy trong khi truy cập vào một cam kết muốn viết ra một tập tin với cùng một tên đường dẫn đó.

Có vẻ như không phải là cách để thử lại chỉ là bước gần đây nhất của quá trình rebase. Thông thường khi một rebase tạm dừng, nó sẽ để lại xung đột trong chỉ mục. Nhưng trong trường hợp này, nó không thể gắn cờ vấn đề này trong chỉ mục vì làm như vậy sẽ chuyển đổi tập tin không được theo dõi của bạn thành một tệp được theo dõi. Đây có lẽ là một chút của một điểm thô trong giao diện người dùng của git rebase.Bạn có thể khai thác vào thư mục mà nó sử dụng để lưu trữ trạng thái bên trong của nó (.git/rebase-apply) và áp dụng bản vá "hiện tại" theo cách thủ công, nhưng việc hủy bỏ và khởi động lại có thể dễ dàng hơn (nhưng có thể không nhanh hơn nếu bạn đang trong quá trình rebasing một chuỗi rất dài) .


Nếu việc bổ sung các bar.txt được coi là một sai lầm, sau đó bạn có thể xem xét sử dụng git rebase -i trêu chọc nhau và thả việc bổ sung và loại bỏ các bar.txt kể từ khi bạn đang viết lại lịch sử anyway.
Bạn sẽ vẫn gặp phải xung đột, nhưng các phương pháp bên dưới cũng có thể được áp dụng với git rebase -i. Kịch bản cuối cùng sẽ phải được chia thành hai phần (“thiết lập temp/” và “kết hợp kết quả rebase” vì một rebase tương tác thường sẽ đòi hỏi nhiều lệnh giữa hai phần.


Move tập tin mâu thuẫn sang một bên tạm thời và làm lại rebase.

mv bar.txt +bar.txt 
git rebase --abort 
git rebase master 

Nếu bạn mong đợi nhiều file mâu thuẫn như vậy thì bạn có thể xem xét việc làm rebase của bạn trong một bản sao riêng biệt, nơi bạn có thể chắc chắn rằng bạn sẽ không có bất kỳ tập tin được theo dõi. có lẽ một phần khó khăn nhất là kiểm tra xem các tệp không được theo dõi của bạn không xung đột với kết quả của t anh ta rebase (số git checkout rebased-topic hoàn thành điều này; nó hủy bỏ nếu các tập tin không được theo dõi xung đột với kết quả rebase).

: "Note: will destroy 
:  * 'rebased-topic' branch 
:  * 'temp' directory" 
(set -x && 
    : '*** Clearing temp/' && 
    rm -rf temp/ && 

    : '*** Making sure we have topic checked out' && 
    git checkout topic 

    : '*** Cloning into temp/' && 
    git clone . temp && 

    : '*** Rebasing topic onto master in temp/ clone' && 
    (cd temp && 
    git rebase origin/master 
) && 

    : '*** Fetching rebase result from topic/ into local rebased-topic branch' && 
    git fetch -f temp topic:rebased-topic && 

    : '*** Checking rebased-topic for conflicts with untracked files' && 
    git checkout rebased-topic && 

    : '*** Resetting topic to tip of rebased-topic' && 
    git branch -f topic rebased-topic && 

    : '*** Returning to topic branch' && 
    git checkout topic && 

    : '*** Deleting rebased-topic branch' && 
    git branch -d rebased-topic && 

    : '*** Deleting temp/' && 
    rm -rf temp/ 
) 
+0

Trong trường hợp của tôi, lý do duy nhất mà tập tin bị hủy là do quá trình tua lại được khôi phục. Không nên tua lại xóa các tệp không được theo dõi trong các cam kết trước đó? Sẽ không có mất dữ liệu. – Shannon

+0

@ rehevkor5: Tôi không chắc chắn về các chi tiết của tình huống của bạn, nhưng nếu (ví dụ) bạn có cam kết tuần tự A, B, C và D, nơi chỉ có lần cuối cùng có tệp 'frob' (nghĩa là ban đầu nó được thêm vào trong D và không có nơi nào khác), sau đó Git * sẽ * (tạm thời) loại bỏ 'frob' trong khi tua lại để rebase D lên một số base khác (ví dụ: B đã sửa đổi). Tình hình của câu hỏi này phức tạp hơn một chút; nếu bạn có một số tình huống cụ thể trong tâm trí, bạn có thể muốn mở một câu hỏi mới với các chi tiết. –

0

Điều này đã xảy ra với tôi và một số thành viên trong nhóm nhiều lần ... Thông thường khi làm việc trên cùng chi nhánh và cam kết thường xuyên.

Chúng tôi sử dụng SmartGit cho khách hàng của mình và điều xảy ra là mặc dù SmartGit hiển thị repo sạch, git status hiển thị một số tệp ngẫu nhiên đã được sửa đổi.

Tôi chỉ gặp lại vấn đề này và thấy rằng git checkout . đã khắc phục sự cố cho tôi. Nó loại bỏ những 'thay đổi cục bộ vô hình' này và cho phép tôi tiếp tục kéo (và xóa bỏ các cam kết gửi đi của tôi).

Tôi quyết định viết xuống đây để tham khảo trong tương lai. Ofc, tôi cho rằng bạn đã cam kết những thay đổi có chủ ý của mình, và bạn ổn với việc loại bỏ những thứ không mong muốn. Nếu đúng như vậy, một git checkout . nên (hy vọng) làm điều đó.

Chúc mừng

Các vấn đề liên quan