2008-10-26 35 views
9

Tôi có một kho lưu trữ Git cục bộ mà tôi đã phát triển trong một vài ngày: nó có mười tám cam kết cho đến nay. Tối nay, tôi đã tạo một kho lưu trữ Github riêng tư mà tôi đã hy vọng đẩy nó vào; tuy nhiên, khi tôi làm như vậy, nó chỉ kết thúc tám trong số mười tám cam kết với Github. Tôi đã xóa repo Github và thử lại, với kết quả tương tự.Việc đẩy kho lưu trữ Git hiện có sang Github chỉ gửi khoảng một nửa số cam kết?

Bất kỳ suy nghĩ nào về lý do điều này có thể xảy ra? Tôi đã thực hiện thủ tục này trước khi không thành công vài lần, vì vậy tôi hơi bối rối.

Cập nhật: Luôn có, chỉ có nhánh chính trong repo này. Chỉ để giải quyết một vài câu trả lời đã đăng ...

Trả lời

17

Tôi đã xem xét các kho lưu trữ trong câu hỏi và đây là những gì đang xảy ra:

  • Tại một số điểm, rpj đã thực hiện git checkout [commit id]. HEAD này chỉ ở một cam kết lỏng lẻo hơn là một nhánh được công nhận. Tôi tin rằng đây là vấn đề "lủng lẳng" mà CesarB đang đề cập đến.
  • Không nhận ra vấn đề này, anh ấy tiếp tục thực hiện thay đổi và cam kết với họ, điều này đã từng thúc đẩy HEAD mỗi lần. Tuy nhiên, HEAD chỉ đang chỉ vào một chuỗi cam kết lủng lẳng, không phải ở một chi nhánh được công nhận.
  • Khi anh ta đi để đẩy những thay đổi của mình, git đẩy tất cả mọi thứ lên đến đỉnh của bậc thầy, mà chỉ là khoảng nửa chừng cây hiện tại anh ta đang ở trên.
  • Lẫn lộn xảy ra sau đó

sơ đồ này nên làm cho nó rõ ràng hơn:

    -- D -- E -- F 
       /   ^
    A -- B -- C -    | 
^  ^    HEAD 
    |   | 
remote master 

Khi ông đã cố gắng để thúc đẩy những thay đổi của mình, chỉ A qua C bị đẩy và remote chuyển lên đến C. Anh ta không thể nhận được cam kết D thông qua F để đẩy vì chúng không được tham chiếu bởi một chi nhánh đã biết.

Đây là những gì bạn nhìn thấy khi bạn đang ở trong trạng thái này:

$ git branch 
* (no branch) 
master 

Giải pháp là để di chuyển master lên đến F trong chuỗi lủng lẳng các cam kết. Đây là cách tôi đã làm nó.

  • Tạo một chi nhánh hợp pháp cho tình trạng hiện tại:

    git checkout -b tmp

    • Nhánh tmp bây giờ chỉ vào cam kết F trong sơ đồ trên
  • nhanh về phía trước master đến tmp

    git checkout master

    git merge tmp

    • master bây giờ chỉ vào cam kết F.
  • vứt bỏ chi nhánh tạm thời của bạn

    git branch -d tmp

  • Bạn hạnh phúc có thể đẩy vào kho từ xa và nó sẽ gửi tất cả các thay đổi của bạn.

+0

Cách tiếp cận này là tốt nếu bạn muốn thận trọng; nếu bạn biết * rằng việc hợp nhất sẽ chuyển tiếp nhanh, thì bạn chỉ có thể xóa và tạo lại nhánh. Xem câu trả lời của tôi. –

+0

Bạn nói đúng - nếu nó không nhanh về phía trước, bạn sẽ kết thúc với một cây hơi khác, nhưng bạn vẫn sẽ nhận được kết quả cuối cùng. Tuy nhiên, câu trả lời của bạn đơn giản hơn rất nhiều. – farktronix

+0

nó không giúp đỡ nếu bạn có dĩa –

2

Tôi cho rằng điều đầu tiên tôi sẽ làm là chạy git fsck trên kho lưu trữ địa phương của bạn để đảm bảo rằng mọi thứ đều tốt.

Tôi chưa bao giờ gặp vấn đề này trước đây và tôi không thể nghĩ ra điều gì có thể sai.

3

Kiểm tra xem bạn có đang đẩy đúng nhánh hay không và rằng các nhánh thực sự có những gì bạn nghĩ là chúng có. Đặc biệt, kiểm tra xem bạn không có HEAD tách rời, có thể khá khó hiểu nếu không được thực hiện đúng mục đích.

Cách dễ nhất để kiểm tra là sử dụng gitk --all, hiển thị đồ họa tất cả các nhánh, HEAD và hơn thế nữa.

1

Vì vậy, nó chỉ ra rằng cả hai: băm cam kết trong .git/refs/heads/master là đúng và thông tin trong .git/logs/refs/heads/master chưa hoàn thành; trong đó tôi có nghĩa là nó chỉ đi đến và bao gồm băm cam kết quy định trong .git/refs/heads/master.

Khi tôi đã sửa các tệp này (bằng tay) và được đẩy trở lại Github, mọi thứ lại trở lại. Tôi vẫn có không có ý tưởng những gì đã xảy ra để có được những thứ trong trạng thái này, nhưng tôi vui vì tôi ít nhất đã tìm ra được bản sửa lỗi.

Trong trường hợp bất kỳ ai thắc mắc: sửa lỗi .git/refs/heads/master, tôi chỉ thay thế nội dung của tệp đó bằng băm commit mới nhất (HEAD) và sửa .git/logs/refs/heads/chủ, tôi chỉ cần sao chép nội dung của .git/logs/HEAD vào .git/logs/refs/heads/master. Dễ dàng peasy ... KHÔNG.

+0

Bạn có thể có, như tôi đã đề cập trong câu trả lời của tôi, một "HEAD tách rời". Kiểm tra .git/HEAD; nếu nó KHÔNG có "ref: refs/heads/master" (hoặc một ref: line) khác, bạn có HEAD tách rời, và các commit của bạn sẽ không tới nhánh nào, chỉ với HEAD. – CesarB

+0

Và, bằng cách này, nếu bạn có một HEAD tách rời, bạn chỉ cố định các triệu chứng, và tất cả các cam kết mới của bạn sẽ tiếp tục đi đến HEAD chỉ. IIRC, cách để thoát khỏi tình huống đó là thanh toán chi nhánh ("git checkout master"), sẽ đặt HEAD để trỏ đến nhánh đó. – CesarB

1

Tôi không có danh tiếng để bình luận trực tiếp về câu trả lời trước đó CesarB, nhưng gitk --all không hoạt động trong trường hợp này bởi vì nó chỉ liệt kê ra các chi nhánh được biết đến.

gitk HEAD hiển thị vấn đề này, nhưng không hoàn toàn rõ ràng. Khẩu súng hút thuốc là master hiển thị cây cam kết thay vì ở lần commit gần đây nhất.

5

Từ Git 1.7.3 trở đi, bạn có thể làm điều này với một lệnh đơn giản:

git checkout -B master 

Việc chuyển đổi -b có nghĩa là “tạo ra chi nhánh ở đây trước khi kiểm tra nó ra” và -B là phiên bản vô điều kiện đó, “ ngay cả khi nhánh đã tồn tại - trong trường hợp đó, di chuyển nó ở đây trước khi kiểm tra nó ra ”.


Cách tiếp cận rất đơn giản để khắc phục sự cố này là chỉ cần xóa chi tiết master và tạo lại. Sau khi tất cả, các chi nhánh trong git chỉ đơn thuần là tên cho các cam kết và chi nhánh master là không có gì đặc biệt.

Vì vậy, giả định rằng các cam kết hiện nay là một trong những bạn muốn master được, bạn chỉ cần làm

git branch -D master 

để xóa các master chi nhánh hiện có, sau đó làm

git checkout -b master 

a) tạo ra một chi nhánh mới được gọi là master trỏ đến cam kết hiện tại và b) cập nhật HEAD để trỏ đến chi nhánh master. Sau đó, HEAD sẽ được đính kèm theo số master và do đó master sẽ chuyển tiếp bất cứ khi nào bạn cam kết.

+0

Phương pháp ưa thích của tôi không liên quan đến việc xóa, chỉ cần giao lại. 'git branch -f master' buộc nhánh' master' hiện tại trỏ tới 'HEAD' hiện tại của bạn, và sau đó' git checkout master' đưa bạn ra khỏi trạng thái "đang lơ lửng". – Quuxplusone

+1

@Quuxplusone: với Gits gần đây, thậm chí điều đó phức tạp hơn cần thiết: chỉ cần sử dụng 'checkout -B'. Tôi đã cập nhật câu trả lời của mình. –

0

Tôi đã gặp vấn đề tương tự này hai lần và cuối cùng đã tìm ra những gì tôi đang làm đã gây ra sự cố đó. Trong quá trình chỉnh sửa cam kết cũ với git rebase -i, thay vì gọi số git commit --amend, tôi đã gọi git commit -a bằng lực lượng thói quen, ngay lập tức theo sau là git rebase --continue, tất nhiên. Một người khác có thể giải thích những gì đang diễn ra đằng sau hậu trường, nhưng có vẻ như kết quả là vấn đề HEAD tách rời.

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