Câu hỏi Làm thế nào tôi có thể hòa giải HEAD tách rời với master / origin?


Tôi mới ở sự phức tạp phân nhánh của Git. Tôi luôn luôn làm việc trên một nhánh duy nhất và cam kết thay đổi và sau đó định kỳ đẩy đến nguồn gốc từ xa của tôi.

Một nơi nào đó gần đây, tôi đã đặt lại một số tệp để đưa chúng ra khỏi dàn dựng cam kết và sau đó đã thực hiện rebase -i để loại bỏ một vài cam kết địa phương gần đây. Bây giờ tôi đang ở trong trạng thái tôi không hiểu lắm.

Trong khu vực làm việc của tôi, git log cho thấy chính xác những gì tôi mong đợi-- Tôi đang ở trên chuyến tàu phù hợp với những cam kết mà tôi không muốn đi, và những cái mới ở đó, v.v.

Nhưng tôi chỉ cần đẩy đến kho lưu trữ từ xa, và có gì khác biệt-- một vài cam kết mà tôi đã giết trong rebase đã bị đẩy, và những cái mới cam kết cục bộ không có ở đó.

Tôi nghĩ rằng "master / origin" được tách ra khỏi HEAD, nhưng tôi không rõ 100% về ý nghĩa của nó, làm thế nào để hình dung nó với các công cụ dòng lệnh và cách sửa nó.


1275
2018-04-24 17:51


gốc


Bạn đã đẩy các cam kết trước khi rebase? - manojlds
@manojlds: Không chắc chắn ý bạn là gì. Tôi đã đẩy một chút thời gian trước khi rebase, nhưng không phải ngay trước đó. - Ben Zotto
Như trước đây bạn đã đẩy các cam kết mà bạn loại bỏ trong rebase -i .. Từ câu trả lời của bạn, tôi nghĩ rằng không. - manojlds
@manojlds: Đúng. Tôi chỉ giết những cam kết gần đây hơn là sự thúc đẩy gần đây nhất. (Mặc dù như tôi đã đề cập, tôi đã từ từ đẩy, vì tôi nghĩ mọi thứ đều ổn) - Ben Zotto
Bạn có thể giải thích những gì bạn đã làm trong I did a reset of some files to get them out of commit staging phần? xin lỗi vì câu hỏi :) - manojlds


Các câu trả lời:


Trước tiên, hãy làm rõ HEAD là gì và ý nghĩa của nó khi nó được tách ra.

HEAD là tên biểu tượng cho cam kết hiện đã được kiểm tra. Khi HEAD không bị tách rời (“bình thường”1 tình huống: bạn đã kiểm tra chi nhánh), HEAD thực sự trỏ đến “ref” của chi nhánh và chi nhánh trỏ đến cam kết. Do đó, HEAD được gắn vào một nhánh. Khi bạn thực hiện một cam kết mới, nhánh mà HEAD trỏ tới được cập nhật để trỏ đến cam kết mới. HEAD tự động theo dõi vì nó chỉ trỏ đến nhánh.

  • git symbolic-ref HEAD sản lượng refs/heads/master
    Chi nhánh có tên "chính" được chọn.
  • git rev-parse refs/heads/master năng suất 17a02998078923f2d62811326d130de991d1a95a
    Cam kết đó là mũi hiện tại hoặc “đầu” của nhánh chính.
  • git rev-parse HEAD cũng sản lượng 17a02998078923f2d62811326d130de991d1a95a
    Đây là ý nghĩa của việc trở thành một "biểu tượng ref". Nó chỉ vào một đối tượng thông qua một số tham chiếu khác.
    (Các tham chiếu tượng trưng ban đầu được thực hiện dưới dạng các liên kết tượng trưng, ​​nhưng sau đó được thay đổi thành các tệp đơn giản với cách giải thích thêm để chúng có thể được sử dụng trên các nền tảng không có liên kết tượng trưng.)

Chúng ta có HEAD → refs/heads/master → 17a02998078923f2d62811326d130de991d1a95a

