Вам просто нужно взглянуть на третий коммит.Но «просто нужно» немного преуменьшает значение, и это не имеет никакого смысла, пока вы не узнаете, что из трех коммитов есть .Чтобы понять, что я имею в виду, читайте дальше.
Настройка: что нужно знать о тайниках
Когда вы запускаете git stash save
или git stash push
, обычным действием Git является создание two коммитов, ни один из которых не находится ни на одной ветви.Если вы нарисуете картинку «до», как это, вы получите следующую серию коммитов:
...--o--o--* <-- branch (HEAD)
После завершения git stash save
у вас будет два новых коммита, которые не находятся на веткеbranch
и не в любой другой ветви:
...--o--o--* <-- branch (HEAD)
|\
i-w <-- the stash
Фиксация w
сохраняет состояние рабочего дерева, в то время как фиксация i
сохраняет индекс.Каждый из этих двух коммитов очень похож на любой другой коммит, и фактически фиксация i
выполняется с использованием большей части обычного механизма git commit
: Git записывает текущий индекс во внутренний объект tree используя git write-tree
, затем создает commit объект, используя git commit-tree
.Если вы не знаете, что это за внутренние объекты, не беспокойтесь об этом: дело в том, что именно так git commit
выполняет большую часть своей работы, записывая дерево, а затем объект фиксации.(Остальная часть git commit
состоит в том, чтобы сначала собрать ваше лог-сообщение и обновить имя ветки в конце.)
Коммит w
немного сложнее, потому что он имеет форму (но не намерение) коммита merge с двумя родителями вместо одного.Но в основном он сохраняет снимок рабочего дерева, как если бы вы запустили git add
для всех отслеживаемых файлов.
При добавлении --all
или --include-untracked
(-a
или -u
для краткости), что делает git stash
, так это то, что он добавляет третий коммит, который мы можем нарисовать следующим образом:
...--o--o--* <-- branch (HEAD)
|\
i-w <-- the stash
/
u
Третий коммит является снимком, но этоочень странный снимок.Он содержит только неотслеживаемых файлов - либо неотслеживаемых, но не игнорируемых файлов (git stash save -u
), либо неотслеживаемых файлов , включая неотслеживаемых и игнорируемых файлов (* 1058)*).У него также нет родительского коммита.
стека "stash", хеш-идентификаторов коммитов и родителей
Одна причина 1 , что Git добавилpush
глагол, как в git stash push
- который в целом является синонимом save
- это то, что когда вы создаете новый тайник, Git использует тайник reflog для отслеживания более ранних тайников.Текущий тайник stash@{0}
в терминах reflog, а ранний тайник становится stash@{1}
.
Каждое из этих имен является лишь частным случаем более общей вещи, которую дает вам Git: вы можете ссылаться на любойЗафиксируйте любое имя, которое соответствует правильному хэш-идентификатору .«Истинное имя» любого коммита - это его большой уродливый хэш-идентификатор. Документация gitrevisions содержит полное описание всех способов написания хэш-идентификатора в Git;использование имени, такого как branch
или stash
, является одним из таких способов.
Использование имени stash
специально определяет фиксацию w
.Затем Git использует w
для поиска коммита i
и, если он существует, коммит u
.Git может сделать это, потому что каждый коммит включает хэш-идентификаторы его parent commits.w
имеет форму коммита слияния в том, что у него есть как минимум два родителя: i
, индексный коммит и *
, коммит, на котором вы сидели, когда запускали git stash save
или git stash push
во-первых.
Мы можем модифицировать большинство спецификаторов ревизий (например, stash
), добавив символ вставки ^
и число, чтобы посмотреть конкретно на пронумерованного родителя.Запись stash^1
- это способ фиксации именования *
;запись stash^2
- это способ присвоения имен фиксации i
.Если коммит u
существует, запись stash^3
дает ему имя.Обратите внимание, что в некоторых системах (Windows) ^
может быть специальным символом, который требует удвоения или цитирования, поэтому вместо stash^3
вам может понадобиться stash^^3
.
1 Другая причина заключалась в том, чтобы добавить возможность частичного сохранения с использованием pathspecs: git stash save
принимала любые дополнительные аргументы в качестве сообщения для включения в коммиты stash, поэтому им был нужен новый глагол, который использовал -m
чтобы указать сообщение, оставляя место для аргументов pathspec.
Просмотр u
commit
Мы можем просмотреть любой коммит, используя git show
.Поскольку stash w
фиксирует это осечки, потому что Git считает, что коммит w
является слиянием, поэтому мы можем использовать git stash show
вместо этого.(Это - это слияние, просто не то, которое git show
может показать правильно.) Мой более ранний ответ на связанный вопрос требует использования git diff
в коммите u
,потому что в данном конкретном случае мы не хотим получать заголовок, который показывает git show
, но если мы просто хотим посмотреть фиксированный файл, то можно использовать git show
здесь:
git show stash^3
например.Вот вывод для приведенного выше примера foo
:
$ git show stash^3
commit 4c9bd2486706980f5a492d19c49270381db2d796
Author: Chris Torek <chris.torek gmail.com>
Date: Sun Sep 16 12:35:03 2018 -0700
untracked files on master: f72737e initial
diff --git a/foo b/foo
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/foo
@@ -0,0 +1 @@
+foo
Использование имени наподобие stash@{1}
идентифицирует коммит в записи reflog # 1, которая является следующей копью в вашем "стэке стека".(Reflog начинает отсчет с нуля, поэтому stash
и stash@{0}
означают один и тот же коммит.) Так что для stash@{1}
вам потребуется stash@{1}^3
или, возможно, stash@{1}^^3
.