Яка різниця між скиданням git --mixed, --soft та --hard?


740

Я хочу розділити комісію і не знаю, який варіант скидання використовувати.

Я дивився сторінку простою англійською мовою, що робить "git reset"? , але я зрозумів, що я не дуже розумію, що таке індекс git або область постановки, і тому пояснення не допомогли.

Крім того, випадки використання для --mixedі --softвиглядають так само, як у мені у цій відповіді (коли ви хочете виправити та повторно) Чи може хтось розбити це ще більше? Я усвідомлюю, що --mixed, мабуть, варіант піти з цим, але я хочу знати, чому . Нарешті, про що --hard?

Чи може хтось надати мені приклад робочого процесу того, як відбудеться вибір трьох варіантів?


1
Я спробую відредагувати свою відповідь на це інше питання, щоб спробувати зробити це трохи більш зрозумілим.
Каскабель

Відповідь @mkarasek досить хороша, але можна зацікавитись і на це питання .
brandizzi

3
Примітка для себе: Загалом , soft: stage everything, mixed: unstage everything, hard: ignore everythingдо фіксації я скинути с.
користувач1164937


ще одна хороша стаття David Zychз чітким поясненням - davidzych.com/difference-between-git-reset-soft-mixed-and-hard
src3369

Відповіді:


1489

Коли ви змінюєте файл у вашому сховищі, зміни спочатку не змінюються. Для того, щоб здійснити його, ви повинні поставити його на етапі, тобто додати його до індексу, використовуючи git add. Коли ви приймаєте на себе зобов’язання, зміни, які здійснюються, - це ті, які були додані до індексу.

git resetзмінюється, як мінімум, там, де HEADвказується поточна гілка ( ). Різниця між --mixedі --softполягає в тому, змінюється чи ні ваш індекс. Отже, якщо ми вже в галузі masterз цією низкою зобов'язань:

- A - B - C (master)

HEADбалів до Cта індексу відповідає C.

Коли ми біжимо git reset --soft B, master(і таким чином HEAD) тепер вказує на B, але індекс все ще має зміни від C; git statusпокаже їх як постановочні. Тож якщо ми запустимо git commitцей момент, ми отримаємо нове зобов’язання з тими ж змінами, що і C.


Гаразд, починаючи звідси знову:

- A - B - C (master)

Тепер зробимо git reset --mixed B. (Примітка: --mixedпараметр за замовчуванням). Ще раз masterі HEADвкажіть на B, але цього разу індекс також змінено на відповідність B. Якщо ми побіжимо git commitв цей момент, нічого не станеться з моменту відповідності індексу HEAD. У нас все ще є зміни в робочому каталозі, але оскільки вони не git statusвходять до індексу, вони показують їх як незазначені. Здійснюючи їх, ви б git addі потім виконували обов'язки.


І нарешті, --hardце те саме, що --mixed(він змінює ваш HEADі індекс), за винятком того, що --hardтакож змінює ваш робочий каталог. Якщо ми в Cі запустити git reset --hard B, то зміни , додані в C, а також будь-які непідтверджені зміни , які ви, будуть видалені, а також файли у вашій робочої копії буде відповідати фіксації B. Оскільки ви можете назавжди втрачати зміни таким чином, вам слід завжди запускатись git statusперед тим, як зробити жорсткий перезавантаження, щоб переконатися, що ваш робочий каталог чистий, або що ви все гаразд із втратою невмілих змін.


І нарешті, візуалізація: введіть тут опис зображення


44
Іншими словами, - софт відміняє останню фіксацію, - мімікс відміняє останню фіксацію та додавання, - жорсткість відкидає останню фіксацію, додавання та будь-які зміни, внесені вами в коди, що збігається з Git checkout HEAD
Джеймс Ван

11
@eventualEntropy Ви можете відновити будь-які здійснені зміни за допомогою відмикання; невідомі зміни, які вилучені reset --hard, зникли назавжди.
mkarasek

2
@ Роберт Ні; --mixedзмінює ваш індекс, але не ваш робочий каталог, тому будь-які локальні зміни не впливають.
mkarasek

3
Може бути корисним для візуальних людей, які використовують git на терміналі з кольором: 1.'Git reset --soft A ', і ви побачите речі B і C зеленим (поетапно) 2.'Git reset - змішаним A', і ви дивіться речі B і C червоним кольором (без позначень) 3.'git reset --hard A ', і ви більше не побачите змін B і C ніде (буде так, ніби їх ніколи не було)
timhc22

2
@ user1933930 1 і 3 залишать вас - A - B - C′, де C ′ містить ті самі зміни, що і C (з різними часовими позначками та, можливо, повідомленнями фіксації). 2 і 4 залишить вас з - A - D, де D містить комбіновані зміни B і C.
mkarasek

213

Найпростішими словами:

  • --soft: скасувати зміни, зміни залишаються поетапними ( покажчик ).
  • --mixed (за замовчуванням) : зніміть + нестабільні зміни, зміни залишаються в робочому дереві .
  • --hard: зніміть + нестабільність + видалити зміни, нічого не залишилося.

8
найкраща відповідь, оскільки у відповіді використовуються технічні терміни, щоб дати повну відповідь, яка також є найбільш стислою
Тревор Бойд Сміт

1
Коли я створив файл (unlashhed) і у мене є нещодавно створений нерозроблений файл, то git reset - твердий нічого не робить? Тільки коли я виставляю файл, що не відстежується, він видаляє його з робочого каталогу.
Майкл

1
@Nikhil Чи можете ви пояснити, де ця відповідь неправильна?
Нед Батчелдер

1
@NedBatchelder Жодне з пунктів не є правильним: оскільки не використовується ніколи, коли ці команди використовуються.
Ніхіл

1
@Nikhil Можливо, ви маєте на увазі те, що оригінальний комітет все ще існує, що правда. Але гілка була змінена, так що комісія вже не є частиною гілки. Чи згодні ми з цим?
Нед Батчелдер

69

Зауважте, що це спрощене пояснення, яке є першим кроком у розумінні цього складного функціоналу.

Може бути корисним для візуальних учнів, які хочуть уявити, як виглядає їхній проект після кожної з цих команд:


Для тих, хто використовує термінал із увімкненим кольором (git config --global color.ui auto):

git reset --soft A і ви побачите речі B та C зеленим кольором (поетапно та готові до вчинення)

git reset --mixed A(або git reset A), і ви побачите речі B і C червоним кольором (нестандартним і готовим до постановки (зеленим), а потім скоєним)

git reset --hard A і ви більше не побачите змін B і C ніде (буде так, ніби їх ніколи не було)


Або для тих, хто використовує програму GUI типу "Tower" або "SourceTree"

git reset --soft A і ви побачите матеріали B і C в області "поетапних файлів", готових до введення

git reset --mixed A(або git reset A), і ви побачите матеріали B і C в області "нестандартних файлів", готових до переміщення в інсценовані та потім скоєні

git reset --hard A і ви більше не побачите змін B і C ніде (буде так, ніби їх ніколи не було)


1
Це в омані в кращому випадку: ваша відповідь звучить так, ніби git resetлише змінює вигляд git statusрезультату.
jub0bs

3
Я бачу вашу думку, але не погоджуюся, тому що, будучи візуальним учнем, бачення того, як мій проект 'виглядав' після використання 3 команд, нарешті допомогло мені зрозуміти, що вони роблять!
timhc22

Я бачив, що це більше як ідея "приступ для манекенів", щоб допомогти людям полегшити те, що відбувається насправді. Чи можете ви подумати, як це можна було б покращити, щоб не вводити в оману
timhc22

