Sự khác biệt giữa git reset --mixed, --soft và --hard là gì?


741

Tôi đang tìm cách phân chia một cam kết và không chắc chắn nên sử dụng tùy chọn thiết lập lại nào.

Tôi đã xem trang bằng tiếng Anh, "git reset" làm gì? , nhưng tôi nhận ra rằng tôi không thực sự hiểu chỉ số git hoặc khu vực tổ chức là gì và do đó, những lời giải thích đã không giúp được gì.

Ngoài ra, các trường hợp sử dụng cho --mixed--softtrông giống như tôi trong câu trả lời đó (khi bạn muốn sửa chữa và đề nghị). Ai đó có thể phá vỡ nó nhiều hơn? Tôi nhận ra --mixedcó lẽ là lựa chọn để đi cùng, nhưng tôi muốn biết tại sao . Cuối cùng, những gì về --hard?

Ai đó có thể cho tôi một ví dụ về quy trình làm việc về cách chọn 3 tùy chọn sẽ xảy ra không?


1
Tôi sẽ đi chỉnh sửa câu trả lời của mình cho câu hỏi khác đó để thử và làm cho nó rõ ràng hơn một chút.
Cascabel

Câu trả lời @mkarasek là khá tốt nhưng người ta cũng có thể quan tâm đến việc xem xét câu hỏi này .
brandizzi

3
Lưu ý để tự: Nói chung , soft: stage everything, mixed: unstage everything, hard: ignore everythinglên đến cam kết Tôi đặt lại từ.
dùng1164937


một bài viết hay khác bằng cách David Zychgiải thích rõ ràng - davidzych.com/difference-b between
git

Câu trả lời:


1489

Khi bạn sửa đổi một tệp trong kho lưu trữ của bạn, thay đổi ban đầu không được thực hiện. Để thực hiện nó, bạn phải tạo ra nó, đó là thêm nó vào chỉ mục sử dụng git add. Khi bạn thực hiện một cam kết, những thay đổi được cam kết là những thay đổi đã được thêm vào chỉ mục.

git resetthay đổi, tối thiểu, trong đó nhánh hiện tại ( HEAD) đang trỏ. Sự khác biệt giữa --mixed--softlà liệu chỉ số của bạn có được sửa đổi hay không. Vì vậy, nếu chúng tôi ở chi nhánh mastervới loạt cam kết này:

- A - B - C (master)

HEADđiểm Cvà chỉ số phù hợp C.

Khi chúng ta chạy git reset --soft B, master(và do đó HEAD) bây giờ trỏ đến B, nhưng chỉ mục vẫn có các thay đổi từ C; git statussẽ cho họ thấy như được dàn dựng. Vì vậy, nếu chúng tôi chạy git commitvào thời điểm này, chúng tôi sẽ nhận được một cam kết mới với những thay đổi tương tự như C.


Được rồi, vì vậy bắt đầu từ đây một lần nữa:

- A - B - C (master)

Bây giờ hãy làm git reset --mixed B. (Lưu ý: --mixedlà tùy chọn mặc định). Một lần nữa, masterHEADtrỏ đến B, nhưng lần này chỉ số cũng được sửa đổi để phù hợp B. Nếu chúng ta chạy git commitvào thời điểm này, sẽ không có gì xảy ra vì chỉ số khớp với HEAD. Chúng tôi vẫn có các thay đổi trong thư mục làm việc, nhưng vì chúng không có trong chỉ mục, git statuscho thấy chúng là chưa được xử lý. Để cam kết với họ, bạn sẽ git addvà sau đó cam kết như bình thường.


Và cuối cùng, --hardcũng giống như --mixed(nó thay đổi HEADchỉ mục và chỉ mục của bạn ), ngoại trừ điều đó --hardcũng sửa đổi thư mục làm việc của bạn. Nếu chúng tôi đang Cvà chạy git reset --hard B, thì những thay đổi được thêm vào C, cũng như mọi thay đổi không được cam kết mà bạn có, sẽ bị xóa và các tệp trong bản sao làm việc của bạn sẽ khớp với cam kết B. Vì bạn có thể mất vĩnh viễn các thay đổi theo cách này, bạn nên luôn luôn chạy git statustrước khi thực hiện thiết lập lại cứng để đảm bảo thư mục làm việc của bạn sạch sẽ hoặc bạn ổn với việc mất các thay đổi không được cam kết.


