Я видел интересные посты, объясняющие тонкости о git reset
.
К сожалению, чем больше я об этом читаю, тем больше мне кажется, что я не до конца понимаю. Я родом из SVN, а Git - совершенно новая парадигма. Я легко получил Mercurial, но Git гораздо более технический.
Я думаю, что git reset
близко hg revert
, но, кажется, есть различия.
Так что же git reset
делать? Пожалуйста, включите подробные объяснения о:
- варианты
--hard
,--soft
и--merge
; - странные обозначения, которые вы используете с
HEAD
такими какHEAD^
иHEAD~1
; - конкретные варианты использования и рабочие процессы;
- последствия для рабочей копии,
HEAD
и ваш глобальный уровень стресса.
Ответы:
В общем,
git reset
функция заключается в том, чтобы взять текущую ветвь и сбросить ее так, чтобы она указывала куда-то еще, и, возможно, перенести индекс и рабочее дерево. Конкретнее, если ваша основная ветвь (в настоящее время проверенная) выглядит так:и вы понимаете, что хотите, чтобы мастер указывал на B, а не на C, вы будете
git reset B
перемещать его туда:Отступление: это отличается от проверки. Если вы бежите
git checkout B
, вы получите это:Вы оказались в отдельном состоянии HEAD.
HEAD
, рабочее дерево, индекс все совпадаютB
, но основная ветвь осталась вC
. Если вы сделаете новый коммитD
в этот момент, вы получите это, что, вероятно, не то, что вы хотите:Помните, сброс не делает коммитов, он просто обновляет ветку (которая является указателем на коммит), чтобы указывать на другой коммит. Остальное - просто детали того, что происходит с вашим индексом и рабочим деревом.
Случаи использования
Я расскажу о многих из основных вариантов использования в
git reset
рамках моего описания различных вариантов в следующем разделе. Это действительно может быть использовано для самых разных вещей; общий поток состоит в том, что все они включают в себя сброс ветви, индекса и / или рабочего дерева для указания / совпадения с данным коммитом.Вещи, чтобы быть осторожным
--hard
может заставить вас действительно потерять работу. Это изменяет ваше рабочее дерево.git reset [options] 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...]
, которая сбрасывает указанные пути в их состояние из данного коммита. Если пути не указаны, все дерево сбрасывается, а если фиксация не указана, она считается HEAD (текущая фиксация). Это общий шаблон для команд git (например, checkout, diff, log, хотя точная семантика различается), поэтому это не должно вызывать удивления.Например,
git reset other-branch path/to/foo
все в пути / to / foo сбрасывается в его состояние в other-branch,git reset -- .
сбрасывает текущий каталог в его состояние в HEAD, а простойgit reset
сбрасывает все в его состояние в HEAD.Основное дерево работы и параметры индекса
Существует четыре основных варианта управления тем, что происходит с вашим рабочим деревом и индексом во время сброса.
Помните, что индекс - это «область подготовки» git - это то, куда идут вещи, когда вы говорите,
git add
готовясь к фиксации.--hard
делает все совпадающим с коммитом, на который вы сбросили. Это проще всего понять, наверное. Все ваши локальные изменения сгущаются. Одним из основных применений является срыв вашей работы, но не переключение коммитов:git reset --hard
означаетgit reset --hard HEAD
, т.е. не меняйте ветку, а избавляйтесь от всех локальных изменений. Другой - это просто перемещение ветви из одного места в другое и синхронизация индекса и рабочего дерева. Это тот, который действительно может заставить вас потерять работу, потому что он изменяет ваше рабочее дерево. Будьте очень уверены, что хотите выбросить местную работу, прежде чем запускать какую-либоreset --hard
.--mixed
по умолчанию, т.е.git reset
означаетgit reset --mixed
. Сбрасывает индекс, но не рабочее дерево. Это означает, что все ваши файлы не повреждены, но любые различия между исходным коммитом и исходным коммитом будут отображаться как локальные изменения (или файлы без отслеживания) со статусом git. Используйте это, когда вы понимаете, что сделали плохие коммиты, но хотите сохранить всю работу, которую вы сделали, чтобы вы могли исправить ее и подтвердить. Для фиксации вам необходимо снова добавить файлы в индекс (git add ...
).--soft
не касается индекса или рабочего дерева. Все ваши файлы не повреждены, как при использовании--mixed
, но все изменения отображаются какchanges to be committed
со статусом git (т. Е. Проверены при подготовке к фиксации). Используйте это, когда вы поймете, что сделали плохие коммиты, но все хорошо - все, что вам нужно сделать, это подтвердить это по-другому. Индекс не тронут, поэтому вы можете зафиксировать его немедленно, если хотите - итоговый коммит будет иметь все то же содержимое, что и до сброса.--merge
был добавлен недавно и предназначен для того, чтобы помочь вам прервать неудачное слияние. Это необходимо, поскольку наgit merge
самом деле вы можете попытаться выполнить слияние с грязным рабочим деревом (с локальными изменениями), если эти изменения находятся в файлах, не затронутых слиянием.git reset --merge
сбрасывает индекс (например,--mixed
все изменения отображаются как локальные изменения) и сбрасывает файлы, затронутые слиянием, но оставляет другие в покое. Надеемся, что это восстановит все до того, как было до неудачного слияния. Вы будете обычно использовать его какgit reset --merge
(имеется в видуgit reset --merge HEAD
), потому что вы хотите только сбросить слияние, а не перемещать ветку. (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
означает второго родителя коммита . Помните, что у обычного коммита слияния есть два родителя - первый родитель - это коммит слияния, а второй родитель - коммит, который был слит. Вообще, у слияний может быть сколько угодно родителей (слияния осьминогов).^
и~
могут быть соединены вместе, напримерHEAD~3^2
, во втором родительском элементе предка третьего поколенияHEAD
,HEAD^^2
во втором родительском элементе первого родительского элементаHEAD
или дажеHEAD^^^
, что эквивалентноHEAD~3
.источник
Помните, что у
git
вас есть:HEAD
указатель , который говорит вам , что совершить вы работаетеВ порядке возрастания степени опасности:
--soft
перемещается,HEAD
но не касается области подготовки или рабочего дерева.--mixed
перемещаетHEAD
и обновляет область подготовки, но не рабочее дерево.--merge
перемещаетHEAD
, сбрасывает промежуточную область и пытается переместить все изменения в вашем рабочем дереве в новое рабочее дерево.--hard
перемещаетHEAD
и настраивает вашу область подготовки и рабочее дерево в новоеHEAD
, выбрасывая все.--soft
когда вы хотите перейти к другому коммиту и исправить все, не теряя своего места. Это довольно редко, что вам нужно это.-
-
Используйте
--mixed
(по умолчанию), когда вы хотите увидеть, как выглядят другие коммиты, но вы не хотите потерять какие-либо изменения, которые у вас уже есть.Используется,
--merge
когда вы хотите перейти на новое место, но включите изменения, которые у вас уже есть, в это рабочее дерево.Используйте,
--hard
чтобы уничтожить все и начать новый лист на новом коммите.источник
reset --merge
. Он не выполняет трехстороннее слияние. Это действительно только для сброса конфликтующих слияний, как описано в документации. Вы хотите использовать,checkout --merge
чтобы делать то, о чем вы говорите. Если вы хотите переместить ветку, я думаю, что единственный способ - это выполнить проверку / сброс, чтобы тащить ее вперед.reset --merge
с какой-либо целью, кроме (по умолчанию)HEAD
, потому что в случаях, помимо прерывания конфликтующего слияния, он отбрасывает информация, которую вы могли бы сохранить.git reset
иgit reset -- .
.Пост Reset Demystified в блоге Pro Git дает очень легкое объяснение
git reset
иgit checkout
.После всего полезного обсуждения в верхней части этого поста автор сводит правила к следующим простым трем шагам:
источник
Когда вы делаете что-то для git, вам сначала нужно внести изменения (добавить в индекс). Это означает, что вам нужно добавить в git все файлы, которые вы хотите включить в этот коммит, прежде чем git считает их частью коммита. Давайте сначала посмотрим на изображение git-репо:
теперь все просто. Надо работать в рабочем каталоге, создавать файлы, каталоги и все. Эти изменения не отслеживаются. Чтобы их отслеживать, нам нужно добавить их в индекс git с помощью команды git add . После того, как они добавлены в Git Index. Теперь мы можем зафиксировать эти изменения, если мы хотим отправить их в репозиторий git.
Но неожиданно мы узнали, что при фиксации у нас есть один дополнительный файл, который мы добавили в индекс, не требуется для добавления в git-репозиторий. Это означает, что мы не хотим этот файл в индексе. Теперь вопрос в том, как удалить этот файл из индекса git. Поскольку мы использовали git add, чтобы поместить их в индекс, было бы логично использовать git rm ? Неправильно! git rm просто удалит файл и добавит удаление в индекс. Так что же делать сейчас:
Использование: -
Он очищает ваш индекс, оставляет ваш рабочий каталог нетронутым. (просто unstaging все).
Это может быть использовано с рядом опций. Существует три основных варианта использования git reset: --hard, --soft и --mixed . Они влияют на то, что получает сброс в дополнение к указателю HEAD при сбросе.
Во-первых, --hard сбрасывает все. Ваш текущий каталог будет точно таким же, как если бы вы следили за этой веткой все время. Рабочий каталог и индекс изменяются на этот коммит. Это версия, которую я использую чаще всего. git reset --hard это что-то вроде svn revert .
Далее, полная противоположность - софт , не сбрасывает ни рабочее дерево, ни индекс. Он только перемещает указатель HEAD. Это оставляет ваше текущее состояние с любыми изменениями, отличными от коммита, на который вы переключаетесь, на месте в вашем каталоге и «подготовленным» для фиксации. Если вы делаете коммит локально, но не отправляете коммит на git-сервер, вы можете сбросить предыдущий коммит и повторить с хорошим сообщением коммита.
Наконец, --mixed сбрасывает индекс, но не рабочее дерево. Таким образом, изменения все еще присутствуют, но они «неустановлены» и должны быть добавлены в git add или git commit -a . мы используем это иногда, если мы зафиксировали больше, чем намеревалось, с помощью git commit -a, мы можем отменить коммит с помощью git reset --mixed, добавить вещи, которые мы хотим зафиксировать, и просто зафиксировать их.
Разница между git revert и git reset : -
Проще говоря, git reset - это команда «исправить ошибки, не переданные», а git revert - команда «исправить ошибки» .
Это означает, что если мы допустили какую-то ошибку в каком-либо изменении, зафиксировали и отправили то же самое в git repo, то git revert является решением. И если в случае, если мы определили ту же ошибку до нажатия / подтверждения, мы можем использовать git reset, чтобы исправить проблему.
Я надеюсь, что это поможет вам избавиться от путаницы.
источник
git reset HEAD
по умолчанию?--hard
,--soft
Или--mixed
? Отличный ответ, кстати.git reset --hard
вы потеряете некоторые данные. И есть пункт, который может быть неправильным (хотя я не уверен на 100% ... все еще учусь!): Говоря о--mixed
вас, вы говорите, что "мы используем это иногда, если мы совершали больше, чем намеревались, с помощью git commit -a". Вы имели в виду: «если бы мы поставили больше, чем хотелиgit stage .
»? Если вы действительно допустили это, я думаю, что уже слишком поздно (как вы говорите в конце, git reset - это команда для «исправления ошибок»),TL; DR
БОЛЬШАЯ ВЕРСИЯ
Но это, очевидно, упрощенно, поэтому многие довольно подробные ответы. Для меня было больше смысла читать
git reset
в контексте отмены изменений. Например, увидеть это:С https://www.atlassian.com/git/tutorials/undoing-changes/git-reset
и это
С https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations
источник
Пожалуйста, имейте в виду, что это упрощенное объяснение, предназначенное в качестве первого шага в попытке понять эту сложную функциональность.
Может быть полезно для визуальных учеников, которые хотят визуализировать состояние своего проекта после каждой из следующих команд:
Для тех, кто использует Терминал с включенным цветом (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 (как если бы они никогда не существовали)Или для тех, кто использует программу с графическим интерфейсом, как «Башня» или «SourceTree»
git reset --soft A
и вы увидите вещи B и C в области 'готовые файлы', готовые к фиксацииgit reset --mixed A
(илиgit reset A
), и вы увидите вещи B и C в области 'unstaged files', готовые для перемещения в промежуточную, а затем зафиксированныеgit reset --hard A
и вы больше нигде не увидите изменений B и C (как если бы они никогда не существовали)источник
Оформить заказ указывает на конкретный коммит.
Сброс указывает ветку на конкретный коммит. (Ветвь - это указатель на коммит.)
Кстати, если ваша голова не указывает на коммит, на который также указывает ветка, то у вас оторванная голова.(оказалось не так. Смотрите комментарии ...)источник