Как восстановить спрятанные незафиксированные изменения

696

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

Кроме того, с тех пор я внес некоторые изменения в файлы с сохраненным кодом.

Есть ли шанс, что я смогу получить спрятанные изменения в новую ветку, если это возможно?

Асвати П Кришнан
источник
7
Вы пытались использовать 'Stash Pop'?
Роберт
На самом деле я новичок в Git. Поскольку я не полностью осознаю все команды, я больше ничего не пробовал! Я не хочу терять эти изменения.
Асвати П Кришнан
33
Если вы не хотите потерять сохраненные изменения, попробуйте использовать «git stash apply». Это применит сохраненные изменения к вашей текущей ветке, сохраняя при этом хранилище. Если все в порядке, после применения тайника вы можете сбросить тайник, используя «git stash drop»
Роберт
2
@robert Спасибо за простой ответ по сравнению с ужасно сложным (для новичка) принятым ответом.
Сахил Годхейн

Ответы:

1189

Простой ответ на простой вопрос git stash apply

Просто проверьте ветку, в которой вы хотите внести изменения, а затем git stash apply. Затем используйте, git diffчтобы увидеть результат.

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

Я всегда предлагаю использовать, git stash applyа не git stash pop. Разница в том, что вы applyоставляете тайник для повторной попытки apply, или для просмотра, и т. Д. Если popудастся извлечь тайник, он сразу же получит dropего, и если вы вдруг поймете, что хотели где-то извлечь его иначе (в другой ветке), или с --index, или с некоторыми другими , это не так просто. Если вы apply, вы можете выбрать, когда drop.

Это все довольно незначительно, так или иначе, и для новичка, чтобы быть мерзавцем, это должно быть примерно таким же. (И вы можете пропустить все остальное!)


Что делать, если вы делаете более продвинутые или более сложные вещи?

Существует как минимум три или четыре разных «способа использования git stash». Выше для «способ 1», «легкий путь»:

  1. Вы начали с чистой ветки, работали над некоторыми изменениями, а затем поняли, что делаете их не в той ветке. Вы просто хотите принять изменения, которые у вас есть, и «переместить» их в другую ветку.

    Это простой случай, описанный выше. Беги git stash save(или просто так git stashже). Проверьте другую ветку и используйте git stash apply. Это позволяет git слиться с вашими более ранними изменениями, используя довольно мощный механизм слияния git. Внимательно осмотрите результатыgit diff), чтобы увидеть, нравятся ли они вам, и если вам это нравится, используйте git stash dropдля сброса тайника. Вы сделали!

  2. Вы начали некоторые изменения и спрятали их. Затем вы переключились на другую ветку и начали больше изменений, забыв, что у вас есть спрятанные.

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

    Вы можете на самом деле git stash saveснова, как git stashделает "стек" изменений. Если вы делаете это, у вас есть два тайника, один из которых просто называется stash- но вы также можете написать stash@{0}- и один пишется stash@{1}. Используйте git stash list(в любое время), чтобы увидеть их все. Новейший всегда с самым низким номером. Когда вы git stash drop, он сбрасывает самое новое, а тот, который был, stash@{1}перемещается на вершину стека. Если у вас было еще больше, то, что было, stash@{2}становится stash@{1}и так далее.

    Можно applyи то dropконкретный заначить тоже: git stash apply stash@{2}и тд. Отбрасывание определенного тайника перенумеровывает только номера с большими номерами. Опять же, номер без номера тоже stash@{0}.

    Если вы накапливаете много тайников, это может стать довольно грязным (тайник, который я хотел stash@{7}или был stash@{4}? Подожди, я просто толкнул другой, теперь их 8 и 5?). Я лично предпочитаю перенести эти изменения в новую ветку, потому что у ветвей есть имена, и это cleanup-attempt-in-Decemberзначит для меня гораздо больше, чем stash@{12}. (Команда git stashпринимает необязательное сообщение сохранения, и они могут помочь, но каким-то образом все мои тайники просто названы WIP on branch.)

  3. (Дополнительно) Вы использовали git stash save -pили тщательно git addотредактировали и / или git rmотредактировали определенные биты своего кода перед запуском git stash save. У вас была одна версия в области сохраненного индекса / промежуточной области, а другая (другая) версия в рабочем дереве. Вы хотите сохранить все это. Так что теперь вы используете git stash apply --index, и это иногда не удается с:

    Conflicts in index.  Try without --index.
    
  4. Вы используете git stash save --keep-indexдля того, чтобы проверить «что будет совершено». Этот выходит за рамки этого ответа; см. этот другой ответ StackOverflow вместо этого.

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

git status               # see if there's anything you need to commit
                         # uh oh, there is - let's put it on a new temp branch
git checkout -b temp     # create new temp branch to save stuff
git add ...              # add (and/or remove) stuff as needed
git commit               # save first set of changes

Теперь вы находитесь на «чистой» отправной точке. Или, может быть, это выглядит так:

git status               # see if there's anything you need to commit
                         # status says "nothing to commit"
git checkout -b temp     # optional: create new branch for "apply"
git stash apply          # apply stashed changes; see below about --index

Главное, что нужно помнить, это то, что «stash» - это коммит, это просто «смешной / странный» коммит, который не «на ветке». В applyоперации смотрит на то , что коммит изменилось, и пытается повторить его там , где вы сейчас находитесь . Тайник все еще будет там ( applyхранит его), так что вы можете посмотреть на него больше или решить, что это было не то место, applyи попробовать еще раз, или что-то еще.


Каждый раз, когда у вас есть тайник, вы можете использовать git stash show -pупрощенную версию того, что находится в тайнике. (Эта упрощенная версия рассматривает только изменения «конечного рабочего дерева», а не сохраненные изменения индекса, которые --indexвосстанавливаются отдельно.) Команда git stash applyбез --indexэтого сейчас просто пытается внести те же самые изменения в ваш рабочий каталог.

Это верно, даже если у вас уже есть некоторые изменения. Команда applyрада применить тайник к измененному рабочему каталогу (или, по крайней мере, попытаться применить его). Вы можете, например, сделать это:

git stash apply stash      # apply top of stash stack
git stash apply stash@{1}  # and mix in next stash stack entry too

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

Запуск git merge с нетривиальными незафиксированными изменениями не рекомендуется: хотя это возможно, он может оставить вас в состоянии, в котором трудно выйти из ситуации в случае конфликта.

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


Как насчет самого худшего возможного случая?

Допустим, вы делаете «Много расширенного Git Stuff», и вы создали тайник, и хотите git stash apply --index, но с помощью этого хранилища больше нельзя применить --index, потому что ветка слишком сильно разошлась со времени, когда вы ее сохранили.

Это для чего git stash branch.

Если ты:

  1. проверьте точный коммит, на котором вы были, когда делали оригинал stash, затем
  2. создать новую ветку и, наконец,
  3. git stash apply --index

попытка заново создать изменения , безусловно , будет работать. Это то, что делает. (И затем он сбрасывает тайник, поскольку он был успешно применен.)git stash branch newbranch


Несколько заключительных слов о том --index(что, черт возьми, это?)

То, что --indexделает, легко объяснить, но немного сложнее внутри:

  • Когда у вас есть изменения, вы должны git add(или «ставить») их перед использованием commit.
  • Таким образом, когда вы бежали git stash, вы могли редактировать оба файла fooи zorg, но только поставить один из них.
  • Так что, когда вы просите , чтобы получить копить обратно, было бы хорошо , если это git addВЛЯЕТСЯ addред вещи и вовсе не git add в не-добавлены вещи. То есть, если вы addредактировали, fooно не zorgвернулись до того, как сделали это stash, было бы неплохо иметь точно такую ​​же настройку. То, что было поставлено, должно быть снова поставлено; то, что было изменено, но не организовано, должно быть снова изменено, но не организовано.

--indexФлаг applyпытается установить вещи таким образом. Если ваше дерево работы чистое, это обычно просто работает. Если add, однако, в вашем рабочем дереве уже есть материал ed, вы можете увидеть, что здесь могут быть некоторые проблемы. Если вы пропустите --index, applyоперация не будет пытаться сохранить всю ступенчатую / не постановочную установку. Вместо этого он просто вызывает механизм слияния git, используя коммит рабочего дерева в «шкатулке» . Если вы не заботитесь о сохранении поэтапного / неустановленного сценария, упускать --indexего намного проще git stash apply.

