Изменения которые будут включены в коммит используйте git reset head файл чтобы убрать из индекса
Мы всегда готовы подчеркивать бесчисленные возможности, которые предлагает Git, и эта статья не станет исключением. Git известен своей потрясающей способностью отменять практически любые действия! Наверняка на память вам уже приходят тысячи печальных случаев, когда вы делали объединение, а потом понимали, что в ваши планы оно не входило. Даже если вам кажется, что ошибочное объединение— это величайшая неудача всей вашей жизни, сделайте глубокий вдох и дочитайте статью до конца.
Од и н из самых распространенных вопросов в сообществе Git звучит так: “Как откатить git add перед коммитом?” Вы можете отменить действия над конкретным файлом или все внесенные изменения.
Решение, которое потребуется для этого, весьма простое. Чтобы откатить один файл, просто вызовите команду git reset :
Для отмены всех изменений запустите следующее:
Необходимость в откате становится неизбежной, если вы сделали коммит слишком рано и забыли добавить еще несколько файлов. В подобных случаях используется команда amend , чтобы внести изменения, зафиксировать их и сделать коммит снова.
Здесь на помощь приходит еще одна команда класса “отмена”: git revert . Начнем с того, что переключимся на мастер-ветку, используя команду git checkout :
Следующий шаг — запустить команду git log , чтобы получить ID сделанного объединения:
Затем вернитесь к упомянутому коммиту, выполнив следующее:
Используя -m 1 , вы даете Git указание: вернуться к первому родительскому элементу мастер-ветки, куда был совершен коммит объединения. Например, использование -m 2 сказало бы Git вернуться к первому родительскому элементу ветки, откуда пришел запрос на объединение.
Git также предлагает возможность предварительного просмотра, если вы хотите увидеть, что произойдет при объединении веток.
Предлагаем суперкороткий способ отменить команду git reset:
Следом можно запустить команду git reflog , чтобы просмотреть журнал всех обновлений (т.е. переключение веток, сброс, коммит, объединение).
Существует несколько методов для отмены git commit . Давайте рассмотрим их по очереди.
Команду git reset можно использовать для отмены внесенных изменений:
x введите число. Например, если вы укажете
4 , то команда повлияет на четвертый снизу коммит. Если вы не укажете никакое конкретно число, git reset — soft HEAD применится к последнему коммиту.
Когда вы используете команду git reset — soft HEAD , то просто отменяете последний коммит, при этом внесенные изменения останутся в вашем рабочем дереве и в вашем индексе. Поэтому git commit создаст в будущем коммит с теми же самыми изменениями, которые вы “обнулили” перед этим.
Другой метод — это команда git revert HEAD
x ( git reset — hard commit hash ), которая отменяет изменения, указанные последним коммитом в HEAD , и создает новый с возвращенными изменениями:
Этот метод лучше всего работает в случае с общими публичными репозиториями.
Допустим, вы выполнили команду git rebase в локальной ветке git и отправили ее в удаленную ветку. Следом вы поняли, что это не отвечает вашим ожиданиям, и захотели отменить сделанное.
Самый простой способ — найти главный коммит вашей ветки, запустив команду:
Следом необходимо установить туда текущую ветку, воспользовавшись git reset .
В данном случае старым коммитом был HEAD5 .
Вот и все о том, как вы можете отменить наиболее часто используемые команды в Git. Хоть никакой традиционной команды отмены и нет, другие команды git могут помочь вам откатить то, что вы могли сделать по ошибке.
Мы всегда готовы подчеркивать бесчисленные возможности, которые предлагает Git, и эта статья не станет исключением. Git известен своей потрясающей способностью отменять практически любые действия! Наверняка на память вам уже приходят тысячи печальных случаев, когда вы делали объединение, а потом понимали, что в ваши планы оно не входило. Даже если вам кажется, что ошибочное объединение— это величайшая неудача всей вашей жизни, сделайте глубокий вдох и дочитайте статью до конца.
Отмена Git Add
Один из самых распространенных вопросов в сообществе Git звучит так: “Как откатить git add перед коммитом?” Вы можете отменить действия над конкретным файлом или все внесенные изменения.
Решение, которое потребуется для этого, весьма простое. Чтобы откатить один файл, просто вызовите команду git reset :
Для отмены всех изменений запустите следующее:
Необходимость в откате становится неизбежной, если вы сделали коммит слишком рано и забыли добавить еще несколько файлов. В подобных случаях используется команда amend , чтобы внести изменения, зафиксировать их и сделать коммит снова.
Как откатить Git Merge
Здесь на помощь приходит еще одна команда класса “отмена”: git revert . Начнем с того, что переключимся на мастер-ветку, используя команду git checkout :
Следующий шаг — запустить команду git log , чтобы получить ID сделанного объединения:
Затем вернитесь к упомянутому коммиту, выполнив следующее:
Используя -m 1 , вы даете Git указание: вернуться к первому родительскому элементу мастер-ветки, куда был совершен коммит объединения. Например, использование -m 2 сказало бы Git вернуться к первому родительскому элементу ветки, откуда пришел запрос на объединение.
Git также предлагает возможность предварительного просмотра, если вы хотите увидеть, что произойдет при объединении веток.
Как откатить Git Reset
Предлагаем суперкороткий способ отменить команду git reset:
Следом можно запустить команду git reflog , чтобы просмотреть журнал всех обновлений (т.е. переключение веток, сброс, коммит, объединение).
Отмена последних коммитов в Git
Существует несколько методов для отмены git commit . Давайте рассмотрим их по очереди.
Команду git reset можно использовать для отмены внесенных изменений:
x введите число. Например, если вы укажете
4 , то команда повлияет на четвертый снизу коммит. Если вы не укажете никакое конкретно число, git reset — soft HEAD применится к последнему коммиту.
Когда вы используете команду git reset — soft HEAD , то просто отменяете последний коммит, при этом внесенные изменения останутся в вашем рабочем дереве и в вашем индексе. Поэтому git commit создаст в будущем коммит с теми же самыми изменениями, которые вы “обнулили” перед этим.
Другой метод — это команда git revert HEAD
x ( git reset — hard commit hash ), которая отменяет изменения, указанные последним коммитом в HEAD , и создает новый с возвращенными изменениями:
Этот метод лучше всего работает в случае с общими публичными репозиториями.
Отмена Git Rebase
Допустим, вы выполнили команду git rebase в локальной ветке git и отправили ее в удаленную ветку. Следом вы поняли, что это не отвечает вашим ожиданиям, и захотели отменить сделанное.
Самый простой способ — найти главный коммит вашей ветки, запустив команду:
Следом необходимо установить туда текущую ветку, воспользовавшись git reset .
В данном случае старым коммитом был HEAD5 .
Заключение
Вот и все о том, как вы можете отменить наиболее часто используемые команды в Git. Хоть никакой традиционной команды отмены и нет, другие команды git могут помочь вам откатить то, что вы могли сделать по ошибке.
К моему удивлению на целом хабрахабре нет ни одного поста где бы было понятно написано про 3 вида git reset . Например, во второй по релевантности статье по запросу «git reset» автор пишет что «данное действие может быть двух видов: мягкого(soft reset) и жесткого(hard reset)». Режим --mixed , используемый по умолчанию, почему-то не удостоился упоминания.
Ничего удивительного, что часто видишь непонимание работы этой команды. Под катом коротко и ясно расскажу о всех трёх режимах git reset , после прочтения топика неясностей остаться не должно.
Сделанные изменения в репозитории по умолчанию имеют статус unstaged. Для того чтобы их закоммитить сначала вы должны добавить изменения в индекс, выполнив git add . Когда вы делаете git commit , в репозиторий будет закоммичено только то, что было в индексе.
git reset --soft
Возьмем для примера ветку:
- A - B - C (master)
HEAD указывает на C и индекс совпадает с C.
После выполнения
HEAD будет указывать на B и изменения из коммита C будут в индексе, как будто вы их добавили командой git add . Если вы сейчас выполните git commit вы получите коммит полностью идентичный C.
git reset --mixed (по умолчанию)
Режим --mixed используется по умолчанию, т.е. git reset --mixed = git reset
Вернемся к тем же начальным условиям:
- A - B - C (master)
Выполнив
или
HEAD опять же будет указывать на B, но на этот раз изменения из С не будут в индексе и если вы запустите здесь git commit ничего не произойдет т.к. ничего нет в индексе. У нас есть все изменения из С, но если запустить git status то вы увидите, что все изменения not staged. Чтобы их закоммитить нужно сначала добавить их в индекс командой git add и только после этого git commit .
git reset --hard
Те же самые начальные условия:
- A - B - C (master)
Последний режим --hard также как и --mixed переместит HEAD на В и очистит индекс, но в отличие от --mixed жесткий reset изменит файлы в вашей рабочей директории. Если выполнить
то изменения из С, равно как и незакоммиченные изменения, будут удалены и файлы в репозитории будут совпадать с B. Учитывая то, что этот режим подразумевает потерю изменений, вы всегда должны проверять git status перед тем как выполнить жесткий reset чтобы убедиться что нет незакоммиченных изменений(или они не нужны).
Перевод статьи «Git Reset Explained – How to Save the Day with the Reset Command».
«Помогите! Я закоммитил не в ту ветку!» «Ну вот, опять… Где мой коммит?» Знакомые ситуации, правда?
Я такое слышал неоднократно. Кто-то окликает меня по имени и просит помочь, когда у него что-то пошло не так с git. И такое происходило не только когда я учил студентов, но также и в работе с опытными разработчиками.
Со временем я стал кем-то вроде «того парня, который разбирается в Git».
Мы используем git постоянно, и обычно он помогает нам в работе. Но порой (и куда чаще, чем нам хотелось бы!) что-то идет не так.
Бывает, мы отправляем коммит не в ту ветку. Бывает, теряем часть написанного кода. А можем и добавить в коммит что-то лишнее.
По git есть много онлайн-ресурсов, и часть из них (например, вот эта статья) фокусируется на том, что делать в таких вот нежелательных ситуациях.
Но мне всегда казалось, что в этих ресурсах не хватает объяснений, почему нужно делать так, а не иначе. Когда приводится набор команд, что делает каждая из них? И вообще, как вы пришли к этим командам?
В прошлом посте я рассказывал о внутреннем устройстве Git. И хотя понимать его полезно, читая теория практически всегда недостаточна. Как применить свои знания внутреннего устройства git и использовать их для решения возникающих проблем?
В этом посте я хотел бы построить мост между теорией и практикой и рассказать о команде git reset . Мы разберем, что делает эта команда, что происходит за кулисами, а также применим эти знания в различных сценариях.
Исходные условия — рабочая директория, индекс и репозиторий
Чтобы разобраться во внутренних механизмах git reset , важно понимать процесс записи изменений внутри git. В частности, я имею в виду записи в рабочей директории, индексе и репозитории.
Если вы хорошо ориентируетесь в этой теме, переходите к следующему разделу. Если же вам нужно более глубокое пояснение, почитайте мой предыдущий пост.
Когда мы работаем над кодом своего проекта, мы делаем это в рабочей директории. Ею может быть любая директория в нашей файловой системе, имеющая привязанный к ней репозиторий. В ней хранятся папки и файлы нашего проекта, а также директория под названием .git.
Давайте создадим в рабочей директории какой-нибудь файл и запустим команду git status :
Да, git не записал (не закоммитил) изменения, сделанные в рабочей директории, напрямую в репозиторий.
Вместо этого изменения сначала регистрируются в индексе (или в стейджинге). Оба эти термина означают одно и то же, и оба часто используются в документации git. В этой статье мы тоже будем пользоваться обоими, так как они полностью взаимозаменяемы.
Когда мы применяем git add , мы добавляем файлы (или изменения внутри файлов) в стейджинг. Давайте попробуем использовать эту команду для только что созданного файла:
Как показывает git status , наш файл теперь в стейджинге и готов к коммиту. Да, он еще не является частью никакого коммита. Другими словами, сейчас он находится в рабочей директории, а также в индексе, но не в репозитории.
Если мы теперь выполним git commit , мы создадим коммит на основе состояния индекса. Таким образом новый коммит (в примере — commit 3) будет включать файл, который мы чуть ранее добавили в стейджинг.
Рабочая директория находится в точно таком же состоянии, как индекс и репозиторий.
При выполнении git commit текущая ветка master начинает указывать на только что созданный объект commit.
Внутренняя работа git reset
Мне нравится представлять git reset как команду, которая поворачивает вспять описанный выше процесс (внесение изменений в рабочей директории, добавление их в индекс, а затем сохранение в репозиторий).
У git reset есть три режима: --soft , --mixed и --hard . Я рассматриваю их как три стадии:
- Стадия 1. Обновление HEAD — git reset --soft
- Стадия 2. Обновление индекса — git reset --mixed
- Стадия 3. Обновление рабочей директории — git reset --hard
Прежде всего, git reset меняет то, на что указывает HEAD. Если мы выполним git reset --hard HEAD
1 , HEAD будет указывать не на master, а на HEAD
1. Если использовать флаг --soft , git reset на этом и остановится.
Если вернуться к нашему примеру, HEAD будет указывать на commit 2, и таким образом new_file.txt не будет частью дерева текущего коммита. Но он будет частью индекса и рабочей директории.
Если посмотреть git status , мы увидим, что этот файл определенно в стейджинге, но не закоммичен.
Иными словами, мы вернули процесс на стадию, где мы уже применили git add , но еще не применяли git commit .
Если мы используем git reset --mixed HEAD
1 , git не остановится на обновлении того, на что указывает HEAD. Помимо этого обновится еще и индекс (до состояния уже обновленного HEAD).
В нашем примере это значит, что индекс будет в том же виде, что и commit 2:
Таким образом мы вернули процесс на стадию до выполнения команды git add . Новосозданный файл является частью рабочей директории, но не индекса и не репозитория.
Если использовать git reset -- hard HEAD
1 , то после перевода указателя HEAD (на что бы он ни указывал раньше) на HEAD
1, а также обновления индекса до (уже обновленного) HEAD, git пойдет еще дальше и обновит рабочую директорию до состояния индекса.
Применительно к нашему примеру это означает, что рабочая директория будет приведена к состоянию индекса, который уже приведен в состояние commit 2:
Собственно, мы вернули весь процесс на этап до создания файла my_file.txt.
Применяем наши знания в реальных сценариях
Теперь, когда мы разобрались с тем, как работает git reset , давайте применим эти знания, чтобы спасти какую-нибудь ситуацию!
1. Упс! Я закоммитил что-то по ошибке
Рассмотрим следующий сценарий. Мы создали файл со строкой «This is very importnt», отправили его в стейджинг, а после — в коммит.
А затем — ой! — обнаружили, что в предложении у нас опечатка.
1 . Теперь моно отредактировать содержимое файла и сделать коммит еще раз.
Совет. В данном конкретном случае мы также можем использовать git commit --amend , как описано здесь.
2. Упс! Я сделал коммит не в ту ветку, а эти изменения мне нужны в новой ветке
Со всеми нами такое случалось. Сделал что-то, закоммитил…
О нет, мы сделали коммит в ветку master, а надо было создать новую и затем сделать пул-реквест.
Я считаю, что здесь будет полезно визуализировать наше положение и то положение, в котором мы хотели бы оказаться.
Собственно, от желаемого состояния нас отделяют три изменения.
- Ветка new должна указывать на наш недавно добавленный коммит.
- Ветка master должна указывать на предыдущий коммит.
- HEAD должен указывать на new.
Мы можем достичь желаемого положения в три шага:
Во-первых, нужно сделать так, чтобы ветка new указывала на недавно добавленный коммит. Достичь этого можно при помощи команды git branch new . Таким образом мы достигаем следующего состояния:
Во-вторых, нужно сделать так, чтобы master указывала на предыдущий коммит (иными словами, на HEAD
1). Достичь этого можно при помощи команды git reset --hard HEAD
1 . Таким образом мы достигаем следующего состояния:
Наконец, мы хотели бы оказаться в ветке new, т. е. сделать так, чтобы HEAD указывал на new . Это легко достижимо путем выполнения команды git checkout new .
- git branch new
- git reset --hard HEAD
3. Упс! Я отправил коммит не в ту ветку, а он мне нужен в другой (уже существующей) ветке
В этом случае мы проходим те же шаги, что и в предыдущем сценарии. Мы проделали какую-то работу и закоммитили изменения…
Давайте снова изобразим текущее и желаемое положение:
У нас опять же есть три отличия.
Нам нужно, чтобы самый последний коммит оказался в ветке existing. Поскольку в настоящее время на этот коммит указывает master , мы можем попросить git взять последний коммит из ветки master и применить его к ветке existing :
- git checkout existing — переключение на ветку existing ,
- git cherry-pick master — применение последнего коммита в ветке master к текущей ветке ( existing ).
Теперь наше положение следующее:
Все, что нам нужно, это сделать так, чтобы master указывала на предыдущий коммит, а не на самый последний. Для этого:
- git checkout master — смена активной ветки на master ,
- git reset --hard HEAD
Таким образом мы достигли желаемого положения:
Итоги
В этой статье мы изучили, как работает git reset , а также разобрали три разных режима этой команды: --soft , --mixed и --hard .
Также мы применили свои новые знания для решения жизненных задач.
Понимание работы git позволяет уверенно действовать в любых ситуациях, а также наслаждаться красотой этого инструмента.
Читайте также: