На простом английском языке, что делает "git reset"?

Я видел интересные сообщения, объясняющие тонкости о git reset.

К сожалению, чем больше я читал об этом, тем больше кажется, что я не понимаю его полностью. Я родом из SVN-фона, а Git - это совершенно новая парадигма. Я легко получил ртуть, но Git гораздо более технический.

Я думаю, что git reset близок к hg revert, но, похоже, есть различия.

Так что же делает git reset? Пожалуйста, укажите подробные объяснения:

  • параметры --hard, --soft и --merge;
  • странное обозначение, которое вы используете с HEAD, например HEAD^ и HEAD~1;
  • конкретные варианты использования и рабочие потоки;
  • последствия для рабочей копии, HEAD и уровень глобального стресса.

Ответ 1

В общем, функция git reset должна взять текущую ветку и reset, чтобы она указывала где-то в другом месте, и, возможно, приводила индекс и рабочее дерево. Более конкретно, если ваша ведущая ветка (в настоящее время проверена) выглядит следующим образом:

- A - B - C (HEAD, master)

и вы понимаете, что хотите, чтобы хозяин указывал на B, а не на C, вы будете использовать git reset B для перемещения туда:

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

Отступление: это отличается от проверки. Если вы запустите git checkout B, вы получите следующее:

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

Вы попали в отдельное состояние HEAD. HEAD, дерево работы, индекс все совпадают B, но главная ветвь осталась в C. Если вы создадите новый фиксатор D в этот момент, вы получите это, что, вероятно, не то, что вы хотите:

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

Помните, что reset не выполняет коммиты, он просто обновляет ветку (которая является указателем на фиксацию), чтобы указать на другую фиксацию. Остальное - это просто детали того, что происходит с вашим индексом и деревом.

Использовать случаи

В моих описаниях различных опций в следующем разделе описываются многие основные варианты использования git reset. Он действительно может использоваться для самых разных вещей; общий поток заключается в том, что все они связаны с сбросом ветки, индекса и/или дерева работы, чтобы указать/сопоставить данный коммит.

Что нужно соблюдать

  • --hard может привести к потере работы. Он изменяет ваше дерево работы.

  • git reset [options] commit может привести к (потере) сбоям. В приведенном выше примере игрушек мы потеряли commit C. Он все еще находится в репо, и вы можете найти его, посмотрев на git reflog show HEAD или git reflog show master, но он больше не доступен из любой ветки.

  • Git навсегда удаляет такие коммиты через 30 дней, но до тех пор вы можете восстановить C, снова указав ветку на нее (git checkout C; git branch <new branch name>).

Аргументы

Перефразируя man-страницу, наиболее распространенное использование имеет форму git reset [<commit>] [paths...], которая будет reset заданными путями к их состоянию из данного фиксации. Если пути не предусмотрены, все дерево reset, и если коммит не указан, он считается HEAD (текущая фиксация). Это общий шаблон в командах git (например, checkout, diff, log, хотя точная семантика меняется), поэтому не должно быть слишком неожиданным.

Например, git reset other-branch path/to/foo сбрасывает все в пути/в/foo в его состояние в другой ветки, git reset -- . сбрасывает текущую директорию в ее состояние в HEAD, а простой git reset сбрасывает все в свое состояние в ГОЛОВА.

Основное дерево работы и параметры индекса

Существует четыре основных параметра для контроля того, что происходит с вашим деревом и индексом во время reset.

Помните, что индекс является git "промежуточной областью" - там, где все идет, когда вы говорите git add в процессе подготовки к фиксации.

  • --hard делает все, что соответствует фиксации, с которой у вас есть reset to. Вероятно, это легче всего понять. Все ваши локальные изменения сбиты. Одно из основных применений - это сдувание вашей работы, но не переключение: git reset --hard означает git reset --hard HEAD, т.е. Не меняет ветвь, но избавляется от всех локальных изменений. Другой просто перемещает ветку из одного места в другое и сохраняет дерево индексов/рабочих данных. Это тот, который действительно может заставить вас потерять работу, потому что она изменяет ваше дерево работы. Будьте очень уверены, что хотите выбросить локальную работу, прежде чем запускать любой reset --hard.

  • --mixed - значение по умолчанию, т.е. git reset означает git reset --mixed. Он сбрасывает индекс, но не дерево работы. Это означает, что все ваши файлы не повреждены, но любые различия между исходной фиксацией и той, что вы reset, будут отображаться как локальные модификации (или необработанные файлы) с статусом git. Используйте это, когда понимаете, что совершили какие-то плохие коммиты, но вы хотите сохранить всю работу, которую вы сделали, чтобы вы могли ее исправить и подтвердить. Для фиксации вам нужно будет снова добавить файлы в индекс (git add ...).

  • --soft не касается индекса или дерева работ. Все ваши файлы не повреждены, как и при использовании --mixed, но все изменения отображаются как changes to be committed со статусом git (т.е. Отмечены при подготовке к фиксации). Используйте это, когда понимаете, что совершили какие-то плохие коммиты, но все работает хорошо - все, что вам нужно сделать, это повторить его по-другому. Индекс нетронутый, поэтому вы можете немедленно зафиксировать его, если хотите - результирующая фиксация будет иметь все тот же контент, что и раньше, чем вы reset.

  • --merge был добавлен недавно и призван помочь вам прервать сбой слияния. Это необходимо, потому что git merge фактически позволит вам попробовать слияние с грязным деревом работ (с локальными изменениями), если эти изменения находятся в файлах, не затронутых слиянием. git reset --merge сбрасывает индекс (например, --mixed - все изменения отображаются как локальные модификации) и сбрасывает файлы, затронутые слиянием, но оставляет остальных в покое. Это, надеюсь, восстановит все до того, как это произошло до неудачного слияния. Обычно вы используете его как git reset --merge (что означает git reset --merge HEAD), потому что вы хотите только reset свернуть слияние, а не переместить ветвь. (HEAD еще не обновлено, так как слияние завершилось с ошибкой)

    Чтобы быть более конкретным, предположим, что вы модифицировали файлы A и B, и вы пытаетесь объединиться в ветки, в которой были изменены файлы C и D. По какой-то причине слияние не удается, и вы решили ее прервать. Вы используете git reset --merge. Он возвращает C и D к тому, как они были в HEAD, но оставляет ваши модификации только для A и B, так как они не были частью попытки слияния.

Хотите узнать больше?

Я действительно думаю, что man git reset действительно хорош для этого - возможно, вам нужно немного понять, как git работает для них, чтобы действительно утонуть. В частности, если вы внимательно изучите их, очень полезны те таблицы, в которых подробно описываются состояния файлов в индексе и дереве работ для всех различных вариантов и случаев. (Но да, они очень плотные - они передают очень много вышеуказанной информации в очень сжатой форме.)

Странное обозначение

"Странная нотация" (HEAD^ и HEAD~1), которую вы упоминаете, является просто сокращением для указания коммитов, без использования имени хэша, такого как 3ebe3f6. Он полностью задокументирован в "указание ревизий" раздела справочной страницы для git -rev-parse, с большим количеством примеров и связанного синтаксиса. Каретка и тильда на самом деле означают разные вещи:

  • HEAD~ сокращен для HEAD~1 и означает фиксацию первого родителя. HEAD~2 означает первый родительский родительский элемент. Подумайте о HEAD~n как "n совершает действия перед HEAD" или "предком n-го поколения HEAD".
  • HEAD^ (или HEAD^1) также означает фиксацию первого родителя. HEAD^2 означает фиксацию второго родителя. Помните, что нормальное объединение слияния имеет два родителя - первый родитель - это объединенный в commit, а второй родитель - это объединение, которое было объединено. В общем, слияния могут фактически иметь сколько угодно родителей (осьминог сливается).
  • Операторы ^ и ~ могут быть нанизаны вместе, как и в HEAD~3^2, второй родитель предка третьего поколения HEAD, HEAD^^2, второго родителя первого родителя HEAD или даже HEAD^^^, что эквивалентно HEAD~3.

caret and tilde

Ответ 2

Помните, что в git у вас есть:

  • указатель HEAD, в котором сообщается, что вы совершаете над
  • рабочее дерево, представляющее состояние файлов в вашей системе
  • промежуточная область (также называемая индексом), которая "ступенями" изменяется, так что впоследствии они могут быть совершены вместе.

Пожалуйста, укажите подробные объяснения:

--hard, --soft и --merge;

В порядке возрастания опасностей:

  • --soft перемещается HEAD, но не касается области постановки или рабочего дерева.
  • --mixed перемещает HEAD и обновляет промежуточную область, но не рабочее дерево.
  • --merge перемещает HEAD, сбрасывает промежуточную область и пытается переместить все изменения в рабочем дереве в новое рабочее дерево.
  • --hard перемещает HEAD и настраивает вашу промежуточную область и рабочее дерево на новый HEAD, отбрасывая все.

конкретные варианты использования и рабочие процессы;

  • Используйте --soft, когда вы хотите перейти на другую фиксацию и исправить вещи без "потери вашего места". Это довольно редко, что вам нужно это.

-

# git reset --soft example
touch foo                            // Add a file, make some changes.
git add foo                          // 
git commit -m "bad commit message"   // Commit... D'oh, that was a mistake!
git reset --soft HEAD^               // Go back one commit and fix things.
git commit -m "good commit"          // There, now it right.

-

  • Используйте --mixed (который по умолчанию), когда вы хотите увидеть, как выглядят вещи на другом коммите, но вы не хотите терять никаких изменений, которые у вас уже есть.

  • Используйте --merge, когда вы хотите перейти на новое место, но включите изменения, которые у вас уже есть в рабочем дереве.

  • Используйте --hard, чтобы уничтожить все и запустить новый сланец при новом фиксации.

Ответ 3

Пост Reset Demystified в блоге Pro Git дает очень легкое объяснение git reset git checkout.

После всего полезного обсуждения в верхней части этого поста автор сводит правила к следующим трем простым шагам:

Это в основном это. Команда reset перезаписывает эти три дерева в определенном порядке, останавливаясь, когда вы указываете это.

  1. Переместите любую ветку, на которую указывает HEAD (остановите, если --soft)
  2. ПОТОМ, сделайте так, чтобы Индекс выглядел так (остановитесь здесь, если --hard)
  3. ТОГДА сделайте так, чтобы рабочий каталог выглядел так

Есть также --merge и --keep, но я бы предпочел пока упростить ситуацию - это будет для другой статьи.

Ответ 4

Когда вы совершаете что-то в git, вам сначала нужно сгенерировать (добавить в индекс) свои изменения. Это означает, что вы должны git добавить все файлы, которые вы хотите включить в этот коммит, прежде чем git считает их частью коммита. Сначала рассмотрим образ репо git: enter image description here

так, теперь его просто. Мы должны работать в рабочем каталоге, создавать файлы, каталоги и все. Эти изменения являются неотслеживаемыми изменениями. Чтобы их отслеживать, нам нужно добавить их в индекс git, используя команду git добавить. Как только они добавляются в индекс git. Теперь мы можем зафиксировать эти изменения, если мы хотим переместить их в репозиторий git.

Но неожиданно мы узнали, что при добавлении одного дополнительного файла, который мы добавили в индекс, не требуется вставлять в репозиторий git. Это означает, что мы не хотим, чтобы этот файл находился в индексе. Теперь вопрос заключается в том, как удалить этот файл из индекса git, так как мы использовали git add, чтобы поместить их в индекс, было бы логично использовать git rm? Неправильно! git rm просто удалит файл и добавит удаление в индекс. Итак, что теперь делать:

Использование: -

git reset

Он очищает ваш индекс, не оставляет рабочий каталог. (просто все не все).

Его можно использовать с количеством опций с ним. Существует три основных варианта использования git reset: --hard, --soft и --mixed. Они влияют на то, что получает reset в дополнение к указателю HEAD, когда вы reset.

Во-первых, - жесткий сбрасывает все. Ваш текущий каталог будет таким же, как если бы вы следили за этой веткой. Рабочий каталог и индекс изменяются на этот коммит. Это версия, которую я использую чаще всего. git reset --hard - это что-то вроде svn revert.

Далее, полная противоположность -soft не работает reset рабочего дерева или индекса. Он перемещает указатель HEAD. Это оставляет текущее состояние с любыми изменениями, отличными от фиксации, которую вы переключаете на место в вашем каталоге, и "поставлено" для совершения. Если вы сделаете фиксацию локально, но havent нажали фиксацию на сервер git, вы можете reset выполнить предыдущую фиксацию и повторно подтвердить сообщение с хорошей фиксацией.

Наконец, - смешанный сбрасывает индекс, но не рабочее дерево. Таким образом, изменения все еще существуют, но "нестационарны" и должны быть добавлены git или git commit -a. мы иногда используем это, если мы совершили больше, чем мы имели с git commit -a, мы можем отменить фиксацию с помощью git reset --mixed, добавить вещи, которые мы хотим совершить, и просто зафиксировать их.

Разница между git revert и git reset: -


Простыми словами git reset является командой "исправления ошибок" и git revert. команда "исправленная ошибка" .

Это означает, что если мы допустили некоторую ошибку в некоторых изменениях и совершили ошибку, а затем перетащили то же самое на git repo, то git revert - это решение. И если в случае, если мы идентифицировали ту же ошибку перед нажатием/коммитом, мы можем использовать git reset, чтобы исправить эту проблему.

Я надеюсь, что это поможет вам избавиться от вашей путаницы.

Ответ 5

TL; DR

git reset сбрасывает этап до последнего фиксации. Используйте --hard, а также reset файлы в рабочем каталоге до последнего коммита.

ДОЛГОВЕЧНАЯ ВЕРСИЯ

Но это, очевидно, упрощенное, следовательно, много довольно многословных ответов. Для меня было больше смысла читать git reset в контексте отмены изменений. Например. см. это:

Если git revert является "безопасным" способом отмены изменений, вы можете думать о git reset как опасный метод. Когда вы отмените git reset (и commits больше не ссылаются никакими ссылками или reflog), есть невозможно восстановить исходную копию - это постоянная отмена. Уход должен при использовании этого инструмента, как его единственной команды git, которая может потерять вашу работу.

От https://www.atlassian.com/git/tutorials/undoing-changes/git-reset

и этот

На уровне фиксации сброс - это способ переместить кончик ветки на другую фиксацию. Это можно использовать для удаления фиксаций из текущей ветки.

От https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations

Ответ 6

Помните, что это упрощенное объяснение, предназначенное для первого этапа поиска этой сложной функциональности.

Может быть полезно для зрителей, которые хотят визуализировать, как выглядит их состояние проекта после каждой из этих команд:


Для тех, кто использует терминал с включенным цветом (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 в любом месте (будет, как если бы они никогда не существовали)

Ответ 8

Оформить заказ указывает на конкретный коммит.

Сброс указывает ветку на конкретный коммит. (Ветвь - это указатель на коммит.)

Между прочим, если ваша голова не указывает на коммит, на который также указывает ветвь, то у вас отдельная голова. (оказалось не так. Смотрите комментарии...)