2010-03-29 33 views
41

Trong khi resetcheckout có các cách sử dụng khác nhau hầu hết thời gian, tôi không thể thấy sự khác biệt giữa hai loại này.Có sự khác biệt giữa "git reset --hard hash" và "git checkout hash" không?

Có thể có một hoặc không ai có thể làm phiền thêm tùy chọn --hard để làm điều gì đó cơ bản checkout có thể thực hiện.

Có thể có sự khác biệt là cách bạn sẽ thấy lịch sử?

+1

tôi được bảo hiểm này trong một cập nhật cho câu trả lời của tôi để một trong những câu hỏi trước đó của bạn - nhìn vào nghệ thuật ascii gần đầu trang, đặc biệt là nơi nó nói "Digression: ..." (nhiều như tôi muốn đại diện nhiều hơn để trả lời lại nó ở đây) – Cascabel

+0

Tôi nghĩ bạn có thể đăng câu trả lời của bạn ở đây và giành được đại diện từ nó. Nếu ai đó tìm kiếm kiến ​​thức cụ thể này, anh ta sẽ không tìm thấy bài đăng khác. Điều này nhằm mục đích một chủ đề rất cụ thể, và nó xứng đáng để có trang riêng của nó. BTW, có vẻ như bạn là người cố vấn Git của tôi :-) harigato, senseï! –

+1

Nhưng tôi nhận được nó, sự khác biệt là thiết lập lại di chuyển chi nhánh và không thanh toán. –

Trả lời

52

Câu trả lời này chủ yếu được trích dẫn từ câu trả lời của tôi cho câu hỏi trước: git reset in plain english.

Hai loại này rất khác nhau. Chúng tạo ra cùng một trạng thái cho chỉ mục và cây công việc của bạn, nhưng lịch sử kết quả và nhánh hiện tại không giống nhau.

Giả sử lịch sử của bạn trông như thế này, với các chi nhánh chủ hiện kiểm tra ra:

- A - B - C (HEAD, master) 

và bạn chạy git reset --hard B. Bạn sẽ có được điều này:

- A - B (HEAD, master)  # - C is still here, but there's no 
          # branch pointing to it anymore 

Bạn thực sự muốn có được hiệu ứng mà nếu bạn sử dụng --mixed hoặc --soft quá - sự khác biệt duy nhất là những gì xảy ra với cây công việc của bạn và chỉ mục. Trong trường hợp --hard, cây công việc và chỉ mục phù hợp với B.

Bây giờ, giả sử bạn sẽ chạy git checkout B để thay thế. Bạn sẽ nhận được điều này:

- A - B (HEAD) - C (master) 

Bạn đã kết thúc ở trạng thái HEAD tách rời. HEAD, cây công việc, chỉ mục tất cả phù hợp với B, giống như với việc đặt lại khó khăn nhưng chi nhánh chính bị bỏ lại ở số C. Nếu bạn thực hiện một cam kết mới D vào thời điểm này, bạn sẽ có được điều này, mà có lẽ không phải những gì bạn muốn:

- A - B - C (master) 
     \ 
     D (HEAD) 

Vì vậy, bạn sử dụng thanh toán, tốt, hãy kiểm tra rằng cam kết. Bạn có thể fiddle với nó, làm những gì bạn thích, nhưng bạn đã để lại chi nhánh của bạn phía sau. Nếu bạn muốn các chi nhánh di chuyển quá, bạn sử dụng thiết lập lại.

+5

+1 như thường lệ. Chủ đề này (http://marc.info/?l=git&m=120955970704567&w=2) cũng thêm vào một hiệu ứng phụ: nếu bạn đang ở giữa một hợp nhất (ví dụ: khi có xung đột hợp nhất, hoặc sau khi 'git merge - -no-commit'), 'git reset --hard' quên khoảng việc hợp nhất, nhưng' git checkout -f' thì không; do đó, một 'git commit' sau khi sau này sẽ tạo ra một cam kết hợp nhất, mà thường không phải là những gì bạn muốn. – VonC

+0

@VonC: và một điểm bổ sung tuyệt vời từ bạn, như thường lệ! – Cascabel

14

Nếu tài liệu được cung cấp với Git không giúp bạn, hãy xem A Visual Git Reference bởi Mark Lodato.

Đặc biệt nếu bạn đang so sánh git checkout <non-branch> với git reset --hard <non-branch> (hotlinked):

git checkout master~3 http://marklodato.github.com/visual-git-guide/checkout-detached.svg.png

git reset --hard master~3 http://marklodato.github.com/visual-git-guide/reset-commit.svg.png

Lưu ý rằng trong trường hợp của git reset --hard master~3 bạn để lại đằng sau một phần của DAG các phiên bản - một số cam kết không được tham chiếu bởi bất kỳ chi nhánh nào. Chúng được bảo vệ (theo mặc định) 30 ngày bởi reflog; họ cuối cùng sẽ được cắt tỉa (loại bỏ).

6

git-reset hash đặt tham chiếu nhánh thành mã băm đã cho và tùy chọn kiểm tra nó, với --hard.

git-checkout hash đặt cây làm việc thành băm đã cho; và trừ khi băm là tên chi nhánh, bạn sẽ kết thúc bằng một đầu tách rời.

cuối cùng, giao dịch git với 3 điều:

    working tree (your code) 
------------------------------------------------------------------------- 
        index/staging-area 
------------------------------------------------------------------------- 
     repository (bunch of commits, trees, branch names, etc) 

git-checkout theo mặc định chỉ cập nhật các chỉ mục và cây làm việc, và tùy chọn có thể cập nhật một cái gì đó trong kho (với tùy chọn -b)

git-reset theo mặc định, chỉ cập nhật kho lưu trữ và chỉ mục và tùy chọn cây làm việc (với tùy chọn --hard)

Bạn có thể nghĩ về kho lưu trữ như thế này:

HEAD -> master 

refs: 
    master -> sha_of_commit_X 
    dev -> sha_of_commit_Y 

objects: (addressed by sha1) 

    sha_of_commit_X, sha_of_commit_Y, sha_of_commit_Z, sha_of_commit_A .... 

git-reset điều chỉnh tham chiếu của chi nhánh.

Giả sử lịch sử của bạn trông như thế này:

  T--S--R--Q [master][dev] 
     /
    A--B--C--D--E--F--G [topic1] 
        \ 
        Z--Y--X--W [topic2][topic3] 

Hãy ghi nhớ rằng các chi nhánh chỉ là tên mà trước tự động khi bạn cam kết.

Vì vậy, bạn có các chi nhánh sau:

master -> Q 
dev -> Q 
topic1 -> G 
topic2 -> W 
topic3 -> W 

Và chi nhánh hiện tại của bạn là topic2, có nghĩa là, các điểm HEAD để topic2.

HEAD -> topic2 

Sau đó, git reset X sẽ đặt lại tên topic2 để trỏ đến X; có nghĩa là nếu bạn thực hiện một cam kết P trên nhánh topic2, mọi thứ sẽ trông như thế này:

  T--S--R--Q [master][dev] 
     /
    A--B--C--D--E--F--G [topic1] 
        \ 
        Z--Y--X--W [topic3] 
          \ 
          P [topic2] 
Các vấn đề liên quan