Có gì khác biệt giữa thiết lập lại git và


440

Tôi đã luôn nghĩ git resetgit checkoutgiống nhau, theo nghĩa là cả hai đưa dự án trở lại một cam kết cụ thể. Tuy nhiên, tôi cảm thấy chúng không thể giống hệt nhau, vì điều đó sẽ là dư thừa. Sự khác biệt thực sự giữa hai là gì? Tôi hơi bối rối, vì svn chỉ svn cophải hoàn nguyên cam kết.

THÊM

VonC và Charles đã giải thích sự khác biệt giữa git resetgit checkoutthực sự tốt. Sự hiểu biết hiện tại của tôi là hoàn nguyên git resettất cả các thay đổi trở lại một cam kết cụ thể, trong khi git checkoutít nhiều chuẩn bị cho một chi nhánh. Tôi thấy hai sơ đồ sau khá hữu ích để hiểu điều này:

http://a.imageshack.us/img651/1559/86421927.png http://a.imageshack.us/img801/1986/resetr.png

THÊM 3

Từ http://think-like-a-git.net/sections/rebase-from-the-ground-up/USE-git-cherry-pick-to-simulation-git-rebase.html , thanh toán và đặt lại có thể mô phỏng cuộc nổi loạn.

nhập mô tả hình ảnh ở đây

git checkout bar 
git reset --hard newbar 
git branch -d newbar 

nhập mô tả hình ảnh ở đây



Re: "Nó sai hay đơn giản hóa quá mức?" Vâng, sơ đồ đầu tiên đó là sai lệch về sự khác biệt giữa thanh toán và thiết lập lại. (Có thể không ổn về các -- filesbiến thể; Tôi không chắc chắn.) Sơ đồ đó làm cho nó có vẻ như sự khác biệt chính là liệu chúng có ảnh hưởng đến chỉ số hay WD không. Xem câu trả lời của tôi về điều đó. Các sơ đồ thứ 2 và 3 rất hữu ích để thấy sự khác biệt thực sự. Các sơ đồ thứ 4 và 5 rất hữu ích để kiểm tra xem bạn có hiểu những lệnh này làm gì không, nhưng sẽ không thực sự giúp bạn đạt được điều đó.
LarsH

Tôi đã tìm thấy phần "Kiểm tra xem" trong phần "Thiết lập lại công cụ Git" để đưa ra bản tóm tắt hữu ích nhất.
Josiah Yoder

1
prosseek: Nếu bạn đồng ý với @LarsH rằng sơ đồ đầu tiên là sai lệch, bạn có thể xóa nó không?
Josiah Yoder

Xin lưu ý rằng thanh toán và đặt lại chỉ mô phỏng phần thứ hai của rebase và các bước bổ sung (được cung cấp trong think-like-a-git.netbài viết được liên kết ) là bắt buộc để tránh mất dữ liệu.
chăn bò

Câu trả lời:


198
  • git resetđặc biệt về việc cập nhật chỉ mục , di chuyển ĐẦU.
  • git checkoutlà về việc cập nhật cây làm việc (lên chỉ mục hoặc cây được chỉ định). Nó sẽ cập nhật ĐẦU chỉ khi bạn kiểm tra một nhánh (nếu không, bạn kết thúc với một ĐẦU tách rời ).
    (thực tế, với Git 2.23 Q3 2019, điều này sẽ git restorekhông nhất thiết phải như vậy git checkout)

Để so sánh, vì svn không có chỉ mục, chỉ có một cây làm việc, svn checkoutsẽ sao chép một sửa đổi nhất định trên một thư mục riêng.
Tương đương gần hơn với git checkoutsẽ:

  • svn update (nếu bạn ở cùng chi nhánh, nghĩa là cùng một URL SVN)
  • svn switch (nếu bạn thanh toán ví dụ cùng một chi nhánh, nhưng từ một URL repo SVN khác)

Tất cả những thay đổi ba cây làm việc ( svn checkout, update, switch) chỉ có một lệnh trong git: git checkout.
Nhưng vì git cũng có khái niệm về chỉ mục ("khu vực tổ chức" giữa repo và cây làm việc), bạn cũng có git reset.


Thinkeye đề cập trong các ý kiến bài viết " Đặt lại làm sáng tỏ ".

Chẳng hạn, nếu chúng ta có hai nhánh, ' master' và ' develop' chỉ vào các cam kết khác nhau và chúng ta hiện đang ở trên ' develop' (vì vậy CHÍNH chỉ vào nó) và chúng ta sẽ chạy git reset master, ' develop' chính nó sẽ trỏ đến cùng một cam kết đó ' master' làm.

Mặt khác, nếu chúng ta thay vào đó chạy git checkout master, ' develop' sẽ không di chuyển, HEADchính nó sẽ. HEADbây giờ sẽ trỏ đến ' master'.

