Перейти к содержимому

Как отменить git stash

  • автор:

Как это отменить?! Git-команды для исправления своих ошибок

Если вы что-то сделали в Git’е, а потом очень сильно пожалели, не отчаивайтесь: возможно, всё можно исправить. Рассказываем, как это сделать.

Если вы ошиблись в Git’е, разобраться, что происходит и как это исправить, — непростая задача. Документация Git — это кроличья нора, из которой вы вылезете только зная конкретное название команды, которая решит вашу проблему.

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

Вот блин, я сделал что-то не то… У Git ведь есть машина времени?!

git reflog # Тут вы увидите всё, что вы делали # в Git во всех ветках. # У каждого элемента есть индекс HEAD@. # Найдите тот, после которого всё сломалось. git reset HEAD@ # Машина времени к вашим услугам. 

Так вы можете восстановить то, что случайно удалили, и откатить слияние, после которого всё сломалось. reflog используется очень часто — давайте поблагодарим того, кто предложил добавить его в Git.

Введение в Git: от установки до основных команд

Я только что сделал коммит и заметил, что нужно кое-что поправить!

# Внесите изменения git add . # или добавьте файлы по отдельности. git commit --amend --no-edit # Теперь последний коммит содержит ваши изменения. # ВНИМАНИЕ! Никогда не изменяйте опубликованные коммиты. 

Обычно эта команда нужна если вы что-то закоммитили, а потом заметили какую-то мелочь, например отсутствующий пробел после знака = . Конечно вы можете внести изменения новым коммитом, а потом объединить коммиты с помощью rebase -i , но это гораздо дольше.

Внимание Никогда не изменяйте коммиты в публичной ветке. Используйте эту команду только для коммитов в локальной ветке, иначе вам конец.

Мне нужно изменить сообщение последнего коммита!

git commit --amend # Открывает редактор сообщений коммита. 

Тупые требования к оформлению сообщений…

Я случайно закоммитил что-то в мастер, хотя должен был в новую ветку!

# Эта команда создаст новую ветку из текущего состояния мастера. git branch some-new-branch-name # А эта — удалит последний коммит из мастер-ветки. git reset HEAD~ --hard git checkout some-new-branch-name # Теперь ваш коммит полностью независим :) 

Команды не сработают, если вы уже закоммитили в публичную ветку. В таком случае может помочь git reset HEAD@ вместо HEAD~ .

Ну отлично. Я закоммитил не в ту ветку!

# Отменяет последний коммит, но оставляет изменения доступными. git reset HEAD~ --soft git stash # Переключаемся на нужную ветку. git checkout name-of-the-correct-branch git stash pop # Добавьте конкретные файл или не парьтесь и закиньте все сразу. git add . git commit -m «Тут будет ваше сообщение» # Теперь ваши изменения в нужной ветке. 

Многие в такой ситуации предлагают использовать cherry-pick , так что можете выбрать, что вам больше по душе.

git checkout name-of-the-correct-branch # Берём последний коммит из мастера. git cherry-pick master # Удаляем его из мастера. git checkout master git reset HEAD~ --hard 

Самые типичные ошибки и вопросы, связанные с Git, и удобные способы их решения

Я пытаюсь запустить diff, но ничего не происходит

Если вы знаете, что изменения были внесены, но diff пуст, то возможно вы индексировали изменения (через add ). Поэтому вам нужно использовать специальный флаг.

git diff --staged 

Конечно, «это не баг, а фича», но с первого взгляда это чертовски неоднозначно.

Мне нужно каким-то образом отменить коммит, который был сделан 5 коммитов назад

# Найдите коммит, который нужно отменить. git log # Можно использовать стрелочки, чтобы прокручивать список вверх и вниз. # Сохраните хэш нужного коммита. git revert [тот хэш] # Git создаст новый коммит, отменяющий выбранный. # Отредактируйте сообщение коммита или просто сохраните его. 

Вам не обязательно откатываться назад и копипастить старые файлы, замещая ими новые. Если вы закоммитили баг, то коммит можно отменить с помощью revert .

Помимо этого, откатить можно не целый коммит, а отдельный файл. Но следуя канону Git’а, это будут уже совсем другие команды…

Мне нужно отменить изменения в файле

# Найдите хэш коммита, до которого нужно откатиться. git log # Сохраните хэш нужного коммита. git checkout [тот хэш] --path/to/file # Теперь в индексе окажется старая версия файла. git commit -m «О май гадбл, вы даже не использовали копипаст» 

Именно поэтому checkout — лучший инструмент для отката изменений в файлах.

Давай по новой, Миша, всё х**ня

cd .. sudo rm -r fucking-git-repo-dir git clone https://some.github.url/fucking-git-repo-dir.git cd fucking-git-repo-dir 

Если вам нужно полностью откатиться до исходной версии (т. е. отменить все изменения), то можете попробовать сделать так.

Будьте осторожны, эти команды разрушительны и необратимы.

# Получить последнее состояние origin. git fetch origin git checkout master git reset --hard origin/master # Удалить неиндексированные файлы и папки. git clean -d --force # Повторить checkout/reset/clean для каждой испорченной ветки. 

Эти команды Git нужны для экстренных ситуаций, но пригодиться могут не только они. Про другие команды с пояснениями писали тут:

Как отменить откат изменений (восстановить потерянный коммит)?

Вопрос: Есть ли способ в git отменить откат, т.е восстановить состояние, не закоммиченное в git`е ? Около месяца назад я создал коммит и сегодня я создал коммит( как я думал ), но коммит, как оказалось позже, не создался( моя вина ). Затем, спустя час, я решил произвести откат к последнему коммиту, но так как сегодня во время его создания произошла ошибка, я откатился к коммиту месячной давности.

Отслеживать
34k 25 25 золотых знаков 130 130 серебряных знаков 222 222 бронзовых знака
задан 28 июн 2013 в 17:23
13.6k 13 13 золотых знаков 62 62 серебряных знака 122 122 бронзовых знака

Если данные были закоммичены, то к ним можно восстановиться. Если данные не были закоммичены, то скорее всего все утеряно. Да, коммитить раз в месяц — это странно. git приветствует частые коммиты. Если перестарались и сделали много мелких коммитов — их можно объединить.

28 июн 2013 в 17:43

Ясно, что ж, спасибо. Коммит был сделан спустя месяц потому, что месяц к проекту никто не прикасался, а спустя месяц работа возобновилась. Выходит, GIT может превращаться из удобного инструмента в опасный.

28 июн 2013 в 17:49

Если данные были закоммичены, то пусть хоть десять откатов назад сделаете, восстановиться можно. btw, изучите возможности «кармана» — git stash спрятать в карман, git stash pop — достать. Карман стековый (можно много запихать). Очень полезный инструмент, если планируете использовать «страшные неизвестные операции».

28 июн 2013 в 18:01

если файлы добавлялись в индекс (staging area), то для них будут созданы blob объекты в репозитории, и соответственно, можно вытащить содержимое в незаисимости был сделан коммит или нет

28 июн 2013 в 20:48

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Все что попадает в репозиторий не удаляется сразу, т.е. если даже ты удалил ветку, изменил коммит и т.д. есть возможность вернуться к предыдущей версии. Если же изменения были только в рабочей копии, а потом они «потерялись», то тут уж ничем не поможешь :(.

Ты можешь посмотреть в логе git reflog историю изменения HEAD ,еще можно перечислить все недостижимые объекты git fsck —unreachable . Может это поможет.

Если ты добавлял файлы в индекс, но не закомитил их то по выводу git fsck —unreachable можно будет найти эти файлы. Содержимое файлов хранится в blob объектах. В объектах типа tree хранятся коллекции blob объектов. Увы не знаю создается ли tree объект при добавлении файлов в индекс, но если создается то все что нужно это найти недостижимый tree объект с нужными файлами.

Для отображения содержимого объекта: git cat-file -p

Как отменить git stash apply?

2ord

В Git команды stash, apply применяются одна независимо от другой. Поясни в каком порядке применялись какие команды.

Решения вопроса 0
Ответы на вопрос 1

dlnsk

ПК Партнер 01.01 -> ПК Поиск -> IBM PC

Хм. я бы попробовал так:
Назовем последний имеющийся коммит (0), а текущую ветку (а).
Поскольку сделана stash apply, то в стеше этот элемент сохранился (если pop, то нужно поколдовать с git reflog).
1. Сделаем коммит (1а).
2. Вернемся к коммиту 0 и создадим ветку «б»
3. Выполним git stash apply в ветку «б»
4. Сделаем коммит (1б)
5. Сделаем git revert предыдущего коммита (2б)
6. Перейдем в ветку «а» и сделаем git cherry-pick 2б (получим коммит 2а)
7. Если все нормально, то объединяем коммиты 1а и 2а (git rebase -i)
Все.
На словах довольно просто, но в реальности это может усложниться конфликтами, но они решаемы.

Руководство по git stash

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

Эта инструкция — часть курса «Введение в Git».

Смотреть весь курс

Введение

В процессе написания кода может возникнуть ситуация, когда нужно срочно переключиться на другую ветку (использовать git checkout) — или, например, внести правки, которые относятся к другой задаче. Однако новые изменения еще не готовы к тому, чтобы их коммитить и добавлять в репозиторий, — при этом терять их нельзя. В таком случае, как и во многих других, полезной окажется команда git stash.

Откладывание кода

Git stash

git stash

Git stash перемещает текущие изменения (так называемые local changes) в локальную директорию, которая выполняет роль специального хранилища, то есть скрывает эти изменения, сохраняя их отдельно, с опцией вернуть позже, когда это понадобится. Таким образом, файлы рабочей копии возвращаются к своему исходному состоянию. Внесенные изменения помещаются в стек, после чего их можно легко оттуда извлечь. Важно отметить, что в рабочей копии исчезнут все измененные файлы, — независимо от того, добавлены они в индекс или нет.

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

Git stash save

Команда git stash save исполняет ту же функцию, но имеет другие опции.

Git stash save

Когда необходимо добавить комментарий, мы прописываем его вместе с основной командой:

git stash save ""

Важно отметить, что git stash не спрячет изменения, не добавленные в репозиторий. Если необходимо сохранить и их, нужно использовать ту же команду с флагом:

git stash save --include-untracked
git stash save -u

Git stash push

Сейчас команда git stash save считается неактуальной, ее более полезная замена — git stash push. Вызвано это прежде всего тем, что, выполняя git stash push, можно сохранять определенные спецификации пути. Это, к сожалению, не поддерживается git stash save. Git stash save все еще работает, но в будущем следует ожидать постепенного перехода на git stash push из-за доступности нового функционала.

Применение отложенных изменений

Теперь мы знаем, как «спрятать» ненужные в текущий момент изменения, но не знаем, как их извлечь и вернуть в рабочую версию проекта (или, еще можно сказать, сделать «git unstash»). Для решения такой проблемы понадобится git stash pop:

git stash pop

После выполнения в хранилище очищаются изменения и возвращаются к рабочей копии. Если же необходимо, чтобы изменения остались (то есть не удалились из хранилища), но при этом вернулись в проект, мы применим git stash apply:

git stash apply

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

git branch --delete

Необычное откладывание

Еще одну вариацию использования git stash составляет флаг —keep-index:

git stash --keep-index

Git не просто спрячет изменения, уже добавленные в индекс, но и оставит эти «прятанья» в индексе.

Откладывание неотслеживаемых или игнорируемых файлов

При работе с git stash нельзя забывать, что простое выполнение этой команды не дает скрывать изменения в некоторых типах файлов, то есть не убирает в хранилище появившиеся правки кода. К таким типам относятся неотслеживаемые и игнорируемые.

Все «прятанья», создаваемые git stash, делятся на две категории: индексированные и неиндексированные. Индексированными называются исправления, которые уже были добавлены в раздел проиндексированных файлов, а неиндексированными — исправления, которые отслеживаются сейчас.

Проиндексированными называются файлы, о чьих преобразованиях уже знает Git, но само изменение еще не записано в репозиторий.

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

При необходимости спрятать неотслеживаемые файлы поможет уже известный параметр -u (или же -include-untracked):

git stash -u

Перенос правок для игнорируемых файлов осуществляется с помощью флага -all:

git stash -all
git stash -a

Управление несколькими наборами отложенных изменений

При повторном использовании git stash мы можем понять, что фактически мы создаем коммит, но сохраняем его по отдельности. Используя следующее выражение, мы можем посмотреть на список всех спрятанных изменений:

git stash list

Полученный список будет отсортирован по времени, когда были отложены изменения: внизу списка будут самые старые изменения. Также каждое изменение имеет свой идентификатор с номером, например:

stash@: WIP on master: 08f13aa add processing file stash@: WIP on master: c33b610 refactor code 

Описание «прятаний» по умолчанию начинается с WIP (что указывает на незавершенную работу) перед названием ветки (в частности коммита), где их отложили.

После выполнения git stash pop будет возвращен последний из наборов откладываний (с индексом 0). Если нужно выбрать конкретный набор из всех ранее отложенных участков, то в фигурных скобках нужно явно прописать его идентификатор. Например:

git stash pop stash@

Просмотр различий между наборами отложенных изменений

Команда git stash show выводит информацию по последнему сделанному изменению:

git stash show

Если нужно посмотреть информацию о другом изменении, то необходимо явно указать индекс:

git stash show stash@

Очень полезной функцией может стать сравнение полученных наборов друг с другом. Для такой ситуации понадобится параметр —patch:

git stash show --patch

Или что будет равносильно:

git stash show -p

Частичное откладывание изменений

Иногда бывает удобно разделить существующие в коде незакоммиченные изменения на несколько откладываний. Тогда в разных откладываниях могут храниться изменения в разных файлах или даже в одном. Тогда необходимо написать флаг -p (или —patch):

git stash -p

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

  • ? — узнать все возможные варианты для работы (ниже будут перечислены самые распространенные);
  • y — отложить этот участок;
  • / — использовать для поиска регулярное выражение;
  • n — не откладывать этот участок кода;
  • q — отложить все выбранные участки и выйти;
  • s — разделить текущее изменение на несколько откладываний.

Прервать работу откладывания поможет комбинация клавиш CTRL+C.

Создание ветки из отложенных изменений

При работе с разными ветками и откладыванием изменений (или другими операциями) могут возникнуть конфликты. Одной из возможностью избежать этого и ничего не сломать будет создание новой ветки и применение изменений в ней:

git stash branch

Теперь будет создана новая ветка, к которой уже применятся сделанные изменения. Однако последние правки будут удалены из списка всех спрятанных изменений. Как и в предыдущих случаях, если нужно работать не с последним набором, то можно указать индекс.

Удаление отложенных изменений

Теперь нам нужно научиться удалять отложенные изменения:

git stash drop

Так мы удалим последний набор. Аналогично другим командам для удаления определенного набора указываем индекс:

git stash drop stash@

Иногда нужно очищать хранилище от всех наборов, то есть отменять все созданные изменения. В таких случаях мы пишем:

git stash clear

Разрешение конфликтов

При работе с возвращением в исходный код спрятанных изменений могут возникнуть конфликты. Если это произошло, то после выполнения git stash pop появится сообщение о возникновении конфликта.

Чтобы посмотреть файлы, в которых возникли конфликты, нужно воспользоваться git status. Они будут находиться в секции Unmerged paths. Также все новые изменения отслеживаемых и проиндексированных файлов будут находиться в разделе Changes to be committed.

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

Можно сделать вывод, что конфликты при работе git stash pop допустимо рассматривать в качестве незафиксированных изменений.

Принцип работы команды git stash

Разберемся, как устроена работа команды и получим более подробное git stash-описание.

Мы уже знаем, что наборы откладываний на самом деле являются коммитами (из этого следует, что команда git log корректно отработает, выводя изменения). Ссылка в .git/refs/stash ведет на последнюю группу откладываний. Чтобы найти более ранние наборы, существует журнал ссылок, который так и называется — stash. Поэтому если нужно просмотреть «прятанья», мы пишем stash@, то есть обращаемся к записи с номером n.

В зависимости от откладываемых элементов git stash создает от двух до трех коммитов. Конкретно рассмотрим, какие это будут коммиты.

  • В коммите stash@ будут содержаться файлы в исходном коде на момент запуска команды.
  • Первым предком stash@ будет являться уже существующий коммит в той ветке, куда ведет HEAD.
  • Второй предок stash@ — новый коммит, который является индексом.
  • Третий коммит будет создан только в том случае, если в проекте содержатся неотслеживаемые Git-файлы или были указаны параметры -u или -a. Это будет коммит с файлами, которые содержатся в исходном коде и не видны Git’у.

Теперь поподробнее разберем, как git stash зашифровывает рабочий каталог и работает с проиндексированными файлами.

  • Выше мы разбирали, что каталог может содержать исправления в разных типах файлов. Такие файлы могут быть только частично отмечены в репозитории.
  • Git stash кодирует преобразования в отслеживаемых участках под видом ориентированного ациклического графа (это можно проверить, если нарисовать дерево, описанное выше). Целью одного коммита будет хранение неиндексированных, а второго — уже индексированных изменений, которые были отмечены как проиндексированные файлы.
  • Помним, что флаг -u зашифровывает все правки неотслеживаемых файлов в виде другого коммита, в то время как параметр -a, наоборот, включает изменения в игнорируемых файлах в тот же (не создавая при этом дополнительный коммит).

Осталось разобраться, что происходит, когда мы реализуем git stash pop. Спрятанные части кода из всех перечисленных выше пунктов возвращаются сразу и в рабочую копию, и, что важно, также к разделу проиндексированных файлов Git. После этого коммит, который мы извлекли, будет удален из stash. Остальные ссылки в журнале просто сдвигаются (чтобы обеспечить далее корректную работу). Коммиты, которые мы извлекли, не очищаются сразу, но отмечаются как мусор и впоследствии удаляются.

Заключение

Команда git stash открывает новые возможности перед разработчиками в написании кода. С помощью откладываемых изменений можно удобно и оперативно работать в нескольких ветках, не рискуя потерять важные участки кода. Если использовать специальные команды и параметры к ним, можно эффективно управлять сделанными отложенными изменениями. Все рассматриваемые операции применимы также и к таким типам файлов, как неотслеживаемые и игнорируемые, что позволяет комфортно работать со всем разрабатываемым проектом в целом.

Конечно, даже такой обширный функционал не может полностью обезопасить от конфликтов или ошибок. Но если научиться умело пользоваться git stash, можно избежать некоторых сложностей в процессе разработки мобильных приложений, веб-приложений и других продуктов.

Что такое GitLab, как и для чего он используется

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *