Tại sao tôi phải khởi động git đẩy - khởi động ngược dòng <nhánh> nhánh?


145

Tôi đã tạo một chi nhánh địa phương để thử nghiệm Solaris và Sun Studio. Sau đó tôi đẩy nhánh lên thượng nguồn. Sau khi thực hiện thay đổi và cố gắng đẩy các thay đổi:

$ git commit blake2.cpp -m "Add workaround for missing _mm_set_epi64x"
[solaris 7ad22ff] Add workaround for missing _mm_set_epi64x
 1 file changed, 5 insertions(+)
$ git push
fatal: The current branch solaris has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin solaris

Tại sao tôi phải làm một cái gì đó đặc biệt cho việc này?

Có trường hợp sử dụng hợp lý nào mà ai đó sẽ tạo <branch>, đẩy <branch>điều khiển từ xa và sau đó yêu cầu một cam kết <branch>không được cho là <branch>không?


Tôi đã theo dõi câu hỏi và câu trả lời này trên Stack Overflow: Đẩy một nhánh cục bộ mới vào kho lưu trữ Git từ xa và cũng theo dõi nó . Tôi đoán đây là một ví dụ khác về câu trả lời không đầy đủ hoặc sai được chấp nhận. Hoặc, một trường hợp khác của Git nhận một nhiệm vụ đơn giản và gây khó khăn.


Đây là góc nhìn trên một máy khác. Chi nhánh rõ ràng tồn tại, vì vậy nó được tạo ra và đẩy:

$ git branch -a
  alignas
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/alignas
  remotes/origin/arm-neon
  remotes/origin/det-sig
  remotes/origin/master
  remotes/origin/solaris


2
Cảm ơn @Alexi. Thật không may, bản sao được trích dẫn không giải thích trường hợp sử dụng lố bịch đang được trình bày theo mặc định. (Đó không phải là những câu hỏi tu từ. Tôi thực sự quan tâm đến lý do thiết kế UX).
jww

1
Lưu ý rằng đây là cấu hình. Nếu bạn làmgit config --add push.default current , thì git đẩy sẽ tự động tạo chi nhánh trong repo từ xa nếu cần thiết.
Gogowitsch

Câu trả lời:


270

TL; DR: git branch --set-upstream-to origin/solaris


Câu trả lời cho câu hỏi mà bạn đã hỏi, trong đó tôi sẽ viết lại một chút là "tôi có phải đặt ngược dòng" không, không, bạn hoàn toàn không phải đặt ngược dòng.

Tuy nhiên, nếu bạn không có dòng ngược cho nhánh hiện tại, Git cũng thay đổi hành vi của nó git pushvà trên các lệnh khác.

Câu chuyện đẩy hoàn chỉnh ở đây dài và nhàm chán và quay trở lại trong lịch sử trước phiên bản Git 1.5. Để rút ngắn nó rất nhiều, git pushđược thực hiện kém. 1 Kể từ phiên bản Git 2.0, Git hiện có một núm cấu hình được đánh vần push.defaultmà bây giờ mặc định là simple. Đối với một số phiên bản Git trước và sau 2.0, mỗi khi bạn chạy git push, Git sẽ phát ra nhiều tiếng ồn khi cố gắng thuyết phục bạn cài đặt push.defaultchỉ git pushđể im lặng.

Bạn không đề cập đến phiên bản Git nào bạn đang chạy, cũng như bạn đã cấu hình chưa push.default, vì vậy chúng tôi phải đoán. Tôi đoán là bạn đang sử dụng Git phiên bản 2-point-một cái gì đó, và rằng bạn đã thiết lập push.defaultđể simplelàm cho nó im lặng. Chính xác là phiên bản Git nào bạn có, và nếu bất cứ điều gì bạn push.defaultđặt ra, đều quan trọng, do lịch sử lâu dài và nhàm chán đó, nhưng cuối cùng, thực tế là bạn đang nhận được một khiếu nại khác từ Git cho thấy Git của bạn cấu hình để tránh một trong những sai lầm từ quá khứ.

Một thượng nguồn là gì?

Một thượng nguồn chỉ đơn giản là một tên nhánh khác, thường là một nhánh theo dõi từ xa, được liên kết với một nhánh (thông thường, cục bộ).

Mỗi nhánh có tùy chọn có một (1) bộ ngược dòng. Đó là, mỗi nhánh hoặc có một thượng nguồn hoặc không có một thượng nguồn. Không có chi nhánh có thể có nhiều hơn một thượng nguồn.

Thượng nguồn nên , nhưng không nhất thiết phải là một nhánh hợp lệ (cho dù theo dõi từ xa như thế nào hay như cục bộ ). Đó là, nếu nhánh B hiện tại có U ngược dòng , nên hoạt động. Nếu nó không hoạt động, nếu nó phàn nàn rằng U không tồn tại thì thì hầu hết các Git hoạt động như thể dòng ngược dòng không được thiết lập. Một vài lệnh, như , sẽ hiển thị cài đặt ngược dòng nhưng đánh dấu nó là "biến mất".origin/Bmastergit rev-parse U git branch -vv

Những gì tốt là một thượng nguồn?

Nếu bạn push.defaultđược đặt thành simplehoặc upstream, cài đặt ngược dòng sẽ thực hiệngit push , được sử dụng mà không có đối số bổ sung, chỉ hoạt động.

Đó là nó, đó là tất cả những gì nó làm git push. Nhưng điều đó khá quan trọng, vì đây git pushlà một trong những nơi mà một lỗi đánh máy đơn giản gây ra những cơn đau đầu lớn.

Nếu bạn push.defaultđược thiết lập để nothing, matchinghoặc current, thiết lập một thượng nguồn không có gì ở tất cả cho git push.

(Tất cả điều này giả định phiên bản Git của bạn ít nhất là 2.0.)

Thượng nguồn ảnh hưởng git fetch

Nếu bạn chạy git fetchkhông có đối số bổ sung, Git hiểu ra từ xa để lấy từ bằng cách tham khảo ý kiến thượng nguồn các chi nhánh hiện hành. Nếu thượng nguồn là một nhánh theo dõi từ xa, Git sẽ tìm nạp từ điều khiển đó. (Nếu ngược dòng không được đặt hoặc là một nhánh cục bộ, Git sẽ thử tìm nạp origin.)

Thượng nguồn ảnh hưởng git mergegit rebasequá

Nếu bạn chạy git mergehoặc git rebasekhông có đối số bổ sung, Git sử dụng ngược dòng của nhánh hiện tại. Vì vậy, nó rút ngắn việc sử dụng hai lệnh này.

Thượng nguồn ảnh hưởng git pull

Dù sao thì bạn cũng không nên sử dụng 2 lầngit pull , nhưng nếu có, hãy git pullsử dụng cài đặt ngược dòng để tìm ra từ xa nào cần tìm nạp và sau đó là nhánh nào để hợp nhất hoặc khởi động lại. Đó là, git pulllàm điều tương tự như git fetch-because nó thực sự chạy git fetch -Và sau đó làm điều tương tự như git mergehoặc git rebase, bởi vì nó thực sự chạy git merge haygit rebase .

.

Thượng nguồn ảnh hưởng git status

Điều này thực sự có thể là quan trọng nhất. Khi bạn có một bộ ngược dòng, git statuscó thể báo cáo sự khác biệt giữa nhánh hiện tại của bạn và ngược dòng của nó, về mặt cam kết.

Nếu, như trường hợp bình thường, bạn đang ở nhánh Bvới dòng ngược được đặt thành và bạn chạy , bạn sẽ ngay lập tức xem liệu bạn có cam kết bạn có thể đẩy hay không và / hoặc cam kết bạn có thể hợp nhất hoặc khởi động lại.origin/Bgit status

Điều này là do git statuschạy:

  • git rev-list --count @{u}..HEAD: bạn có bao nhiêu cam kết Bmà không có ?origin/B
  • git rev-list --count HEAD..@{u}: bạn có bao nhiêu cam kết mà không có ?origin/BB

Thiết lập một thượng nguồn cung cấp cho bạn tất cả những điều này.

Làm thế nào đến masterđã có một bộ ngược dòng?

Khi bạn lần đầu tiên sao chép từ một số điều khiển từ xa, sử dụng:

$ git clone git://some.host/path/to/repo.git

hoặc tương tự, bước cuối cùng mà Git thực hiện là, về cơ bản , git checkout master. Điều này kiểm tra chi nhánh địa phương của masterbạn, bạn không chi nhánh địa phương master.

Mặt khác, bạn làm có một chi nhánh từ xa theo dõi tên origin/master, bởi vì bạn chỉ cần nhân bản nó.

Git đoán rằng bạn phải có nghĩa là: "làm cho tôi một địa phương mới mastertrỏ đến cùng cam kết như từ xa theo dõi origin/master, và, trong khi bạn đang ở đó, thiết lập các thượng nguồn cho masterđến origin/master."

Điều này xảy ra cho mọi chi nhánh git checkoutmà bạn chưa có. Git tạo ra nhánh làm cho nó "theo dõi" (có dòng ngược) là nhánh theo dõi từ xa tương ứng.

Nhưng điều này không làm việc cho mới ngành, ví dụ, chi nhánh không có chi nhánh từ xa theo dõi chưa .

Nếu bạn tạo một chi nhánh mới :

$ git checkout -b solaris

Có, như vậy, không origin/solaris. Địa phương của bạn solaris không thể theo dõi chi nhánh theo dõi từ xa origin/solarisvì nó không tồn tại.

Khi bạn lần đầu tiên đẩy chi nhánh mới:

$ git push origin solaris

tạo solaris trên origin, và do đó cũng tạo ra origin/solaristrong kho Git của riêng bạn. Nhưng đã quá muộn: Bạn đã có một địa phương solariskhông có thượng nguồn . 3

Không phải Git chỉ nên đặt nó, bây giờ, là thượng nguồn tự động?

Có lẽ. Xem "triển khai kém" và chú thích 1. Bây giờ thật khó để thay đổi : Có hàng triệu 4 tập lệnh sử dụng Git và một số có thể phụ thuộc vào hành vi hiện tại của nó. Thay đổi hành vi yêu cầu một bản phát hành chính mới, nag-ware để buộc bạn đặt một số trường cấu hình, v.v. Nói tóm lại, Git là nạn nhân của sự thành công của chính nó: bất kỳ sai lầm nào trong đó, ngày nay, chỉ có thể được sửa chữa nếu thay đổi chủ yếu là vô hình, rõ ràng tốt hơn nhiều hoặc được thực hiện chậm theo thời gian.

Thực tế là, nó không có ngày hôm nay, trừ khi bạn sử dụng --set-upstreamhoặc -utrong thời gian git push. Đó là những gì tin nhắn đang nói với bạn.

Bạn không cần phải làm như thế. Vâng, như chúng tôi đã lưu ý ở trên, bạn hoàn toàn không phải làm điều đó, nhưng hãy nói rằng bạn muốn một thượng nguồn. Bạn đã tạo chi nhánh solaristrên origin, thông qua một lần đẩy trước đó và khi git branchđầu ra của bạn hiển thị, bạn đã origin/solaris trong kho lưu trữ cục bộ của mình.

Bạn không nên đặt nó làm thượng nguồn cho solaris.

Để đặt nó ngay bây giờ, thay vì trong lần đẩy đầu tiên, hãy sử dụng git branch --set-upstream-to. Lệnh --set-upstream-tophụ lấy tên của bất kỳ nhánh hiện có nào, chẳng hạn như origin/solaris, và đặt ngược dòng của nhánh hiện tại với nhánh khác.

Đó là nó, đó là tất cả những gì nó làm nhưng nó có tất cả những ý nghĩa được ghi nhận ở trên. Điều đó có nghĩa là bạn chỉ có thể chạy git fetch, sau đó nhìn xung quanh, sau đó chạy git mergehoặc git rebasekhi thích hợp, sau đó thực hiện các cam kết mới và chạy git push, mà không cần phải loay hoay thêm.


1 Để công bằng, sau đó không rõ ràng rằng việc triển khai ban đầu dễ bị lỗi. Điều đó chỉ trở nên rõ ràng khi mọi người dùng mới đều mắc lỗi giống nhau mỗi lần. Bây giờ "ít ​​nghèo" hơn, không có nghĩa là "tuyệt vời".

2 "Không bao giờ" là một chút mạnh mẽ, nhưng tôi thấy rằng những người mới Git hiểu mọi thứ tốt hơn rất nhiều khi tôi tách ra các bước, đặc biệt là khi tôi có thể chỉ cho họ những gì git fetchthực sự đã làm, và sau đó họ có thể thấy những gì git mergehoặc git rebasesẽ làm gì tiếp theo.

3 Nếu bạn chạy lần đầu tiên git push với tư cách git push -u origin solarislàieie, nếu bạn thêm -ucờ thì Git sẽ đặt origin/solarislàm thượng nguồn cho nhánh hiện tại của bạn nếu (và chỉ khi) việc đẩy thành công. Vì vậy, bạn nên cung cấp -utrên đẩy đầu tiên . Trong thực tế, bạn có thể cung cấp nó cho bất kỳ lần đẩy nào sau này và nó sẽ thiết lập hoặc thay đổi ngược dòng tại thời điểm đó. Nhưng tôi nghĩ git branch --set-upstream-tolà dễ dàng hơn, nếu bạn quên.

4 Đo bằng phương pháp Austin Powers / Dr Evil chỉ đơn giản là nói "một TRIỆU-YUN", dù sao đi nữa.


2
Nếu trường hợp phổ biến là {tạo nhánh / đẩy nhánh / sử dụng nhánh}, thì không nên kết quả Đẩy một nhánh cục bộ mới vào kho lưu trữ Git từ xa và theo dõi nó có phải là thứ thực sự hoạt động không? Và nếu ai đó muốn {tạo chi nhánh / đẩy chi nhánh / không sử dụng chi nhánh}, thì họ có nên làm điều gì đó đặc biệt --set-upstream /dev/nullkhông? Tại sao gánh nặng đẩy vào trường hợp phổ biến? Tôi thực sự không hiểu một số quyết định kỹ thuật và khả năng sử dụng này.
jww

1
@VonC: đúng, đó là quan điểm git push -u, nhưng nó thực sự có vẻ như git push -usẽ là mặc định, hoặc ít nhất là mặc định nếu không có thượng nguồn chưa , và có phải là một git push --no-set-upstreamkhi có hiện không phải là thượng nguồn và bạn muốn giữ theo cách đó (vì bất kỳ lý do khó hiểu nào :-)).

2
"Bạn cứ hỏi những câu như thế bởi vì, tôi nghĩ, bạn đã viết tắt Git là" thực sự đáng ghét "." Hãy giữ loại đầu cơ này cho chính mình. Tôi bắt gặp câu hỏi này bởi vì tôi cũng tiếp tục tự hỏi mình những loại câu hỏi này. Tôi không phải là nhà thiết kế UX giỏi nhất thế giới, nhưng thậm chí tôi nhận ra rằng hành vi mặc định trong kịch bản cụ thể này có thể tốt hơn.
Steven Byks

4
@torek - Cảm ơn bạn. Câu trả lời của bạn thật tuyệt vời; cũng nghĩ ra, cấu trúc tốt, và cực kỳ nhiều thông tin. :-)
Steven Byks

6
Lưu ý rằng đây là cấu hình. Nếu bạn làm như vậy git config --add push.default current, thì git đẩy sẽ tự động tạo chi nhánh trong repo từ xa nếu cần thiết.
Gogowitsch

30

Sự khác biệt giữa
git push origin <branch>

git push --set-upstream origin <branch>
là cả hai đều đẩy tốt vào kho lưu trữ từ xa, nhưng đó là khi bạn kéo mà bạn nhận thấy sự khác biệt.

Nếu bạn làm:
git push origin <branch>
khi kéo, bạn phải làm:
git pull origin <branch>

Nhưng nếu bạn làm:
git push --set-upstream origin <branch>
sau đó, khi kéo, bạn chỉ phải làm:
git pull

Vì vậy, việc thêm vào --set-upstreamcho phép không phải chỉ định nhánh nào bạn muốn kéo từ mỗi lần bạn làm git pull.


sự khác biệt giữa hai phiên bản "git đẩy" mà tôi không biết tại sao tôi muốn / cần sử dụng chúng. Vô nghĩa!
Frank Puck

16

Một lệnh cơ bản đầy đủ là như thế git push <remote> <local_ref>:<remote_ref>. Nếu bạn chỉ chạy git push, git không biết chính xác phải làm gì trừ khi bạn đã thực hiện một số cấu hình giúp git đưa ra quyết định. Trong một repo git, chúng ta có thể thiết lập nhiều điều khiển từ xa. Ngoài ra chúng ta có thể đẩy một ref địa phương đến bất kỳ ref từ xa nào. Lệnh đầy đủ là cách đơn giản nhất để thực hiện một cú đẩy. Nếu bạn muốn nhập ít từ hơn, trước tiên bạn phải định cấu hình, như --set-upflow.

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.