Làm thế nào để nguồn gốc / ĐẦU được thiết lập?


144

Tôi có một chi nhánh được thiết lập để theo dõi một nguồn gốc ref. git checkout <branchname>chuyển sang chi nhánh đó và git statussẽ cho tôi biết phía trước hoặc phía sau chi nhánh của tôi cách xa nguồn gốc, nhưng tôi ngạc nhiên rằng origin/HEADvẫn chỉ vào origin/master, và khôngorigin/<branchname>

Vì vậy, câu hỏi của tôi là, trong trường hợp nào nguồn gốc / ĐẦU được di chuyển?

BIÊN TẬP:

Tôi đánh giá cao câu trả lời về cách di chuyển nguồn gốc / ĐẦU, nhưng tôi quan tâm đến những gì "hữu cơ" di chuyển nó, bên ngoài tôi nói rõ ràng là làm cho nó làm như vậy.

Ví dụ: khi tôi chuyển đổi các nhánh, git làm cho điểm CHÍNH ở nhánh tôi đang kiểm tra, vì vậy tôi rất ngạc nhiên khi nguồn gốc / ĐẦU không di chuyển theo cách tương tự.


Lưu ý rằng câu hỏi này là về các tài liệu tham khảo tượng trưng địa phương trên điều khiển từ xa, như refs/origin/HEAD. Đây không phải là cách HEADthiết lập tham chiếu tượng trưng của kho lưu trữ .
clacke

Câu trả lời:


172

Lưu ý đầu tiên rằng câu hỏi của bạn cho thấy một chút hiểu lầm. origin / HEAD đại diện cho nhánh mặc định trên remote , tức là HEAD trong kho lưu trữ từ xa mà bạn đang gọi origin. Khi bạn chuyển nhánh trong repo của mình, bạn sẽ không ảnh hưởng đến điều đó. Điều tương tự cũng đúng với các chi nhánh từ xa; bạn có thể có masterorigin/mastertrong repo của bạn, nơi origin/masterđại diện cho một bản sao cục bộ của masterchi nhánh trong kho lưu trữ từ xa.

Head của origin sẽ chỉ thay đổi nếu bạn hoặc người khác thực sự thay đổi nó trong kho lưu trữ từ xa , điều này về cơ bản sẽ không bao giờ xảy ra - bạn muốn nhánh mặc định là repo công khai không đổi, trên nhánh ổn định (có thể là master). origin / HEAD là một ref cục bộ đại diện cho một bản sao cục bộ của HEAD trong kho lưu trữ từ xa. (Tên đầy đủ của nó là refs / điều khiển từ xa / nguồn gốc / ĐẦU.)

Tôi nghĩ các câu trả lời ở trên là những gì bạn thực sự muốn biết, nhưng để tiếp tục và trả lời câu hỏi bạn đã hỏi rõ ràng ... origin / HEAD được đặt tự động khi bạn sao chép một kho lưu trữ, và đó là về nó. Kỳ lạ thay, nó không được thiết lập bởi các lệnh như git remote update- tôi tin rằng cách duy nhất nó sẽ thay đổi là nếu bạn thay đổi thủ công. (Bằng cách thay đổi, tôi có nghĩa là trỏ đến một nhánh khác; rõ ràng là cam kết nó sẽ thay đổi nếu nhánh đó thay đổi, điều này có thể xảy ra khi tìm nạp / kéo / cập nhật từ xa.)


Chỉnh sửa : Vấn đề được thảo luận dưới đây đã được sửa trong Git 1.8.4.3 ; thấy bản cập nhật này .


