У меня была куча поэтапных и неустановленных изменений, и я хотел быстро переключиться на другую ветку, а затем вернуться обратно.
Поэтому я внес свои изменения, используя:
$ git stash push -a
(Оглядываясь назад, я, наверное, мог бы использовать --include-untracked
вместо --all
)
Затем, когда я пошел, чтобы открыть тайник, я получил много ошибок в следующих строках:
$ git stash pop
foo.txt already exists, no checkout
bar.txt already exists, no checkout
...
Could not restore untracked files from stash entry
Похоже, что никаких изменений из тайника не восстановлено.
Я тоже пробовал, $ git stash branch temp
но показывает те же ошибки.
Я нашел способ обойти это, которое нужно было использовать:
$ git stash show -p | git apply
Катастрофа пока предотвращена, но это вызывает некоторые вопросы.
Почему вообще возникла эта ошибка и как избежать ее в следующий раз?
git stash show -p | git apply --3
git stash show
и чем спасательными файлы один за другим:$ git show stash@{0}:your/stashed/file.txt > your_rescued_file.txt
. Это позволит получить файл из тайника и сохранить его под другим именем. Теперь вы можете безопасно экспериментировать с правильными методами спасения (см. Ответы ниже). Если что-то пойдет не так, спасенные файлы всегда будут последним ресурсом.Ответы:
В качестве небольшого дополнительного объяснения обратите внимание, что
git stash
выполняется либо две, либо три фиксации. По умолчанию два; вы получите три, если используете любое написание--all
или--include-untracked
.Эти два, или три, совершающие специальные в одном важном пути: они находятся на нет отрасли. Git находит их по специальному имени
stash
. 1 Однако самое важное - это то, что Git позволяет - и заставляет - делать с этими двумя или тремя коммитами. Чтобы понять это, нам нужно посмотреть, что находится в этих коммитах.Что внутри тайника
Каждая фиксация может содержать одну или несколько родительских коммитов. Они образуют график, где более поздние фиксации указывают на более ранние. Тайник обычно содержит две фиксации, которые я люблю вызывать
i
для содержимого индексной / промежуточной области иw
для содержимого рабочего дерева. Помните также, что каждый коммит содержит снимок. При обычной фиксации этот снимок создается из содержимого области индекса / промежуточной области. Таким образом,i
фиксация на самом деле является совершенно нормальной фиксацией! Его просто нет ни в одной ветке:Если вы создаете обычный тайник,
git stash
кодw
теперь копирует все ваши отслеживаемые файлы рабочего дерева (во временный вспомогательный индекс). Git устанавливает, что первый родительский элемент этойw
фиксации указывает наHEAD
фиксацию, а второй родительский элемент указывает на фиксациюi
. Наконец, онstash
указывает на этотw
коммит:Если вы добавите
--include-untracked
или--all
, Git сделает дополнительную фиксацию,u
между созданиемi
иw
. Содержимое моментального снимкаu
- это файлы, которые не отслеживаются, но не игнорируются (--include-untracked
), или файлы, которые не отслеживаются, даже если они игнорируются (--all
). Это дополнительноеu
обязательство не имеют нет родителей, а затем , когдаgit stash
маркаw
, она устанавливаетw
«s третьего родителя этоu
совершить, так что вы получите:Git также, на этом этапе, удаляет все файлы рабочего дерева, которые были завершены в
u
фиксации (используяgit clean
для этого).Восстановление тайника
Когда вы собираетесь восстановить тайник, у вас есть возможность использовать
--index
или не использовать его. Это говоритgit stash apply
(или какой - либо из команд , которые внутренне использоватьapply
, напримерpop
) , что он должен использоватьi
совершить , чтобы попытаться изменить свой текущий индекс. Эта модификация выполняется с помощью:(более или менее; здесь есть куча мельчайших деталей, которые мешают базовой идее).
Если вы опустите
--index
,git stash apply
полностью игнорируетi
фиксацию.Если в тайнике есть только две фиксации,
git stash apply
теперь можно применитьw
фиксацию. Он делает это, вызываяgit merge
2 (не позволяя ему фиксировать или обрабатывать результат как обычное слияние), используя исходный коммит, на котором был создан тайник (i
родительский элемент иw
первый родительский элемент) в качестве базы слияния,w
как--theirs
commit, а ваш текущий (HEAD) коммит в качестве цели слияния. Если слияние прошло успешно, все в порядке - ну, по крайней мере, Git так думает - иgit stash apply
само успешно. Если раньше вы применялиgit stash pop
тайник, код теперь отбрасывает тайник. 3 Если слияние не удалось, Git объявляет, что применение не удалось. Если вы использовалиgit stash pop
, код сохраняет тайник и выдает то же состояние отказа, что и дляgit stash apply
.Но если у вас есть третья фиксация - если
u
в тайнике, который вы применяете, есть фиксация - тогда все меняется! Невозможно сделать вид, чтоu
фиксации не существует. 4 Git настаивает на извлечении всех файлов из этогоu
коммита в текущее дерево работы. Это означает, что файлы должны либо не существовать вовсе, либо иметь то же содержимое, что и вu
фиксации.Для этого вы можете использовать
git clean
себя, но помните, что неотслеживаемые файлы (игнорируемые или нет) больше не существуют в репозитории Git, поэтому убедитесь, что все эти файлы могут быть уничтожены! Или вы можете создать временный каталог и переместить туда файлы для безопасного хранения - или даже сделать другойgit stash save -u
илиgit stash save -a
, поскольку они будут работатьgit clean
за вас. Но это просто оставляет вамu
тайник в другом стиле, с которым вы будете разбираться позже.+1 Это на самом деле
refs/stash
. Это имеет значение, если вы создаете ветку с именемstash
: полное имя веткиrefs/heads/stash
, поэтому они не конфликтуют. Но не делайте этого: Git не будет возражать, но вы запутаетесь. :-)2
git stash
код на самом деле используетgit merge-recursive
прямо здесь. Это необходимо по нескольким причинам, а также имеет побочный эффект, заключающийся в том, что Git не рассматривает это как слияние при разрешении конфликтов и фиксации.3 Вот почему я рекомендую избегать
git stash pop
в пользуgit stash apply
. Вы получаете шанс рассмотреть то , что получил применены, и решить , был ли он на самом деле применяется правильно. В противном случае у вас все еще есть тайник, а это значит, что вы можете использовать его,git stash branch
чтобы полностью восстановить все. Ну, при условии отсутствия этой надоедливойu
фиксации.+4 Там действительно должно быть:
git stash apply --skip-untracked
что ли. Также должен быть вариант, который означает перетаскивание всех этихu
файлов фиксации в новый каталог , напримерgit stash apply --untracked-into <dir>
, возможно.источник
--index
:git stash apply --index
?git stash save --all
, потом сразу сделалgit stash apply
, но некоторые файлы отсутствовали, потому что я переименовал их, а затем создал заново (перед тем, как спрятать). Что помогло:git checkout stash@{0} -- .
я даже не буду беспокоиться,git checkout stash^3 -- .
потому что теперь все в порядке. Жалко, что у меня нет времени по-настоящему понять, что происходит. Спасибо.Мне удалось воссоздать вашу проблему. Кажется, что если вы храните неотслеживаемые файлы, а затем создаете эти файлы (в вашем примере
foo.txt
иbar.txt
), тогда у вас есть локальные изменения в неотслеживаемых файлах, которые будут перезаписаны при примененииgit stash pop
.Чтобы обойти эту проблему, вы можете использовать следующую команду. Это отменит любые несохраненные локальные изменения, поэтому будьте осторожны.
Вот дополнительная информация, которую я нашел по предыдущей команде .
источник
--all
/-a
будет включать игнорируемые файлы , так что это может быть актуально.git merge --squash --strategy-option=theirs stash
в этом случае подход лучше).already exists, no checkout
), проверьте мой ответ ниже.Чтобы расширить ответ Дэниела Смита : этот код восстанавливает только отслеживаемые файлы, даже если вы использовали
--include-untracked
(или-u
) при создании тайника. Требуется полный код:git checkout stash -- . git checkout stash^3 -- . git stash drop # Optional to unstage the changes (auto-staged by default). git reset
Это полностью восстанавливает отслеживаемое содержимое (в
stash
) и неотслеживаемое содержимое (вstash^3
), а затем удаляет тайник. Несколько примечаний:git checkout
приводит к тому, что все они автоматически становятся постановочными, поэтому я добавилgit reset
все, чтобы отключить постановку.stash@{0}
иstash@{0}^3
в моем тестировании он работает одинаково с или без@{0}
Источники:
stash^3
коммите)источник
Помимо других ответов, я сделал небольшой трюк
git stash apply
(можно использовать любую команду, например, применить, поп и т. д.)источник