Khi HEAD được tách ra, nó trỏ trực tiếp đến một cam kết — thay vì gián tiếp trỏ đến một thông qua một nhánh. Bạn có thể nghĩ ra một HEAD tách rời như đang ở trên một nhánh chưa được đặt tên.

  • git symbolic-ref HEAD thất bại với fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEAD sản lượng 17a02998078923f2d62811326d130de991d1a95a
    Vì nó không phải là một ref biểu tượng, nó phải trỏ trực tiếp đến chính cam kết đó.

Chúng ta có HEAD → 17a02998078923f2d62811326d130de991d1a95a

Điều quan trọng cần nhớ với HEAD tách rời là nếu cam kết mà nó trỏ đến không được tham chiếu (không có ref khác có thể đạt được nó), thì nó sẽ trở thành "lúng túng" khi bạn kiểm tra một số cam kết khác. Cuối cùng, các cam kết lơ lửng như vậy sẽ được cắt tỉa thông qua quá trình thu gom rác (theo mặc định, chúng được giữ trong ít nhất 2 tuần và có thể được giữ lâu hơn bằng cách được tham chiếu bởi bản chỉnh sửa của HEAD).

1 Nó là hoàn toàn tốt đẹp để làm "bình thường" làm việc với một HEAD tách ra, bạn chỉ cần có để theo dõi những gì bạn đang làm để tránh phải cá rơi lịch sử ra khỏi reflog.


Các bước trung gian của một rebase tương tác được thực hiện với một HEAD tách rời (một phần để tránh gây ô nhiễm cho quá trình reflog của nhánh đang hoạt động). Nếu bạn hoàn thành hoạt động rebase đầy đủ, nó sẽ cập nhật nhánh ban đầu của bạn với kết quả tích lũy của hoạt động rebase và gắn lại HEAD vào nhánh ban đầu. Tôi đoán là bạn chưa bao giờ hoàn thành quá trình rebase; điều này sẽ để lại cho bạn một HEAD tách rời trỏ đến cam kết được xử lý gần đây nhất bởi thao tác rebase.

Để phục hồi từ tình huống của bạn, bạn nên tạo một chi nhánh trỏ đến cam kết hiện được chỉ ra bởi HEAD tách rời của bạn:

git branch temp
git checkout temp

(hai lệnh này có thể được viết tắt là git checkout -b temp)

Thao tác này sẽ gắn lại HEAD của bạn với phiên bản mới temp chi nhánh.

Tiếp theo, bạn nên so sánh cam kết hiện tại (và lịch sử của nó) với nhánh thông thường mà bạn dự kiến ​​sẽ làm việc:

git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp

(Có thể bạn sẽ muốn thử nghiệm với các tùy chọn nhật ký: thêm -p, rời khỏi --pretty=… để xem toàn bộ thông điệp tường trình, v.v.)

Nếu bạn mới temp nhánh có vẻ tốt, bạn có thể muốn cập nhật (ví dụ:) master để chỉ vào nó:

git branch -f master temp
git checkout master

(hai lệnh này có thể được viết tắt là git checkout -B master temp)

Sau đó bạn có thể xóa nhánh tạm thời:

git branch -d temp

Cuối cùng, có thể bạn sẽ muốn đẩy lịch sử được thiết lập lại:

git push origin master

Bạn có thể cần phải thêm --force đến cuối lệnh này để đẩy nếu nhánh từ xa không thể "chuyển tiếp nhanh" đến cam kết mới (tức là bạn đã bỏ hoặc viết lại một số cam kết hiện có hoặc viết lại một chút lịch sử).

Nếu bạn đang ở giữa một hoạt động rebase bạn có lẽ nên làm sạch nó lên. Bạn có thể kiểm tra xem quá trình rebase đã được xử lý hay chưa bằng cách tìm thư mục .git/rebase-merge/. Bạn có thể xóa thủ công quá trình rebase đang thực hiện bằng cách chỉ xóa thư mục đó (ví dụ: nếu bạn không nhớ mục đích và ngữ cảnh của hoạt động rebase hoạt động nữa). Thông thường bạn sẽ sử dụng git rebase --abort, nhưng điều đó có một số cài đặt lại bổ sung mà bạn có thể muốn tránh (nó di chuyển HEAD trở lại nhánh ban đầu và đặt lại nó về cam kết ban đầu, điều này sẽ hoàn tác một số công việc chúng tôi đã làm ở trên).


2166
2018-04-24 19:56



Tuyệt vời. Những thứ như thế này cho thấy có chỗ để cải thiện git. Đôi khi trong khi ở giữa công việc dự án, đơn giản là không có chỗ để lãng phí thời gian với s ** t như thế này và nó chỉ đơn giản là gây phiền nhiễu. Nhưng khác hơn thế, git thực sự tuyệt vời. - BastiBen
Nó là không thể tin được làm thế nào các hệ thống phiên bản phức tạp đã trở thành - Antonio Sesto
Tại sao trong địa ngục Git quá phức tạp ... omg, tất cả những gì tôi muốn làm là tạo ra một nhánh mới thực hiện một số thay đổi ở đó và đẩy nó, sau đó chuyển về master và tiếp tục làm việc, nhưng sau đó nó vẫn phàn nàn về câu trả lời của bạn đã lưu lại vài sợi tóc tôi đã để lại trên da đầu của tôi. - Space monkey
Đây là một câu trả lời hay, nhưng tôi nghĩ không cần đến nhánh tạm thời (mặc dù tôi thường dùng một cái tôi). git branch -f master HEAD && git checkout master là đủ - giả sử mục tiêu của bạn là giữ đầu hiện tại của bạn nhưng để chỉ định nó master. Các mục tiêu khác cũng có ý nghĩa và kêu gọi các công thức nấu ăn khác. - Adrian Ratnapala
Lol tại bình luận gurning về chiều dài. Trong khi phần còn lại của chúng tôi chỉ quét qua cho đến khi chúng tôi đến được dòng chữ "Để phục hồi từ tình huống của bạn [...]", và đi từ đó - trong khi lưu ý rằng có một câu chuyện hữu ích được giải thích hữu ích mà chúng ta có thể đọc vào một ngày mưa. Các Tùy chọn để đọc nhiều hơn không làm tổn thương bạn, nhưng nó làm đứng để đem lại lợi ích cho người khác. - underscore_d


Chỉ cần làm điều này:

git checkout master

Hoặc, nếu bạn có thay đổi mà bạn muốn giữ lại, hãy thực hiện việc này:

git checkout -b temp
git checkout -B master temp

514
2017-09-18 07:23



Cảm ơn vì ngắn gọn. Không phải ai cũng có thời gian cho "Đầu tiên, hãy làm rõ HEAD là gì ..." câu trả lời. - Brian Risk
Đây là một phản ứng nguy hiểm. Những người đến câu trả lời này có các trạng thái khác nhau và "chỉ thực hiện việc này để trả lời" câu trả lời không trả lời câu hỏi. Điều này có thể dễ dàng phá hủy công việc. - Archonic
! "git checkout master" sẽ khiến mọi thay đổi bị mất nếu đầu bị tách rời không phải là một phần của master !! - Tony
@Blauhirn Bạn có thể đã cam kết kiểm tra, không phải chi nhánh. Chi nhánh vẫn trỏ đến cùng một cam kết, nhưng bạn đang ở một 'chế độ' khác nhau. - Daniel Alexiuc
Điều này làm việc hoàn hảo! Giải pháp dễ dàng hơn cho câu trả lời được chấp nhận ở trên! - Tfish


Tôi đã gặp sự cố này và khi tôi đọc câu trả lời được bình chọn hàng đầu:

HEAD là tên biểu tượng cho cam kết hiện đã được kiểm tra.

Tôi nghĩ: Ah-ha! Nếu HEAD là tên biểu tượng cho cam kết thanh toán bù trừ, tôi có thể hòa giải nó với master bằng cách rebasing nó chống lại master:

git rebase HEAD master

Lệnh này:

  1. kiểm tra ra master
  2. xác định các cam kết gốc của HEAD trở lại điểm HEAD phân kỳ từ master
  3. chơi những cam kết trên đầu trang của master

Kết quả cuối cùng là tất cả các cam kết trong HEAD nhưng không master sau đó cũng ở master. master vẫn được kiểm tra.


Về điều khiển từ xa:

một vài cam kết mà tôi đã giết trong cuộc phản công đã bị đẩy, và những cái mới cam kết cục bộ không có ở đó.

Lịch sử từ xa có thể không còn được chuyển tiếp nhanh bằng lịch sử cục bộ của bạn nữa. Bạn sẽ cần phải đẩy mạnh (git push -f) để ghi đè lịch sử từ xa. Nếu bạn có bất kỳ cộng tác viên nào, thường là hợp lý để phối hợp điều này với họ để mọi người ở cùng một trang.

Sau khi bạn đẩy master điều khiển origin, chi nhánh theo dõi từ xa của bạn origin/master sẽ được cập nhật để trỏ đến cùng một cam kết như master.


97
2017-08-02 03:10



git: "Đầu tiên, tua đầu để phát lại công việc của bạn trên đầu nó ... Thạc sĩ chuyển tiếp nhanh đến HEAD." Tôi đẹp!" - Benjamin
Cảm ơn, đã quét qua câu trả lời không phải là nhiều trang đọc - Ally


Nhìn ở đây để giải thích cơ bản của đầu tách ra:

http://git-scm.com/docs/git-checkout

Dòng lệnh để hình dung nó:

git branch

hoặc là

git branch -a

bạn sẽ nhận được kết quả như sau:

* (no branch)
master
branch1

Các * (no branch) cho thấy bạn đang ở trong đầu tách rời.

Bạn có thể đã đến trạng thái này bằng cách thực hiện git checkout somecommit vv và nó sẽ cảnh báo bạn với những điều sau đây:

Bạn đang ở trạng thái 'Tách rời'. Bạn   có thể nhìn xung quanh, thử nghiệm   thay đổi và cam kết, và bạn có thể   loại bỏ bất kỳ cam kết nào bạn thực hiện trong này   nhà nước mà không ảnh hưởng đến bất kỳ chi nhánh nào   bằng cách thực hiện một lần thanh toán khác.

Nếu bạn muốn tạo chi nhánh mới cho   giữ lại các cam kết bạn tạo, bạn có thể làm   vì vậy (bây giờ hoặc sau này) bằng cách sử dụng -b với   lệnh thanh toán một lần nữa. Thí dụ:

git checkout -b new_branch_name

Bây giờ, để đưa chúng vào master:

Làm một git reflog hoặc thậm chí chỉ git log và lưu ý các cam kết của bạn. Hiện nay git checkout master và git merge các cam kết.

git merge HEAD@{1}

Chỉnh sửa:

Để thêm, sử dụng git rebase -i không chỉ cho xóa / giết các cam kết mà bạn không cần, mà còn để chỉnh sửa chúng. Chỉ cần đề cập đến "chỉnh sửa" trong danh sách cam kết và bạn sẽ có thể sửa đổi cam kết của mình và sau đó phát hành git rebase --continue tiếp tục. Điều này sẽ đảm bảo rằng bạn không bao giờ đến một HEAD tách rời.


78
2018-04-24 18:41



Cảm ơn thông tin chi tiết và thông tin tuyệt vời tại đây. Có vẻ như một hợp nhất rõ ràng là không cần thiết, nhưng điều này hình dung một số khái niệm tôi sẽ quay trở lại. Cảm ơn. - Ben Zotto
"@ {1}" làm gì? - ebi


Nhận cam kết tách rời của bạn trên nhánh của riêng nó

