Git stash: «Не удается применить к грязному рабочему дереву, пожалуйста, внесите изменения»


133

Я пытаюсь применить изменения, которые я спрятал ранее, git stash popи получаю сообщение:

Cannot apply to a dirty working tree, please stage your changes

Любое предложение о том, как бороться с этим?

Ответы:


196

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

$ git stash show -p | git apply -3 && git stash drop

В основном это

  1. создает патч
  2. трубы, которые применяются к команде
  3. если есть какие-либо конфликты, их необходимо разрешить с помощью трехстороннего слияния
  4. если применить (или объединить) успешно, он удаляет только что примененный тайник ...

Интересно, почему нет -f(принудительного) варианта, для git stash popкоторого должен точно вести себя, как однострочник выше.

Тем временем вы можете добавить этот однострочный псевдоним:

$ git config --global --replace-all alias.unstash \
   '!git stash show -p | git apply -3 && git stash drop'
$ git unstash

Спасибо @SamHasler за указание -3параметра, который позволяет разрешать конфликты напрямую с помощью трехстороннего слияния.


Отличается git stash show -p | git applyчем git stash apply?
Фактор Мистик

1
Джо Фактор, git stash applyне будет применять спрятанные изменения, если у вас есть грязная рабочая копия. Таким образом, вы можете увидеть, git stash show -p | git applyкак применяется какой-то принудительный тайник.
Muhqu

1
не помогает, но помогает: git сбрасывает HEAD и снимает изменения после этого.
Роджер Инопланетянин

4
Я получаю сообщение "ошибка: исправление не удалось ... исправление не применяется" для одного из файлов. Я хотел бы, чтобы это дало конфликт слияния.
Александр Дубинский

1
Это решение не работает для меня, оно не удалось error: <file> does not match indexдля каждого измененного файла. Однако другое решение сработало.
Сильвенон

57

Я делаю это таким образом:

git add -A
git stash apply

а затем (опционально):

git reset

2
+1! Это проще, чем в других решениях, связанных с созданием исправлений или внесением изменений, и обеспечивает безопасную изоляцию локальных изменений от внесенных изменений в хранилище до тех пор, пока вы не убедитесь, что изменения были объединены правильно.
peterflynn

Я получаю сообщение об ошибке "... уже существует, нет проверки ... Не удалось восстановить неотслеживаемые файлы из тайника"
Александр Дубинский,

2
Я использовал git add -u, что похоже на то, -Aчто он не добавляет неотслеживаемых файлов.
Брэд Купит

9

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

Например, скажем, вы хотите применить stash @ {0} к грязному дереву:

  1. Экспорт stash @ {0} в виде патча:

    git stash show -p stash @ {0}> Stash0.patch

  2. Вручную применить изменения:

    git apply Stash0.patch

Если второй шаг не удался, вам нужно отредактировать файл Stash0.patch, чтобы исправить все ошибки, а затем снова попробовать git apply.


Это практично и выполнимо для случая, когда я произвел рефакторинг для dir (удалил его и создал символическую ссылку с его именем). Git не мог сказать, какие были изменения в моей рабочей копии.
2010 года

1
Это сработало отлично. Я не смог применить тайник, хотя я почти уверен, что мое рабочее дерево чистое.
Шики

Да, мне пришлось удалить строки о двоичном файле.
Дориан

8

Либо очистите свой рабочий каталог с помощью git reset, зафиксируйте изменения, либо, если вы хотите сохранить текущие изменения, попробуйте:

$ git stash save "описание текущих изменений"
$ git stash pop stash @ {1}

Это сохранит текущие изменения, а затем вытолкнет второй тайник из стека тайников.


5
Но этот парень хочет применить два тайника!
Элазар Лейбович

@Elazar Вы читаете в вопросе. ОП просто хочет применить предыдущий тайник. Если вы правы в том, что текущие изменения должны быть сохранены, решение может быть повторено: pop, commit, repeat.
Уильям Перселл

Я думаю, что он хочет, чтобы они оба не стеснялись. Но опять же, он может совершить их дважды и раздавить в один коммит.
Элазар Лейбович

Я получаю сообщение об ошибке "... уже существует, нет проверки ... Не удалось восстановить неотслеживаемые файлы из тайника"
Александр Дубинский,

6

Решение Матиаса определенно ближе всего к git stash pop --force (и действительно, давай разработчики Git, давайте уже получим эту опцию!)

Однако, если вы хотите сделать то же самое, используя только команды git, вы можете:

  1. git commit -a -m "Fixme"
  2. Git Stash поп
  3. git commit -a --amend
  4. git reset HEAD ~

Другими словами, сделайте коммит (который мы никогда не будем продвигать) ваших текущих изменений. Теперь, когда ваше рабочее пространство чистое, вставьте свой тайник. Теперь внесите изменения в тайник в качестве дополнения к вашему предыдущему коммиту. После этого оба набора изменений объединены в один коммит («Fixme»); просто сбросьте (--soft NOT --hard, так что на самом деле ничего не потеряно) вашу проверку на «один до этого коммита», и теперь у вас есть оба набора изменений, совершенно незафиксированные.

** РЕДАКТИРОВАТЬ * *

Я просто понял, что на самом деле это даже проще; Вы можете полностью пропустить шаг 3, так что ...

  1. git commit -a -m "Fixme"
  2. Git Stash поп
  3. git reset HEAD ~

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


4

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

  1. Выясните, как использовать хэш git reflog --all
  2. Объедините этот хэш с интересующей вас веткой

1
Большое спасибо, Яр. Я был разочарован тем, как Git странно себя вел в моем локальном репо сейчас, та же проблема, которую вы описали.
yclian

4

Я также нашел, что решение Матиаса Леппича прекрасно работает, поэтому я добавил псевдоним для него в свой глобальный .gitconfig

[alias]
        apply-stash-to-dirty-working-tree = !git stash show -p | git apply && git stash drop

Теперь я могу просто напечатать

git apply-stash-to-dirty-working-tree

который прекрасно работает для меня.

(Ваш пробег может варьироваться в зависимости от этого длинного псевдонима. Но мне нравится доза многословия, когда речь идет о завершении bash.)


3

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


2

У вас есть файлы, которые были изменены, но не зафиксированы. Либо:

git reset --hard HEAD (to bring everything back to HEAD)

или, если вы хотите сохранить изменения:

git checkout -b new_branch
git add ...
git commit
git checkout -b old_branch
git stash pop

1
@MikeCooper - я думаю, он просто хотел добавить все, что вы хотите добавить, прежде чем совершать.
sscirrus

0

У меня была та же проблема, но у git были ноль измененных файлов. Оказывается, у меня был файл index.lock, который валялся. Удаление это решило проблему.


0

Я не смог заставить большинство из них работать; по какой-то причине он всегда думает, что у меня есть локальные изменения в файле. Я не могу применить тайник, патчи не будут применены checkoutи reset --hardпотерпят неудачу. В итоге получилось сохранить сундук как ветку с git stash branch tempbranchnameпоследующим обычным слиянием веток: git checkout masterи git merge tempbranchname. С http://git-scm.com/book/en/Git-Tools-Stashing :

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.