Có một cảnh báo nhỏ, mặc dù. HEAD là một ref mang tính biểu tượng, chỉ vào một nhánh thay vì trực tiếp đến một cam kết, nhưng các giao thức truyền từ xa git chỉ báo cáo các cam kết cho các ref. Vì vậy, Git biết SHA1 của cam kết được chỉ ra bởi HEAD và tất cả các giới thiệu khác; sau đó nó phải suy ra giá trị của HEAD bằng cách tìm một nhánh trỏ đến cùng một cam kết. Điều này có nghĩa là nếu hai nhánh xảy ra ở đó, điều đó không rõ ràng. (Tôi tin rằng nó chọn chủ nếu có thể, sau đó quay lại bảng chữ cái đầu tiên.) Bạn sẽ thấy điều này được báo cáo trong đầu ra của git remote show origin:

$ git remote show origin
* remote origin
  Fetch URL: ...
  Push  URL: ...
  HEAD branch (remote HEAD is ambiguous, may be one of the following):
    foo
    master

Điều kỳ lạ là, mặc dù khái niệm ĐẦU được in theo cách này sẽ thay đổi nếu mọi thứ thay đổi trên điều khiển từ xa (ví dụ: nếu foo bị xóa), nó không thực sự cập nhật refs/remotes/origin/HEAD. Điều này có thể dẫn đến những tình huống thực sự kỳ quặc. Giả sử trong ví dụ trên origin / HEAD thực sự đã trỏ đến foo và nhánh foo của origin sau đó đã bị xóa. Sau đó chúng ta có thể làm điều này:

$ git remote show origin
...
HEAD branch: master
$ git symbolic-ref refs/remotes/origin/HEAD
refs/remotes/origin/foo
$ git remote update --prune origin
Fetching origin
 x [deleted]         (none)     -> origin/foo
   (refs/remotes/origin/HEAD has become dangling)

Vì vậy, mặc dù chương trình từ xa biết rằng CHÍNH là chủ, nhưng nó không cập nhật bất cứ điều gì. Nhánh foo cũ kỹ được cắt tỉa chính xác và HEAD trở nên lơ lửng (chỉ vào một nhánh không tồn tại), và nó vẫn không cập nhật nó để trỏ đến chủ. Nếu bạn muốn sửa lỗi này, hãy sử dụng git remote set-head origin -a, nó sẽ tự động xác định CHÍNH của nguồn gốc như trên, và sau đó thực sự đặt gốc / ĐẦU để trỏ đến nhánh từ xa thích hợp.


@jefromi Câu trả lời tuyệt vời! Chỉ là một nhận xét: bạn viết rằng CHÍNH là một tham chiếu tượng trưng, ​​chỉ vào một nhánh thay vì trực tiếp đến một cam kết [...] , nhưng có lẽ đáng để đề cập đến "trạng thái CHÍNH tách rời", cho hoàn chỉnh.
jub0bs

2
@Jubobs Cảm ơn! Tuy nhiên, nếu câu trả lời của tôi cần cập nhật, xin vui lòng chỉ cần chỉnh sửa nó - chắc chắn sẽ giúp mọi người tiết kiệm thời gian để đọc một bản tóm tắt ngắn gọn về cách mọi thứ thực sự hoạt động, thay vì phải sắp xếp những gì là sự thật hai năm trước và bây giờ là sự thật .
Cascabel

đã đọc điều này ít nhất 5 lần và vẫn không hiểu một chút về nó
krb686

7
git remote set-head origin -ađã làm công việc cho tôi
Shujito

75

Đây là thiết lập của bạn với tư cách là chủ sở hữu của repo địa phương của bạn. Thay đổi nó như thế này:

git remote set-head origin some_branch

Và nguồn gốc / ĐẦU sẽ trỏ đến chi nhánh của bạn thay vì chủ. Điều này sau đó sẽ chỉ áp dụng cho repo của bạn và không áp dụng cho người khác. Theo mặc định, nó sẽ trỏ đến chủ, trừ khi một cái gì đó khác đã được cấu hình trên repo từ xa.

Nhập thủ công cho bộ đầu từ xa cung cấp một số thông tin tốt về điều này.

Chỉnh sửa: để nhấn mạnh: không cần bạn nói với nó, cách duy nhất nó sẽ "di chuyển" sẽ là một trường hợp như đổi tên nhánh chính , mà tôi không nghĩ là được coi là "hữu cơ". Vì vậy, tôi sẽ nói một cách hữu cơ nó không di chuyển.


1
Sự nhấn mạnh chỉnh sửa không hoàn toàn chính xác ở đây. Nó cũng có thể thay đổi nếu bạn sao chép từ một bản sao cục bộ không có trên nhánh chính.
mphair

Tôi không xem xét một bản sao "di chuyển", nhưng tôi đoán chúng ta có thể không đồng ý về điều đó :)
eis

24

Những gì di chuyển nguồn gốc / ĐẦU "hữu cơ"?

  • git clone đặt nó một lần vào vị trí có nguồn gốc
    • nó phục vụ như là chi nhánh mặc định để kiểm tra sau khi nhân bản với git clone

Head về nguồn gốc đại diện cho cái gì?

  • trên các kho lưu trữ trần (thường là kho lưu trữ trên các máy chủ) nó hoạt động như một điểm đánh dấu cho nhánh mặc định, bởi vì git clonesử dụng nó theo cách như vậy
  • trên các kho lưu trữ không trống (cục bộ hoặc từ xa), nó phản ánh thanh toán hiện tại của kho lưu trữ

Những gì thiết lập nguồn gốc / ĐẦU?

  • git clone tìm nạp và thiết lập nó
  • nó sẽ có ý nghĩa nếu git fetchcập nhật nó như bất kỳ tài liệu tham khảo nào khác, nhưng nó không
  • git remote set-head origin -a tìm nạp và thiết lập nó
    • hữu ích để cập nhật kiến ​​thức địa phương về những gì từ xa xem xét chi nhánh mặc định của Google

Câu đố

  • origin/HEAD cũng có thể được đặt thành bất kỳ giá trị nào khác mà không cần liên hệ với điều khiển từ xa: git remote set-head origin <branch>
    • Tôi thấy không có trường hợp sử dụng nào cho việc này, ngoại trừ việc thử nghiệm
  • tiếc là không có gì có thể đặt ĐẦU trên điều khiển từ xa
  • Các phiên bản cũ hơn của git không biết đầu nhánh nào trỏ tới trên điều khiển từ xa, chỉ cuối cùng nó có hàm băm: vì vậy nó chỉ hy vọng chọn được một tên nhánh chỉ vào cùng một hàm băm

Tôi đã mất tham khảo origin/HEADvà giải pháp của bạn đã giúp. Cảm ơn!
java_dude

Tôi không đồng ý với việc git fetchcập nhật nó, vì nó cho phép cấu hình một phím tắt (cục bộ). Trích dẫn tài liệu: "Không yêu cầu một nhánh mặc định cho điều khiển từ xa, nhưng cho phép tên của điều khiển từ xa được chỉ định thay cho một nhánh cụ thể". Sẽ là lạ nếu một thay đổi từ xa sẽ cập nhật các phím tắt được cấu hình cục bộ.
Micha Wiedenmann

@MichaWiedenmann Tại sao đó là một phím tắt được cấu hình cục bộ? Đối với một phím tắt origin/HEADđược cấu hình cục bộ là một tên xấu. Và điều đó cũng git clonesử dụng một tên từ xa làm mặc định cho một nhánh được cấu hình cục bộ, cũng như vậy. Trên các kho lưu trữ không trống, thậm chí không có ý nghĩa gì khi sử dụng dòng điện từ xa HEAD.
Robert Siemer

10

Tuyên bố miễn trừ trách nhiệm : đây là bản cập nhật cho câu trả lời của Jefromi , tôi đang viết để tiết kiệm thời gian.

Tôi đã cố gắng vô ích để sao chép (trong Git 2.0.1) remote HEAD is ambiguousthông điệp mà Jefromi đề cập trong câu trả lời của anh ấy; vì vậy tôi đã thực hiện một số hoạt động đào (bằng cách nhân bản https://github.com/git/git và tìm kiếm nhật ký). Nó đã từng là

Determining HEAD is ambiguous since it is done by comparing SHA1s.

In the case of multiple matches we return refs/heads/master if it
matches, else we return the first match we encounter. builtin-remote
needs all matches returned to it, so add a flag for it to request such.

(Cam kết 4229f1fa325870d6b24fe2a4c7d2ed5f14c6f771, ngày 27 tháng 2 năm 2009, được tìm thấy với git log --reverse --grep="HEAD is ambiguous")

Tuy nhiên, sự mơ hồ trong câu hỏi đã được dỡ bỏ :

One long-standing flaw in the pack transfer protocol used by "git
clone" was that there was no way to tell the other end which branch
"HEAD" points at, and the receiving end needed to guess.  A new
capability has been defined in the pack protocol to convey this
information so that cloning from a repository with more than one
branches pointing at the same commit where the HEAD is at now
reliably sets the initial branch in the resulting repository.

(Cam kết 9196a2f8bd46d36a285bdfa03b4540ed3f01f671, ngày 8 tháng 11 năm 2013, được tìm thấy với git log --grep="ambiguous" --grep="HEAD" --all-match)

Chỉnh sửa (nhờ torek ):

$ git name-rev --name-only 9196a2f8bd46d36a285bdfa03b4540ed3f01f671
tags/v1.8.4.3~3

Điều này có nghĩa là, nếu bạn đang sử dụng Git v1.8.4.3 trở lên , bạn không nên gặp phải bất kỳ vấn đề nào từ xa mơ hồ.


1
Dựa trên các thẻ trong nguồn git, cách khắc phục này áp dụng cho phiên bản git 1.8.4.3 trở lên.

@RobertSiemer Tôi không chắc, nhưng tôi nghĩ vậy, vâng.
jub0bs

8

Hãy nhớ rằng có hai repos git độc lập mà chúng ta đang nói đến. Repo cục bộ của bạn với mã của bạn và điều khiển từ xa đang chạy ở một nơi khác.

Bạn nói đúng, khi bạn thay đổi một nhánh, CHÍNH chỉ vào nhánh hiện tại của bạn. Tất cả điều này đang xảy ra trên repo git địa phương của bạn. Không phải repo từ xa, có thể thuộc sở hữu của nhà phát triển khác, hoặc chọn một máy chủ trong văn phòng của bạn, hoặc github, hoặc một thư mục khác trên hệ thống tệp, v.v ...

Máy tính của bạn (repo cục bộ) không có doanh nghiệp thay đổi con trỏ CHÍNH trên repo git từ xa. Nó có thể được sở hữu bởi một nhà phát triển khác chẳng hạn.

Một điều nữa, những gì máy tính của bạn gọi là origin / XXX là sự hiểu biết của máy tính về trạng thái của điều khiển từ xa tại thời điểm tìm nạp cuối cùng.

Vì vậy, những gì "hữu cơ" cập nhật nguồn gốc / ĐẦU? Nó sẽ là hoạt động trên repo git từ xa. Không phải repo địa phương của bạn.

Mọi người đã đề cập

git Symbolic-ref CHÍNH refs / head / my_other_branch

Thông thường, nó được sử dụng khi có một git repo trung tâm được chia sẻ trên một máy chủ để nhóm phát triển sử dụng. Nó sẽ là một lệnh được thực thi trên máy tính từ xa. Bạn sẽ thấy đây là hoạt động trên repo git từ xa.


1
Xin lỗi, nếu tôi có một chút lặp đi lặp lại. Tôi chỉ muốn chỉ ra một thực tế rằng git là một hệ thống kiểm soát phiên bản phân tán, và như vậy hai repos là độc lập.
Pablo Maurin

3

Chạy các lệnh sau từ git CLI:

# move to the wanted commit
git reset --hard <commit-hash> 

# update remote
git push --force origin <branch-name> 

1
Tuyệt, đó là những gì đã giúp tôi!
Shay Zambrovski
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.