#git #git-stash
#git #git-stash
Вопрос:
У меня есть скрипт обновления, который запускается
git stash -k -u
Перед обновлением до последней версии.
Обычно это выводит: No local changes to save
Но с некоторого времени он выдает: Saved working directory and index state WIP on generated: build
хотя в рабочую копию не было внесено никаких изменений.
Когда я пытаюсь проверить содержимое любого из тайников, оно тоже кажется совершенно пустым:
$ git stash list
stash@{0}: WIP on generated: bc0c9f6 build
stash@{1}: WIP on generated: 1d83819 build
stash@{2}: WIP on generated: 6aff261 build
stash@{3}: WIP on generated: ac3f8a9 build
stash@{4}: WIP on generated: bf0d020 build
stash@{5}: WIP on generated: ba972db build
stash@{6}: WIP on generated: 2c5cfe3 build
$ git stash show stash@{0}
$ git stash show stash@{1}
И т.д… выходные данные пусты для всех тайников. То же самое, если я укажу -p
флаг stash show
команде.
Мне нужна помощь в выяснении содержимого этих тайников, чтобы предположить, зачем они вообще создаются.
Комментарии:
1. Возможно, вашего
show
недостаточно. Конечно, нет никакой разницы с последним коммитом , но это не то, что вы хотите знать.2. Я не знаю, почему
git stash show
не показывает различия для совершенно новых файлов и не может найти его сейчас, но я знаю, как это исправить, если это проблема:git show stash@{0}
3. @Ry- это все еще показывает мне то, что кажется пустой разницей, см.: gist.github.com/sgtlambda/59f942e8f1dbdf61496033deb1774dfc
4. @matt не могли бы вы подробнее остановиться на этом? У меня всегда было это в голове, что тайники — это более или менее полностью независимые коллекции изменений?
Ответ №1:
На самом деле тайник — это просто коммит, или, точнее, два или три коммита (в зависимости от параметров тайника). Поскольку вы используете -u
, вы получаете вариант с тремя фиксациями.
Я вызываю три коммита i
, w
и (при наличии) u
. i
Фиксация выполняется путем фиксации содержимого индекса таким же образом, как это было бы git commit
, за исключением того, что фиксация не переходит ни в одну ветку.
u
Коммит, если он присутствует, содержит только неотслеживаемые, но не игнорируемые файлы (с -u
; с -a
он содержит больше файлов). Выполнив этот u
коммит, Git затем удаляет из вашего рабочего дерева все файлы, сохраненные в этом коммите.
w
Фиксация всегда выполняется последней и содержит тот же набор файлов (имена файлов), что и в i
фиксации, но содержимое этих файлов в w
фиксации соответствует содержимому копий этих файлов в вашем рабочем дереве, а не содержимому индексных копий.
Когда git stash
without -u
не находит различий между HEAD
фиксацией, текущим индексом и вашими файлами рабочего дерева, которые имеют имена копий, которые находятся в индексе, git stash
отказывается создавать новый тайник, выдавая вместо этого упомянутое вами сообщение об ошибке ( No local changes to save
). Однако, если у вас есть неотслеживаемые файлы, он должен создать тайник, а затем удалить эти неотслеживаемые файлы. Это приведет к созданию тайника, в котором i
и w
содержимое совпадают, и оба соответствуют фиксации, которая была HEAD
во время вашего запуска git stash
.
git stash
Команда была переписана в недавнем Git, и некоторые из ее поведенческих параметров, возможно, изменились. Если это так, то это ошибка, и вы должны сообщить о ней сообществу Git (в идеале, с помощью средства воспроизведения и конкретных версий Git, в которых поведение отличается).
Обратите внимание, что git stash show
просто просматривается w
фиксация. Как и у всех коммитов, у всех трех i
, u
и w
коммитов могут быть родительские коммиты. (Единственным) родительским элементом i
коммита является коммит, который был текущим на момент создания тайника. u
Фиксация, если она существует, является корневой фиксацией (не имеет родительского элемента). w
Коммит имеет либо два, либо три родителя: первый — это коммит, который был текущим на момент создания тайника, второй — это i
коммит, а третий, если он присутствует, — это u
коммит. То есть, мы можем нарисовать график фиксации следующим образом:
...--F--G--H <-- current-branch (HEAD)
|
i-w <-- stash
/
u
Название stash
(полное имя refs/stash
) указывает на w
фиксацию. Текущая ветвь здесь current-branch
(полное имя refs/heads/current-branch
) указывает на текущую фиксацию, и к имени HEAD
присоединено специальное имя, current-branch
чтобы Git мог найти идентификатор хэша фиксации H
.
Следовательно, Commit H
является родительским для i
и первым родительским для w
. Git определяет наличие или отсутствие фиксации u
по w
наличию третьего родительского элемента.
git stash show -p
эквивалентен git diff stash stash~1
, т.е. сравнивает содержимое файлов в commit H
с файлами в commit w
. Если причина создания тайника заключается в том, что он u
существует или i
отличается от i~1
, то нет необходимости w
отличаться от w~1
.
Комментарии:
1. Вы можете добавить: run
git show stash@{xx}^3
для просмотра неотслеживаемых файлов, которые, возможно, были сохранены2. @LeGEC: хорошая мысль; вы также можете использовать
git show stash@{number}^2
для просмотра различий междуi
фиксацией и ее родительским элементом (H
на диаграмме в ответе выше). Однако, посколькуw
фиксация имеет форму фиксации слияния, вам нужноgit stash show
(илиgit diff
) просмотреть ее относительно ее первого родительского элемента.3. Блестящий ответ @torek!