Торек
источник
2
Я не понимаю ваш комментарий. Ты имеешь в виду: ты бежал git stash pop? Или вы имеете в виду: вы редактировали некоторые файлы, но еще не запускались git stash? Или ты имеешь в виду что-то совсем другое?
Торек
1
Да. Обратите внимание, что в моем (длинном) редактировании я рекомендую зафиксировать то, что у вас сейчас есть, перед тем, как apply-не хранить тайник. Вам не нужно этого делать, но вам будет намного проще на это смотреть. Вы можете использовать, rebase -iчтобы объединить несколько коммитов, или выбрать определенные изменения, или что-то еще, позже.
Торек
1
Да: git stash apply --index(помните две черточки). Если вы пропустите --index, ничего страшного; единственное, --indexчто нужно - это сохранить постановку / постановку. (Скорее всего, у вас изначально не было никаких специальных настроек.) Затем и git statusт. Д., И добавьте / подтвердите по желанию и т. Д. Когда (и только когда) вы все закончили с тайником, используйте git stash dropдля его отмены.
Торек
1
Пока вы храните (не делаете dropили не храните pop) тайник, у вас всегда будет оригинальный исходный код в безопасности при коммите, потому что тайник - это коммит! Если вы хотите получить его обратно точно, но на ветке, используйте git stash branch(см. Этот раздел выше или книгу Pro Git в ответе Шунии ). Вы можете затем git checkoutэту ветку, или git cherry-pickзафиксировать эту ветку и т. Д.
torek
2
@ChuckWolber: Соглашения об именах в Git оставляют желать лучшего (сколько разных значений мы можем присвоить словам «удаленный», «отслеживание» и «ветвь» ?!). Стоит отметить, что вы можете применить тайник к чему-то, что не связано с оригинальным тайником.
Торек
57
git stash pop

вернет все на место

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

git checkout -b newbranch
git stash pop
Стефано Фаласка
источник
Спасибо за помощь. Могу ли я получить эти изменения в новую ветку? Прямо сейчас я нахожусь на развивающейся ветви
Aswathy P Krishnan
3
git stash branch newbranch, создаст новую ветку с сохраненными изменениями.
Роберт
3
@robert: git stash branch newbranchдействительно сделает это; но имейте в виду, что он создает новую ветвь с родительским установленным значением для коммита, который был HEADна момент stashвыполнения. Другими словами, это когда вы возвращаетесь после долгой хакерской сессии или чего-то еще, смотрите на беспорядок и решаете: «Я должен был положить это на ветку, а не копить» :-)
torek
Я отредактировал свой вопрос. Я хотел бы получить эти изменения в новую ветку, если это возможно.
Асвати П Кришнан,
1
Иногда вы просто хотите получить ответ TLDR :)
sachinruk
24

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

  1. git stash pop - Восстановить обратно в сохраненное состояние, но он удаляет тайник из временного хранилища.
  2. git stash apply - Восстановить обратно в сохраненное состояние и оставить список тайников для возможного последующего использования.

Вы можете прочитать более подробно о git stashes в этой статье.

Неша Зорич
источник
19

Чтобы проверить ваш тайник: -

git stash list

применить определенный тайник нет из списка тайников: -

git stash применить stash @ {2}

или для применения только первого тайника: -

Git Stash поп

Примечание: git stash pop удалит тайник из вашего списка тайников, тогда как git stash будет применяться. Так что используйте их соответственно.

Шиванш Раджолия - HeLleR
источник
2

На Mac это работает для меня:

git stash list (см. все ваши тайники)

git stash list

git stash apply (только номер, который вы хотите из вашего списка тайников)

нравится:

git stash apply 1
Zack
источник
0

Вы можете спрятать незафиксированные изменения, используя "git stash", затем оформить заказ в новую ветку, используя "git checkout -b", затем применить спрятанные коммиты "git stash apply"

S.Sandeeptha
источник