Vì vậy, trong cả hai trường hợp, chúng tôi đều chuyển HEADsang cam kết A, nhưng cách chúng tôi làm như vậy rất khác nhau. resetsẽ di chuyển các HEADđiểm nhánh đến, thanh toán HEADtự di chuyển để trỏ đến một nhánh khác.

http://git-scm.com/images/reset/reset-checkout.png

Trên những điểm đó, mặc dù:

LarsH thêm vào trong các ý kiến :

Tuy nhiên, đoạn đầu tiên của câu trả lời này là sai lệch: " git checkout... sẽ chỉ cập nhật ĐẦU nếu bạn kiểm tra một nhánh (nếu không, bạn kết thúc với một ĐẦU tách rời)".
Không đúng: git checkoutsẽ cập nhật ĐẦU ngay cả khi bạn kiểm tra một cam kết không phải là một nhánh (và vâng, bạn kết thúc với một ĐẦU tách rời, nhưng nó vẫn được cập nhật).

git checkout a839e8f updates HEAD to point to commit a839e8f.

De Novo đồng tình trong các ý kiến :

@LarsH đúng.
Viên đạn thứ hai có một quan niệm sai lầm về những gì ĐẦU TIÊN sẽ cập nhật ĐẦU chỉ khi bạn kiểm tra một nhánh.
ĐẦU đi bất cứ nơi nào bạn đến, giống như một cái bóng.
Kiểm tra một số ref không thuộc chi nhánh (ví dụ: thẻ) hoặc cam kết trực tiếp, sẽ di chuyển CHÍNH. Đầu tách ra không có nghĩa là bạn đã tách ra khỏi ĐẦU, điều đó có nghĩa là đầu bị tách ra khỏi một nhánh ref, mà bạn có thể nhìn thấy, ví dụ , git log --pretty=format:"%d" -1.

  • Các trạng thái đầu đính kèm sẽ bắt đầu bằng (HEAD ->,
  • tách ra vẫn sẽ hiển thị (HEAD, nhưng sẽ không có một mũi tên đến một nhánh ref.

7
Tôi muốn nói rằng đó git resetlà về việc sửa đổi "nhãn" nhánh và cập nhật tùy chọn chỉ mục hoặc cây làm việc như một hiệu ứng phụ. git checkoutlà về việc cập nhật cây làm việc và chuyển nhánh "được chọn" hiện tại (the HEAD).
Mikko Rantalainen

2
@MikkoRantalainen không. git resetlà 100% về HEAD. Nó hoạt động ngay cả trong chế độ CHÍNH tách rời ( stackoverflow.com/a/3965714/6309 ), nghĩa là nơi không có chi nhánh (!). git checkout cũng hoạt động ở chế độ CHÍNH tách rời hoặc có thể được sử dụng để kiểm tra SHA1 ở chế độ CHÍNH tách rời: một lần nữa không có chi nhánh nào liên quan đến trường hợp đó.
VonC

3
Đọc thêm cho tất cả các linh hồn bị mất được gửi bởi một công cụ tìm kiếm ở đây, tôi nghĩ rằng nó đáng giá: git-scm.com/blog/2011/07/11/reset.html
Thinkeye

2
@Thinkeye tham khảo tốt. Tôi đã bao gồm nó, cùng với một trích xuất có liên quan, trong câu trả lời để dễ nhìn hơn.
VonC

2
Giải thích từ Reset Demystified là tuyệt vời. Tuy nhiên, đoạn đầu tiên của câu trả lời này là sai lệch: "git checkout ... sẽ chỉ cập nhật ĐẦU nếu bạn kiểm tra một nhánh (nếu không, bạn kết thúc với một ĐẦU tách rời)". Không đúng ... kiểm tra git sẽ cập nhật ĐẦU ngay cả khi bạn kiểm tra một cam kết không phải là một chi nhánh (và vâng, bạn kết thúc với một ĐẦU tách rời, nhưng nó vẫn được cập nhật). Có lẽ tôi đang hiểu nhầm ý của bạn khi "cập nhật"? git checkout a839e8fcập nhật CHÍNH để chỉ ra cam kết a839e8f.
LarsH

67

Ở dạng đơn giản nhất, resetđặt lại chỉ mục mà không chạm vào cây làm việc, trong khi checkoutthay đổi cây làm việc mà không chạm vào chỉ mục.

Đặt lại chỉ mục để khớp HEAD, cây làm việc một mình:

git reset

Về mặt khái niệm, điều này kiểm tra chỉ số vào cây làm việc. Để làm cho nó thực sự làm bất cứ điều gì bạn sẽ phải sử dụng -fđể buộc nó ghi đè lên bất kỳ thay đổi cục bộ nào. Đây là một tính năng an toàn để đảm bảo rằng biểu mẫu "không đối số" không phá hủy:

git checkout

Khi bạn bắt đầu thêm tham số, đúng là có một số trùng lặp.

checkoutthường được sử dụng với một nhánh, thẻ hoặc cam kết. Trong trường hợp này, nó sẽ thiết lập lại HEADvà chỉ mục cho cam kết đã cho cũng như thực hiện kiểm tra chỉ mục vào cây làm việc.

Ngoài ra, nếu bạn cung cấp --hardcho resetbạn, bạn có thể yêu cầu resetghi đè lên cây làm việc cũng như đặt lại chỉ mục.

Nếu bạn hiện có một chi nhánh được kiểm tra thì có một sự khác biệt quan trọng giữa resetcheckoutkhi bạn cung cấp một chi nhánh hoặc cam kết thay thế. resetsẽ thay đổi nhánh hiện tại để trỏ đến cam kết đã chọn trong khi đó checkoutsẽ để lại nhánh hiện tại một mình nhưng sẽ kiểm tra nhánh được cung cấp hoặc cam kết thay thế.

Các hình thức khác resetcommitliên quan đến đường dẫn cung cấp.

Nếu bạn cung cấp đường dẫn cho resetbạn, bạn không thể cung cấp --hardresetsẽ chỉ thay đổi phiên bản chỉ mục của đường dẫn được cung cấp thành phiên bản trong cam kết được cung cấp (hoặc HEADnếu bạn không chỉ định cam kết).

Nếu bạn cung cấp đường dẫn tới checkout, giống như resetnó sẽ cập nhật phiên bản chỉ mục của các đường dẫn được cung cấp để khớp với cam kết được cung cấp (hoặc HEAD) nhưng nó sẽ luôn kiểm tra phiên bản chỉ mục của các đường dẫn được cung cấp vào cây làm việc.


2
Thật không đúng khi nói rằng "thanh toán" không thay đổi chỉ mục: nó thay đổi nó khi được sử dụng để đi từ chi nhánh này sang chi nhánh khác.
wiki1000

Ở dạng đơn giản nhất, đặt lại thiết lập lại chỉ mục mà không chạm vào cây làm việc, trong khi thanh toán thay đổi cây làm việc mà không chạm vào chỉ mục. : Thật khó hiểu làm sao: |
Aditya Gupta

41

Một trường hợp sử dụng đơn giản khi hoàn nguyên thay đổi:
1. Sử dụng đặt lại nếu bạn muốn hoàn tác phân đoạn tệp đã sửa đổi.
2. Sử dụng thanh toán nếu bạn muốn loại bỏ các thay đổi đối với tệp / s không được sắp xếp.


1
Câu trả lời hoàn hảo. Cảm ơn bạn.
dùng358591

11

Sự khác biệt chính trong một tóm tắt là reset di chuyển tham chiếu nhánh hiện tại , trong khi checkoutkhông (nó di chuyển CHÍNH).

Như sách Pro Git giải thích trong phần Đặt lại bị khử ,

Điều đầu tiên resetsẽ làm là di chuyển những gì CHÍNH chỉ đến . Điều này không giống như thay đổi chính nó (đó là những gì checkoutlàm); reset di chuyển nhánh mà ĐẦU đang chỉ. Điều này có nghĩa là nếu HEAD được đặt thành masternhánh (tức là bạn hiện đang ở masternhánh), việc chạy git reset 9e5e6a4sẽ bắt đầu bằng cách tạo masterđiểm đến 9e5e6a4. [nhấn mạnh thêm]

Xem thêm câu trả lời của VonC cho một đoạn trích văn bản và sơ đồ rất hữu ích từ cùng một bài viết, mà tôi sẽ không sao chép ở đây.

Tất nhiên có nhiều chi tiết hơn về những hiệu ứng checkoutresetcó thể có trên chỉ mục và cây làm việc, tùy thuộc vào tham số nào được sử dụng. Có thể có nhiều điểm tương đồng và khác biệt giữa hai lệnh. Nhưng như tôi thấy, sự khác biệt quan trọng nhất là liệu họ có di chuyển đầu của nhánh hiện tại hay không.


2
Phản hồi tốt, ngoài câu trả lời cũ của tôi. +1
VonC

2

Hai lệnh (thiết lập lại và kiểm tra) là hoàn toàn khác nhau.

checkout X KHÔNG PHẢI reset --hard X

Nếu X là tên nhánh, checkout Xsẽ thay đổi nhánh hiện tại trong khi reset --hard Xsẽ không.


2
Nhưng nếu X là một tập tin hoặc thư mục, thì chúng giống nhau.
Ted Bigham

1

ghi nhớ ngắn gọn:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD
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.