8
Ні, нам не потрібно змінювати цю відповідь. Він забезпечує зручний "шпаргалка". Подумайте над цим: м’який = зелений, змішаний = червоний, жорсткий = нічого (значить, пропав)! Як легко запам’ятати! Для тих новачків, які навіть не розуміють, що означають ці кольори, вони знають занадто мало про git, і все одно вони будуть робити важкі уроки по дорозі, і це НЕ винна @unegma! До речі, я просто підтримую цю відповідь, щоб протидіяти попередньому протизаконному голосуванню. Гарна робота, @unegma!
RayLuo

5
Це послужило чудовим додатковим резюме, щоб краще зрозуміти внутрішню роботу, коли я читав їх в інших місцях. Дякую!
spex

24

Всі інші відповіді великі, але я вважаю , що краще зрозуміти їх, розбиваючи файли на три категорії: unstaged, staged, commit:

  • --hard повинно бути легко зрозуміти, воно відновлює все
  • --mixed (за замовчуванням) :
    1. unstagedфайли: не змінюються
    2. staged файли: перейти до unstaged
    3. commit файли: перейти до unstaged
  • --soft:
    1. unstagedфайли: не змінюються
    2. stagedфайли: не змінювати
    3. commit файли: перейти до staged

Підсумовуючи:

  • --softопція перемістить все (крім unstagedфайлів) уstaging area
  • --mixed варіант перенесе все в unstaged area

22

Ось основне пояснення для користувачів TortoiseGit:

git reset --softі --mixedзалиште свої файли недоторканими.

git reset --hardнасправді змініть ваші файли так, щоб вони відповідали зобов'язанню, яке ви скинули.

У TortoiseGit поняття індексу дуже приховане GUI. Коли ви змінюєте файл, вам не доведеться запускати, git addщоб додати зміни до області / індексу. Якщо просто мати справу з модифікаціями існуючих файлів, які не змінюють імен файлів, git reset --softі --mixedє однаковими! Різницю ви помітите лише в тому випадку, якщо ви додали нові файли або перейменовані файли. У цьому випадку, якщо ви запускаєте git reset --mixed, вам доведеться знову додати свої файли зі списку Not Versioned Files .


Ця відповідь є дуже неясною щодо різниці між м'яким та змішаним. і навіть зневажливо заявляє про це. Ця наступна відповідь на це ясніше. stackoverflow.com/questions/2530060 / ...
barlop

2
Як користувач Github Desktop, який також має таку саму поведінку, ця відповідь дає мені ясність, чому я постійно плутаюсь щодо --mixedта --soft.
Чень Лі Йонг

20

У цих випадках мені подобається наочне зображення, яке, можливо, сподіваюся пояснити це:

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

введіть тут опис зображення

Тому кожен ефект відрізняється сферами застосування

  1. Hard => WorkingDir + індекс + HEAD
  2. Змішаний => Індекс + ГОЛА
  3. Soft => HEAD only (покажчик та робочий режим не змінилися).

15

Три види жалю

Багато існуючих відповідей, схоже, не відповідають дійсному питанню. Вони стосуються того, що роблять команди, а не про те, що ви (користувач) хочете - випадок використання . Але саме про це запитували ОП!

Можливо, буде корисніше описати опис з точки зору того, що саме ви пошкодуєте, коли даєте git resetкоманду. Скажімо, у нас це є:

A - B - C - D <- HEAD

Ось кілька можливих жалю і що з ними робити:

1. Я шкодую, що B, C і D - це не один вчинок.

git reset --soft A. Тепер я можу негайно здійснити і скористатись усіма змінами, оскільки A - це одна фіксація.

2. Я шкодую, що B, C і D - це не десять комітів.

git reset --mixed A. Коміти пішли, і індекс повернувся на A, але робоча область все ще виглядає так, як це було після D. Так що тепер я можу додавати і виконувати цілком різні групи.

3. Я шкодую, що на цій гілці трапилися B, C та D ; Я б хотів, щоб я розгалужувався після А, і вони траплялися на тій іншій гілці.

Зробіть нову гілку otherbranch, а потім git reset --hard A. Поточна гілка зараз закінчується на А, otherbranchвипливає з неї.

(Звичайно, ви також можете скористатися жорстким скиданням, оскільки хочете, щоб B, C і D ніколи не бували.)


5

Не потрібно змушувати себе пам’ятати різниці між ними. Подумайте, як ви насправді взяли на себе зобов’язання.

1.Внесіть деякі зміни.

2.git додати.

3.gc -m "Я щось зробив"

М'який, змішаний і жорсткий спосіб дозволяє відмовитися від операцій, які ви робили з 3 до 1.

М'який "прикинувся", що ніколи не побачив, щоб ти зробив "gc -m".

Змішаний "зробив вигляд", що ніколи не побачив, що ти зробив "git add".

Важко "прикинувся", що ніколи не побачив, що ви зробили зміни файлу.


4

Перш ніж перейти до цих трьох варіантів, слід зрозуміти 3 речі.

1) Історія / ГОЛОВА

2) Етап / покажчик

3) Робочий каталог

скинути --soft: історія змінена, HEAD змінено, робочий каталог не змінено.

скинути - змішано: історію змінили, змінили HEAD, змінили робочий каталог з нестандартними даними.

скинути - тверда: історія змінилася, змінилася HEAD, змінилася робоча директорія із втраченими даними.

Завжди безпечно їхати з Git --soft. Слід використовувати інший варіант у складній вимозі.


3

Тут є ряд відповідей з помилковим уявленням про git reset --soft. Хоча існує специфічна умова, в якій git reset --softбуде змінюватися HEAD(починаючи з відокремленого стану голови), як правило (і за призначенням), воно переміщує посилання гілки, яке ви перевірили на даний момент. Звичайно, це не може зробити, якщо у вас немає філії, яку ви перевірили (отже, конкретна умова, де git reset --softлише зміниться HEAD).

Я вважав, що це найкращий спосіб задуматися git reset. Ви не просто рухатися HEAD( все це робить ), ви також переміщення гілки реф , наприклад master. Це схоже на те, що відбувається під час запуску git commit(поточна гілка рухається разом із HEAD), за винятком того, що замість створення (та переходу до) нової фіксації, ви переходите до попередньої фіксації.

Це сенс resetзмінити гілку на щось інше, ніж нове зобов’язання, а не змінити HEAD. Це можна побачити в прикладі документації:

Скасуйте комісію, зробивши її темою

          $ git branch topic/wip     (1)
          $ git reset --hard HEAD~3  (2)
          $ git checkout topic/wip   (3)
  1. Ви домовились про деякі зобов’язання, але розумієте, що вони були передчасними перебувати у галузі "майстра". Ви хочете продовжувати шліфування їх у темі, тому створіть гілку "тема / витирання" з поточної HEAD.
  2. Перемотайте головну гілку, щоб позбутися цих трьох коміттів.
  3. Перейдіть на гілку "тема / витримка" та продовжуйте працювати.

У чому сенс цієї серії команд? Ви хочете перенести гілку тут master, тож поки ви masterзареєструвались, ви біжите git reset.

Тут найкраще проголосовано відповідь, але я подумав, що я додам це, щоб виправити кілька відповідей з оманами.

Змініть свою філію

git reset --soft <ref>: Скидає покажчик філії в даний час витягнутої гілки до вчиняє в вказаним посиланням, <ref>. Файли у вашому робочому каталозі та індексі не змінюються. Здійснення цього етапу поверне вас туди, де ви були перед git resetкомандою.

Змініть також свій індекс

git reset --mixed <ref>

або рівнозначно

git reset <ref>:

Здійснює те, що --softробить AND, також скидає індекс на відповідність фіксуванню за вказаною посиланням. Хоча git reset --soft HEADнічого не робить (тому що він говорить про переміщення перевіреної гілки до перевіреної гілки), git reset --mixed HEADабо, що рівно git reset HEAD, є загальною і корисною командою, оскільки вона скидає індекс до стану останньої комісії.