Và cuối cùng, một hình dung: nhập mô tả hình ảnh ở đây


45
Nói cách khác, --soft được vứt bỏ cam kết cuối cùng, --mix được vứt bỏ cam kết cuối cùng và thêm, --hard được vứt bỏ cam kết cuối cùng, thêm và mọi thay đổi bạn thực hiện trên các mã mà là cùng với TRỤ thanh toán git
James Wang

11
@eventualEntropy Bạn có thể khôi phục mọi thay đổi đã cam kết với reflog; những thay đổi không được cam kết được loại bỏ reset --hardsẽ biến mất vĩnh viễn.
mkarasek

2
@Robert Cả; --mixedthay đổi chỉ mục của bạn nhưng không phải thư mục làm việc của bạn, vì vậy mọi sửa đổi cục bộ đều không bị ảnh hưởng.
mkarasek

3
Có thể hữu ích cho những người trực quan sử dụng git trên thiết bị đầu cuối có màu: 1.'git reset --soft A 'và bạn sẽ thấy nội dung của B và C có màu xanh lá cây (dàn dựng) 2.'git reset - trộn A' và bạn sẽ xem nội dung của B và C màu đỏ (chưa được phân loại) 3.'git reset --hard A 'và bạn sẽ không còn thấy những thay đổi của B và C ở bất cứ đâu (sẽ như thể chúng chưa từng tồn tại)
timhc22

2
@ user1933930 1 và 3 sẽ để lại cho bạn - A - B - C′, trong đó C ′ chứa các thay đổi tương tự như C (với dấu thời gian khác nhau và có thể là thông báo cam kết). 2 và 4 sẽ để lại cho bạn - A - D, trong đó D chứa các thay đổi kết hợp của B và C.
mkarasek

215

Trong các điều khoản đơn giản nhất:

  • --soft: thay đổi không phổ biến, thay đổi được đặt theo giai đoạn ( chỉ mục ).
  • --mixed (mặc định) : không phổ biến + thay đổi giai đoạn, thay đổi được để lại trong cây làm việc .
  • --hard: không phổ biến + unstage + xóa thay đổi, không còn gì.

8
câu trả lời hay nhất bởi vì câu trả lời sử dụng các thuật ngữ kỹ thuật để cung cấp một câu trả lời hoàn chỉnh cũng là câu trả lời ngắn gọn nhất
Trevor Boyd Smith

1
Khi tôi đã cam kết một tệp (chưa được xử lý) và tôi có một tệp chưa được tạo mới, sau đó git reset - có làm gì không? Chỉ khi tôi tạo tập tin không bị theo dõi, nó mới xóa nó khỏi thư mục làm việc của tôi.
Michael

1
@Nikhil Bạn có thể giải thích câu trả lời này sai ở đâu không?
Ned Batchelder

1
@NedBatchelder Không có điểm nào là đúng: Vì không phổ biến sẽ không bao giờ xảy ra khi các lệnh này được sử dụng.
Nikhil

1
@Nikhil Có lẽ điều bạn muốn nói là cam kết ban đầu vẫn tồn tại, đó là sự thật. Nhưng chi nhánh đã được thay đổi để cam kết không còn là một phần của chi nhánh. Chúng ta có đồng ý về điều đó không?
Ned Batchelder

69

Xin lưu ý, đây là một giải thích đơn giản nhằm mục đích là bước đầu tiên để tìm hiểu chức năng phức tạp này.

Có thể hữu ích cho những người học trực quan muốn hình dung trạng thái dự án của họ trông như thế nào sau mỗi lệnh này:


Đối với những người sử dụng Terminal có bật màu (git config --global color.ui auto):

git reset --soft A và bạn sẽ thấy nội dung của B và C có màu xanh lá cây (được dàn dựng và sẵn sàng cam kết)

git reset --mixed A(hoặc git reset A) và bạn sẽ thấy nội dung của B và C có màu đỏ (không được dàn dựng và sẵn sàng để được dàn dựng (màu xanh lá cây) và sau đó được cam kết)

git reset --hard A và bạn sẽ không còn thấy những thay đổi của B và C ở bất cứ đâu (sẽ như thể chúng chưa từng tồn tại)


Hoặc cho những người sử dụng chương trình GUI như 'Tháp' hoặc 'SourceTree'

git reset --soft A và bạn sẽ thấy nội dung của B và C trong khu vực 'tập tin dàn dựng' sẵn sàng cam kết

git reset --mixed A(hoặc git reset A) và bạn sẽ thấy nội dung của B và C trong khu vực 'tệp không được sắp xếp' sẵn sàng để được chuyển sang dàn dựng và sau đó cam kết

git reset --hard A và bạn sẽ không còn thấy những thay đổi của B và C ở bất cứ đâu (sẽ như thể chúng chưa từng tồn tại)


1
Điều này là sai lệch, tốt nhất là: câu trả lời của bạn đọc như thể git resetchỉ thay đổi giao diện của git statusđầu ra.
jub0bs

3
Tôi thấy quan điểm của bạn, nhưng không đồng ý vì với tư cách là người học trực quan, việc xem dự án của tôi 'trông như thế nào' sau khi sử dụng 3 lệnh cuối cùng đã giúp tôi hiểu họ đang làm gì!
timhc22

Tôi đã thấy nó nhiều hơn một ý tưởng 'git for dummies' để giúp mọi người dễ dàng hiểu được những gì đang thực sự xảy ra. Bạn có thể nghĩ làm thế nào nó có thể được cải thiện để không bị sai lệch
timhc22

8
Không, chúng tôi không cần thay đổi câu trả lời này. Nó cung cấp một "bảng cheat" tiện dụng. Hãy nghĩ về nó: soft = green, hỗn hợp = red, hard = nothing (có nghĩa là biến mất)! Thật dễ nhớ! Đối với những người mới thậm chí không hiểu những màu đó thực sự có ý nghĩa gì, họ biết quá ít về git và dù sao họ cũng sẽ có những bài học khó khăn, và đó không phải là lỗi của @unegma! BTW, tôi chỉ upvote câu trả lời này để chống lại downvote trước đó. Làm tốt lắm, @unegma!
RayLuo

5
Điều này phục vụ như một bản tóm tắt bổ sung tuyệt vời để hiểu rõ hơn các hoạt động bên trong khi tôi đọc chúng ở nơi khác. Cảm ơn bạn!
spex

24

Tất cả các câu trả lời khác là rất lớn, nhưng tôi thấy nó tốt nhất để hiểu chúng bằng cách phá bỏ các file thành ba loại: unstaged, staged, commit:

  • --hard nên dễ hiểu, nó khôi phục lại mọi thứ
  • --mixed (mặc định) :
    1. unstagedtập tin: không thay đổi
    2. staged tập tin: di chuyển đến unstaged
    3. commit tập tin: di chuyển đến unstaged
  • --soft:
    1. unstagedtập tin: không thay đổi
    2. stagedtập tin: không 'thay đổi
    3. commit tập tin: di chuyển đến staged

Tóm tắt:

  • --softtùy chọn sẽ chuyển mọi thứ (trừ unstagedtệp) vàostaging area
  • --mixed tùy chọn sẽ chuyển mọi thứ vào unstaged area

22

Dưới đây là một lời giải thích cơ bản cho người dùng TortoiseGit:

git reset --soft--mixedđể các tập tin của bạn không bị ảnh hưởng.

git reset --hardthực sự thay đổi các tập tin của bạn để phù hợp với cam kết bạn đặt lại.

Trong TortoiseGit, khái niệm về chỉ mục được ẩn rất nhiều bởi GUI. Khi bạn sửa đổi một tệp, bạn không phải chạy git addđể thêm thay đổi vào khu vực / chỉ mục dàn. Khi chỉ cần xử lý các sửa đổi đối với các tệp hiện có không thay đổi tên tệp git reset --soft--mixedgiống nhau! Bạn sẽ chỉ nhận thấy sự khác biệt nếu bạn thêm tệp mới hoặc đổi tên tệp. Trong trường hợp này, nếu bạn chạy git reset - trộn, bạn sẽ phải thêm lại (các) tệp của mình từ danh sách Tệp không được phiên bản .


Câu trả lời này rất không rõ ràng về sự khác biệt giữa mềm và hỗn hợp. và thậm chí là bác bỏ trong việc nêu rõ nó. Câu trả lời sau đây là rõ ràng hơn về điều đó. stackoverflow.com/questions/2530060/ từ
barlop

2
Là một người dùng Github Desktop cũng có hành vi tương tự, câu trả lời này cho tôi một số sự rõ ràng về lý do tại sao tôi cứ bối rối --mixed--soft.
Chen Li Yong

20

Trong những trường hợp này, tôi thích một hình ảnh có thể hy vọng giải thích điều này:

git reset --[hard/mixed/soft] :

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

Vì vậy, mỗi hiệu ứng phạm vi khác nhau

  1. Cứng => WorkDir + Index + ĐẦU
  2. Hỗn hợp => Chỉ mục + ĐẦU
  3. Mềm => Chỉ đầu (chỉ mục và thư mục làm việc không thay đổi).

15

Ba loại hối tiếc

Rất nhiều câu trả lời hiện có dường như không trả lời được câu hỏi thực tế. Chúng là về những gì các lệnh làm, không phải về những gì bạn (người dùng) muốn - trường hợp sử dụng . Nhưng đó là những gì OP yêu cầu!

Nó có thể hữu ích hơn để đi văng mô tả về những gì chính xác là bạn hối tiếc tại thời điểm bạn đưa ra một git resetlệnh. Hãy nói rằng chúng ta có điều này:

A - B - C - D <- HEAD

Dưới đây là một số điều hối tiếc có thể xảy ra và phải làm gì với chúng:

1. Tôi rất tiếc rằng B, C và D không phải là một cam kết.

git reset --soft A. Bây giờ tôi có thể ngay lập tức cam kết và uy tín, tất cả các thay đổi vì A một cam kết.

2. Tôi rất tiếc rằng B, C và D không phải là mười cam kết.

git reset --mixed A. Các cam kết đã biến mất và chỉ mục trở lại A, nhưng khu vực làm việc vẫn trông giống như sau D. Vì vậy, bây giờ tôi có thể thêm và cam kết trong một nhóm hoàn toàn khác.

3. Tôi rất tiếc rằng B, C và D đã xảy ra trên nhánh này ; Tôi ước tôi đã phân nhánh sau A và họ đã xảy ra trên nhánh khác.

Tạo một chi nhánh mới otherbranch, và sau đó git reset --hard A. Chi nhánh hiện tại kết thúc tại A, với otherbranchxuất phát từ nó.

(Tất nhiên bạn cũng có thể sử dụng thiết lập lại cứng vì bạn muốn B, C và D chưa bao giờ xảy ra.)


5

Bạn không cần phải ép mình phải nhớ sự khác biệt giữa chúng. Hãy nghĩ về cách bạn thực sự cam kết.

1. Thực hiện một số thay đổi.

2.git thêm.

3.gc -m "Tôi đã làm gì đó"

Mềm, hỗn hợp và cứng là cách cho phép bạn từ bỏ các thao tác bạn đã làm từ 3 đến 1.

Mềm "giả vờ" để không bao giờ thấy bạn đã làm "gc -m".

Hỗn hợp "giả vờ" để không bao giờ thấy bạn đã làm "git add."

Khó "giả vờ" để không bao giờ thấy bạn đã thực hiện thay đổi tập tin.


4

Trước khi đi vào ba lựa chọn này, người ta phải hiểu 3 điều.

1) Lịch sử / TRỤ

2) Giai đoạn / chỉ số

3) Thư mục làm việc

đặt lại --soft: Lịch sử đã thay đổi, CHÍNH thay đổi, thư mục làm việc không thay đổi.

đặt lại - đã trộn: Lịch sử đã thay đổi, CHÍNH đã thay đổi, Thư mục làm việc đã thay đổi với dữ liệu chưa được xử lý.

đặt lại --hard: Lịch sử đã thay đổi, CHÍNH thay đổi, Thư mục làm việc được thay đổi với dữ liệu bị mất.

Luôn luôn an toàn khi đi với Git --soft. Người ta nên sử dụng tùy chọn khác trong yêu cầu phức tạp.


3

Có một số câu trả lời ở đây với một quan niệm sai lầm về git reset --soft. Mặc dù có một điều kiện cụ thể git reset --softsẽ chỉ thay đổi HEAD(bắt đầu từ trạng thái đầu tách rời), thông thường (và cho mục đích sử dụng), nó di chuyển tham chiếu chi nhánh mà bạn hiện đã kiểm tra. Tất nhiên, nó không thể làm điều này nếu bạn không kiểm tra chi nhánh (do đó điều kiện cụ thể git reset --softsẽ chỉ thay đổi HEAD).

Tôi thấy đây là cách tốt nhất để suy nghĩ git reset. Bạn không chỉ di chuyển HEAD( mọi thứ đều như vậy ), bạn cũng đang di chuyển nhánh ref , ví dụ : master. Điều này tương tự với những gì xảy ra khi bạn chạy git commit(nhánh hiện tại di chuyển cùng HEAD), ngoại trừ thay vì tạo (và chuyển sang) một cam kết mới , bạn chuyển sang cam kết trước .

Đây là điểm reset, thay đổi một nhánh thành một thứ khác hơn là một cam kết mới, không thay đổi HEAD. Bạn có thể thấy điều này trong ví dụ tài liệu:

Hoàn tác một cam kết, làm cho nó trở thành một nhánh chủ đề

          $ git branch topic/wip     (1)
          $ git reset --hard HEAD~3  (2)
          $ git checkout topic/wip   (3)
  1. Bạn đã thực hiện một số cam kết, nhưng nhận ra rằng họ còn sớm để ở trong nhánh "chính". Bạn muốn tiếp tục đánh bóng chúng trong một nhánh chủ đề, vì vậy hãy tạo nhánh "topic / wip" khỏi ĐẦU hiện tại.
  2. Tua lại nhánh chính để thoát khỏi ba cam kết đó.
  3. Chuyển sang chi nhánh "topic / wip" và tiếp tục làm việc.

Điểm của loạt lệnh này là gì? Bạn muốn di chuyển một chi nhánh , ở đây master, vì vậy trong khi bạn đã masterkiểm tra, bạn chạy git reset.

Câu trả lời được bình chọn hàng đầu ở đây nói chung là tốt, nhưng tôi nghĩ tôi nên thêm câu này để sửa một số câu trả lời với những quan niệm sai lầm.

Thay đổi chi nhánh của bạn

git reset --soft <ref>: đặt lại con trỏ nhánh cho nhánh đang được kiểm tra thành cam kết tại tham chiếu đã chỉ định , <ref>. Các tập tin trong thư mục làm việc và chỉ mục của bạn không được thay đổi. Cam kết từ giai đoạn này sẽ đưa bạn trở lại nơi bạn đã ở trước git resetlệnh.

Thay đổi chỉ mục của bạn quá

git reset --mixed <ref>

hoặc tương đương

git reset <ref>:

Liệu những gì --softlàm cũng reset chỉ số cho phù hợp với các cam kết tại tham chiếu cụ thể. Mặc dù git reset --soft HEADkhông có gì (vì nó nói di chuyển nhánh đã kiểm tra sang nhánh đã kiểm tra) git reset --mixed HEAD, hoặc tương đương git reset HEAD, là một lệnh phổ biến và hữu ích vì nó đặt lại chỉ mục về trạng thái của lần xác nhận cuối cùng của bạn.

Thay đổi thư mục làm việc của bạn quá

git reset --hard <ref>: Làm những gì --mixedkhông cũng ghi đè thư mục làm việc của bạn. Lệnh này tương tự git checkout <ref>, ngoại trừ rằng (và đây là điểm quan trọng về reset) tất cả các hình thức git resetdi chuyển mà nhánh ref HEADđang trỏ tới.

Một lưu ý về "lệnh như vậy và lệnh đó di chuyển TRƯỚC":

Nó không hữu ích để nói một lệnh di chuyển HEAD. Bất kỳ lệnh nào thay đổi nơi bạn đang ở trong lịch sử cam kết của bạn sẽ di chuyển HEAD. Đó là những gì HEAD , một con trỏ đến bất cứ nơi nào bạn đang có. HEADlà bạn , và vì vậy sẽ di chuyển bất cứ khi nào bạn làm.


