Вывод `git stash show` пустой

#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!