Змініть також свій робочий каталог

git reset --hard <ref>: робить те, що --mixedробить AND, також перезаписує ваш робочий каталог. Ця команда аналогічна git checkout <ref>, за винятком того, що (і це вирішальний момент щодо reset) всіх форм git resetпереміщення HEADвказівки на гілку .

Примітка про "таку та таку команду рухає ГОЛОВУ":

Не корисно сказати, що команда рухає HEAD. Будь-яка команда, яка змінюється там, де ви знаходитесь у вашій історії фіксації, переміщує HEAD. Ось що HEAD є , вказівник туди, де ви знаходитесь. HEADце ти , і так будеш рухатись, коли робиш.


2
"переміщення гілки ref": хороший момент. Довелося оновити stackoverflow.com/a/5203843/6309 .
VonC

1

Коротка відповідь, у якому контексті використовуються 3 варіанти:

Щоб зберегти поточні зміни в коді, але переписати історію фіксації:

  • soft: Ви можете здійснити все відразу і створити нову комісію за допомогою нового опису (якщо ви використовуєте torotise git або будь-який інший графічний інтерфейс, це саме той, який ви можете використовувати, оскільки ви все одно можете поставити галочку, які файли ви хочете зробити, і зробити кілька здійснює такий спосіб з різними файлами. У Sourcetree всі файли будуть інсценовані для фіксації.)
  • mixed: Вам доведеться знову додати окремі файли до індексу перед тим, як зробити зобов’язання (у Sourcetree всі змінені файли будуть нестатованими)

Щоб також втратити свої зміни в коді:

  • hard: ви не просто переписуєте історію, але й втрачаєте всі зміни до моменту скидання

Я не став м'яким і змішаним у цьому випадку. Якщо вам доведеться взяти на себе зобов'язання, то що було повернено? ви збираєтесь відновити або повторно внести зміни (таким чином повертаєтесь до початкового стану?)
Джон Літтл

Повторне підтвердження змін. Зворотного зобов’язання не буде.
Нікпік

1

Основна різниця між різними параметрами команди git reset наведена нижче.

  • --soft: скидає HEAD лише до вибраного вами зобов'язання. Працює в основному так само, як і git checkout, але не створює відокремленого стану голови.
  • --mixed (опція за замовчуванням): Скидає HEAD до вибраного вами комітету як в історії, так і скасовує зміни в індексі.
  • --hard: Скидає HEAD до вибору, який ви вибрали в історії, скасовує зміни в індексі та скасовує зміни у вашому робочому каталозі.

1

--soft: Повідомляє Git про скидання HEAD на інший фіксатор, тому індекс та робочий каталог не зміняться жодним чином. Усі файли, змінені між початковою HEAD і фіксацією, будуть інсценовані.

--mixed: Так само, як і м'які, це поверне HEAD до іншого вибору. Він також скине індекс, щоб відповідати йому, поки робоча директорія не буде торкатися. Усі зміни залишаться у робочому каталозі та відображатимуться як змінені, але не поетапні.

--hard: Це скидає все - це скидає HEAD назад до іншого коміту, скидає індекс, щоб відповідати йому, і скидає робочий каталог, щоб відповідати йому також.

Основна відмінність --mixedі --softполягає в тому, змінюється чи ні ваш індекс. Більше про це дивіться тут .


0

Відповідь mkarasek чудова, просто кажучи, ми можемо сказати ...

  • git reset --soft: встановіть HEADцільове зобов’язання, але збережіть зміни, відхилені від останніх комісій
  • git reset --mixed: це те саме, git reset --softале єдина відмінність, якщо він не ставить свої зміни від останніх комісій
  • git reset --hard: встановіть HEADна вказаному вами зобов’язанні і скиньте всі ваші зміни з останніх зобов’язань, включаючи неприйняті зміни.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.