Chỉ cần chạy git checkout -b mynewbranch.

Sau đó chạy git logvà bạn sẽ thấy cam kết đó bây giờ HEAD trên nhánh mới này.


29
2018-05-20 02:44



Nếu tôi làm điều này, mynewbranch đính kèm vào bất cứ điều gì? - Benjohn
Vâng, nó gắn liền với nơi đầu bị tách rời sẽ được gắn vào, đó là chính xác những gì tôi muốn. Cảm ơn! - Benjohn


nếu bạn chỉ cần làm chủ chi nhánh và muốn trở lại "phát triển" hoặc một tính năng chỉ cần làm điều này:

git checkout origin/develop

Lưu ý: thanh toán xuất xứ / phát triển.

Bạn đang ở trong HEAD tách rời tiểu bang. Bạn có thể nhìn xung quanh, thử nghiệm thay đổi và cam kết chúng, và bạn có thể loại bỏ bất kỳ cam kết nào bạn thực hiện trong nhà nước mà không ảnh hưởng đến bất kỳ chi nhánh nào bằng cách thực hiện thanh toán khác ...

sau đó

git checkout -b develop

Nó hoạt động :)


18
2017-11-08 13:24



Những gì đã làm việc cho tôi không phải là 'git checkout origin / develop' nhưng 'git checkout develop'. Sử dụng 'origin / develop' luôn luôn dẫn đến không có thay đổi, do đó còn lại trong "HEAD tách ra tại nguồn gốc / phát triển". Bỏ qua phần 'origin' đã sửa mọi thứ. - DrStrangepork


Nếu bạn muốn đẩy HEAD tách rời hiện tại của bạn (hãy kiểm tra git log trước đó), hãy thử:

git push origin HEAD:master

để gửi HEAD tách rời của bạn thành nhánh chính tại gốc. Nếu bạn bị từ chối, hãy thử git pull origin master đầu tiên để có được những thay đổi từ nguồn gốc. Nếu bạn không quan tâm đến những thay đổi từ nguồn gốc và nó bị từ chối, bởi vì bạn đã làm một số cố ý rebase và bạn muốn thay thế nguồn gốc / chủ với chi nhánh hiện tại của bạn tách ra - sau đó bạn có thể ép nó (-f). Trong trường hợp bạn mất quyền truy cập vào các cam kết trước đó, bạn luôn có thể chạy git reflog để xem lịch sử từ tất cả các chi nhánh.


Để quay trở lại nhánh chính, trong khi vẫn giữ các thay đổi, hãy thử các lệnh sau:

git rebase HEAD master
git checkout master

Xem: Git: "Hiện tại không thuộc chi nhánh nào". Có cách nào dễ dàng để lấy lại chi nhánh, trong khi vẫn giữ thay đổi không?


16
2017-09-17 20:35



Điều này thực sự gửi các cam kết tách ra gốc / master. Để đính kèm đầu vào chi nhánh địa phương, hãy thực hiện điều này: stackoverflow.com/a/17667057/776345 - Paschalis
Khi tôi làm điều này tôi nhận được Kho lưu trữ này được cấu hình cho Git LFS nhưng 'git-lfs' không được tìm thấy trên đường dẫn của bạn. Nếu bạn không còn muốn sử dụng Git LFS, hãy xóa móc này bằng cách xóa .git / hooks / post-checkout. - user2568374


Nếu bạn hoàn toàn chắc chắn HEAD là trạng thái tốt:

git branch -f master HEAD
git checkout master

Bạn có thể không thể đẩy đến nguồn gốc, vì chủ của bạn đã tách ra khỏi nguồn gốc. Nếu bạn chắc chắn không có ai khác đang sử dụng repo, bạn có thể đẩy mạnh:

git push -f

Hữu ích nhất nếu bạn đang ở trên một nhánh tính năng mà không ai khác đang sử dụng.


7
2018-03-01 09:31



câu trả lời đúng ngay tại đó - octohedron