TL; DR
Чтобы увидеть имена файлов, используйте git ls-tree -r stash^3
; чтобы увидеть их содержимое, используйте git show stash^3
.
Long
Как мне показать фактическое содержимое sta sh, , включая неотслеживаемые файлы?
Неотслеживаемые файлы обычно отсутствуют в папке sh. Есть исключение - и вы его используете, так что я скоро к этому вернусь. Но показать эти файлы сложно. Использовать их еще сложнее. На мой взгляд, внешний интерфейс git stash
нуждается в некоторой работе.
Во-первых, важно понять, как Git работает внутри. Хранилище Git в основном представляет собой пару баз данных. Один - самый большой, почти всегда - содержит коммитов и другие Git объектов. Меньшая база данных содержит имена: имена веток, такие как master
, имена тегов, такие как v2.1
, имена для удаленного отслеживания, такие как origin/master
, и так далее. Имена ветвей и имена тегов и тому подобное - это конкретные c формы общего назначения ref или ссылка . Ссылка содержит один Git га sh идентификатор, чаще всего это коммит га sh идентификатор. 1
Каждый коммит также может содержать один или несколько предыдущих коммитов га sh идентификаторов. Это родители коммита. Для обычных (не sta sh) коммитов они обычно образуют хорошую простую цепочку: последний коммит запоминает в качестве своего родителя, второй до последнего. Этот второй за последним коммит запоминает своего родителя - прародителя последнего коммита - а дедушка вспоминает другого родителя и так далее. Коммит с двумя родителями по определению является коммитом слияния.
Итак, имя ветки просто содержит ha sh ID коммита, который, как мы хотели бы сказать, является последним коммитом в / on / of эта ветка. Несколько имен могут выбрать один и тот же идентификатор ha sh, и / или идентификатор ha sh может быть достижимым из какой-либо ветви, начиная с коммита наконечника и работая в обратном направлении. Таким образом, коммиты в Git часто находятся в нескольких ветвях.
В самих коммитах содержатся снимки всех ваших (отслеживаемых) файлов. Git делает их, записывая отслеживаемые файлы в Git index , а затем используя git write-tree
, который записывает файлы во внутренние объекты дерева, затем git commit-tree
, который записывает объект фиксации используя дерево (и), написанное git write-tree
. Таким образом, все коммиты имеют свое происхождение в индексе. И любой файл в индексе отслеживается по определению. Таким образом, это приводит нас к некоторой загадке.
1 Имена филиалов и имена удаленного отслеживания необходимы для хранения только совершить га sh идентификаторов; имена тегов более гибки.
sta sh
Специальный ref refs/stash
, если он существует, указывает на один коммит. Это stash@{0}
коммит. (Его записи reflog в stash@{1}
on up также указывают на один коммит каждый.) Таким образом, sta sh, когда он существует, состоит из коммитов. Эти коммиты находятся на ветке no : 2 вместо них они найдены через refs/stash
.
Обычный sta sh имеет форму коммит слияния, но не то же самое вещество. git stash
делает два коммита, используя метод очень низкого уровня git write-tree
и git commit-tree
, описанный выше. Первый такой коммит, основанный на том, что находится в вашем индексе, когда вы запускаете git stash save
или git stash push
, прост: git write-tree
уже просто записывает то, что находится в индексе, поэтому две команды, вместе взятые, делают этот индекс фиксации , который я называю i
(а документация git stash
вызывает I
).
Второй коммит более хитрый, но, по сути, git stash
выполняет: git add -u
(хотя без фактического использования git add -u
и тем самым вносит ошибки в различные версии git stash
, некоторые из которых в некоторых случаях приводят к неправильной фиксации рабочего дерева). Это обновляет индекс так, чтобы он содержал все отслеживаемые файлы в соответствии с их состоянием в рабочем дереве. Затем git write-tree
, а затем git commit-tree
делает хороший снимок вашего рабочего дерева, за исключением, конечно, всех неотслеживаемых файлов.
Поскольку git stash
использует низкоуровневые команды, оно может заставить коммит рабочего дерева - я называю это w
- с любым набором родителей, которых он выберет. Он делает этот коммит с обоими i
и HEAD
в качестве двух его родителей:
...--o--o <-- branch (HEAD)
|\
i-w
Коммит i
выглядит как любой обычный коммит, а коммит w
напоминает слияние. На самом деле это не слияние - это просто снимок вашего рабочего дерева, добавленный в индекс, но он имеет в качестве первого родителя коммит-наконечник вашей текущей ветви, а в качестве второго родителя - коммит i
.
После этого sta sh, git stash save
делает git reset --hard
, так что ваш индекс и рабочее дерево совпадают HEAD
. Сам HEAD
никогда не перемещается, а неотслеживаемые файлы не сохраняются и не затрагиваются.
Однако, когда вы делаете git stash save -u
или git stash save -a
, Git делает третью commit, который я называю u
. Этот третий коммит использует индекс, который очищается от всех отслеживаемых файлов, а затем загружается с некоторыми или всеми вашими неотслеживаемыми файлами, как если бы это было git add --force
по указанным c именам файлов. 3 Набор файлов, которые go в этом третьем коммите, зависит от того, использовали ли вы -u
или -a
: -u
перечисляет неотслеживаемые файлы, которые not игнорируется, а -a
перечисляет все неотслеживаемые файлы, даже если они игнорируются . Git копирует эти файлы в (ну, в) индекс и делает этот u
коммит без родителя вообще, за до он делает окончательный w
коммит. Затем он делает w
коммит с u
в качестве третьего родителя:
...--o--o <-- branch (HEAD)
|\
i-w
/
u
Таким образом, w^1
- это коммит в конце ветви, w^2
- это индексный коммит i
и w^3
- это коммит u
. w
продолжает напоминать коммит слияния - на этот раз слияние осьминога - но его снимок тот же, что и для любого двухкоммитового sta sh.
Сделав u
коммит, git stash save
или git stash push
сейчас удаляет из вашего рабочего дерева все файлы, которые находятся в коммите u
. Если некоторые файлы в u
также игнорируются, они все равно удаляются.
Применение трехкомпонентного sta sh завершается неудачно, если Git не может извлечь коммит u
в текущее рабочее дерево. , Так что определенно полезно знать, что находится в этом третьем коммите u
. Но нет git stash ____
(заполнить пробел глаголом), чтобы показать, существует ли коммит u
, тем более, что в нем. Поэтому мы должны прибегнуть к командам Git более низкого уровня.
В частности, поскольку u
является root commit , git show
будет отличаться от пустое дерево . Вы можете использовать git show --name-only
или git ls-tree -r
, чтобы получить список файлов, если вам не нужен полный diff. name commit u
, мы можем назвать любой sta sh commit - любой из w
commit объектов, на которые указывает refs/stash
или одну из записей reflog для него - и добавить ^3
суффикс для обозначения третьего родителя . Если у sta sh есть только w
и i
, ^3
потерпит неудачу: третьего родителя нет и, следовательно, нечего показать.
2 Вы можете, если хотите, на самом деле получить их на ветке, но результат ... в лучшем случае уродлив.
3 Внутренне git stash
использует временный индекс вместо реальный / основной индекс, чтобы сделать это проще. Он делает это и для коммита w
. Хотя существует один специальный индекс, индекс , который отслеживает ваше рабочее дерево, вы можете в любое время создать временный индекс, поместить его путь в GIT_INDEX_FILE
и использовать с ним команды Git. временный индекс вместо использования выделенного индекса. Это удобно для любой команды, которая должна создать коммит, для которого требуется использование индекса, который не хочет нарушать индекс в процессе.