2
"di chuyển nhánh ref": điểm tốt. Tôi đã phải cập nhật stackoverflow.com/a/5203843/6309 .
VonC

1

Một câu trả lời ngắn trong bối cảnh 3 tùy chọn được sử dụng:

Để giữ các thay đổi hiện tại trong mã nhưng để viết lại lịch sử cam kết:

  • soft: Bạn có thể cam kết mọi thứ cùng một lúc và tạo một cam kết mới với một mô tả mới (nếu bạn sử dụng torotise git hoặc bất kỳ GUI nào khác, đây là một để sử dụng, vì bạn vẫn có thể đánh dấu các tệp bạn muốn trong cam kết và tạo nhiều cam kết theo cách đó với các tệp khác nhau. Trong Sourcetree, tất cả các tệp sẽ được phân loại cho cam kết.)
  • mixed: Bạn sẽ phải thêm các tệp riêng lẻ vào chỉ mục trước khi bạn thực hiện cam kết (trong Sourcetree, tất cả các tệp đã thay đổi sẽ không được hiển thị)

Để thực sự mất các thay đổi của bạn trong mã:

  • hard: bạn không chỉ viết lại lịch sử mà còn mất tất cả các thay đổi cho đến khi bạn đặt lại

Tôi không nhận được mềm và hỗn hợp trong trường hợp này. Nếu bạn phải cam kết, thì những gì đã được hoàn nguyên? bạn có đang hoàn nguyên hoặc đề xuất các thay đổi (để quay lại trạng thái ban đầu không?)
John Little

Khuyến cáo những thay đổi. Sẽ không có cam kết ngược lại.
Nickpick

1

Sự khác biệt cơ bản giữa các tùy chọn khác nhau của lệnh git reset như dưới đây.

  • --soft: Chỉ đặt lại CHÍNH cho cam kết bạn chọn. Hoạt động cơ bản giống như kiểm tra git nhưng không tạo ra trạng thái đầu tách rời.
  • --mixed (tùy chọn mặc định): Đặt lại CHÍNH cho cam kết bạn chọn trong cả lịch sử và hoàn tác các thay đổi trong chỉ mục.
  • --hard: Đặt lại CHÍNH cho cam kết bạn chọn trong cả lịch sử, hoàn tác các thay đổi trong chỉ mục và hoàn tác các thay đổi trong thư mục làm việc của bạn.

1

--soft: Yêu cầu Git thiết lập lại CHÍNH cho một cam kết khác, vì vậy chỉ mục và thư mục làm việc sẽ không bị thay đổi theo bất kỳ cách nào. Tất cả các tệp đã thay đổi giữa CHÍNH gốc và cam kết sẽ được phân loại.

--mixed: Giống như phần mềm, điều này sẽ thiết lập lại CHÍNH cho một cam kết khác. Nó cũng sẽ thiết lập lại chỉ mục để khớp với nó trong khi thư mục làm việc sẽ không được chạm vào. Tất cả các thay đổi sẽ ở trong thư mục làm việc và xuất hiện dưới dạng sửa đổi, nhưng không được dàn dựng.

--hard: Điều này đặt lại tất cả mọi thứ - nó đặt lại TRƯỚC cho một cam kết khác, đặt lại chỉ mục để khớp với nó và đặt lại thư mục làm việc để khớp với nó.

Sự khác biệt chính giữa --mixed--softlà liệu chỉ số của bạn có được sửa đổi hay không. Kiểm tra thêm về điều này ở đây .


0

Câu trả lời của mkarasek rất hay, nói một cách đơn giản, chúng ta có thể nói ...

  • git reset --soft: đặt HEADcam kết dự định nhưng giữ cho các thay đổi của bạn được tổ chức từ các cam kết cuối cùng
  • git reset --mixed: nó giống như git reset --softnhưng sự khác biệt duy nhất là nó bỏ qua các thay đổi của bạn từ các lần xác nhận trước
  • git reset --hard: đặt của bạn HEADvào cam kết bạn chỉ định và đặt lại tất cả các thay đổi của bạn từ các cam kết cuối cùng bao gồm các thay đổi chưa được cam kết.
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.