Ответ 1
Шкатулки
Вещь, сохраненная git stash
, - это то, что я сделал, чтобы называть "сумку для хранения" . Он состоит из двух 1 отдельных коммитов: фиксация "индекса" (промежуточная область) и "рабочее дерево". Компоновка рабочего дерева - забавный вид фиксации слияния.
Позвольте мне нарисовать это снова здесь (см. ответ с ссылкой для более длинной версии), чтобы просто проиллюстрировать его. Предположим для простоты, что у вас есть небольшое репо с одной ветвью и три фиксации на нем, A
через C
. Вы находитесь в одной ветке и делаете несколько изменений, а затем запускаете git stash save
(или просто просто git stash
). Это то, что вы получаете:
A - B - C <-- HEAD=master
|\
i-w <-- the "stash"
Теперь вы можете сделать (или переключиться на) другую ветвь, но, на иллюстрации, просто скажем, что вы оставите этот кошелек там и сделаете более "регулярные" фиксации на master
:
A - B - C - D - E <-- HEAD=master
|\
i-w <-- stash
Дело в том, что "суммарная сумка", пара i
ndex и w
ork-tree фиксируется, по-прежнему ведется с той же фиксации, что и раньше. Конец не может быть изменен, и это справедливо и для кошельков закладок.
Но теперь вы делаете новый тайник, делая некоторые изменения (пока все еще на master
) и снова запускаете git stash save
.
Что происходит со старой сумкой? "Ссылочное имя" 2stash
теперь указывает на новую сумку. Но старые кошельки все еще там. Теперь им требуется имя стиля "reflog", [email protected]{1}
. 3
В любом случае, у вас есть следующее:
A - B - C - D - E <-- HEAD=master
|\ |\
i-w i-w <-- stash
.
-------------- [email protected]{1}
(Когда вы используете git stash drop
, stash script просто манипулирует reflog для stash
ref, чтобы удалить идентификатор упавшего сумка-пакета. Поэтому все "высшие" перенумеруются. сама сумка-корзина - это сбор мусора на следующем git gc
.)
Этот следующий бит является ключом к пониманию того, что происходит.
В любое время git вам нужно указать конкретную фиксацию, вы можете сделать это любым из множества способов.
Каждая фиксация имеет "истинное имя", которое представляет собой большой уродливый хэш SHA-1, который вы видите, значения, такие как 676699a0e0cdfd97521f3524c763222f1c30a094
. Вы можете это написать. Это всегда означает одно и то же совершение. Конец никогда не может быть изменен и что криптографический хэш всего содержимого коммита, поэтому, если эта конкретная фиксация вообще существует, это значение всегда является его именем.
Это нехорошее имя для людей. Таким образом, у нас есть псевдонимы: такие, как имена ветвей и тегов, и относительные имена, такие как HEAD
и HEAD~2
, и имена типа reflog, такие как [email protected]{yesterday}
или [email protected]{1}
. (Там есть команда git rev-parse
), которая превращает такие строки в хеш-значения. Попробуйте: запустите git rev-parse HEAD
, git rev-parse stash
и т.д. Большинство вещей в git используют либо git rev-parse
, либо его старший брат что делает намного больше, git rev-list
, чтобы превращать имена в значения SHA-1.)
(Полное описание того, как назвать ревизию, см. gitrevisions. git использует SHA-1 для более чем просто коммиты тоже, но здесь давайте просто подумаем о коммитах.)
Git show show, git show и git diff
ОК, наконец, мы можем перейти к вашим git show
vs git stash show
и git diff
и так далее. Давайте сначала рассмотрим git stash show
, как тот, который вы должны использовать с записями. Кроме того, подкоманды git stash
будут проверять, что имя фиксации вы или, если вы не назовёте фиксацию, тот, который найден с помощью ссылки stash
, - выглядит как "кошелек", т.е. Является одним из этих смешных слияний совершает.
Если вы запустите git stash show -p
, git показывает вам diff (-p
atch). Но что именно он показывает?
Вернитесь к диаграмме с сумками. Каждая сумка-штабель вешается с определенной фиксацией. Выше "главный" тайник теперь висит от commit E
, а предыдущий тайник [email protected]{1}
висит от C
.
То, что git stash show -p
делает, сравнивает, что фиксация рабочего дерева stash, w
, против фиксации, из которой висит шкаф. 4
Вы можете, конечно, сделать это сами. Скажем, вы хотите сравнить w
в stash
, который отцепляет commit E
, от commit E
, который может быть назван именем ветки master
. Таким образом, вы можете запустить: git diff master stash
. Здесь имя stash
относится к (текущему) фиксации stash w
, а master
относится к commit E
, поэтому это дает то же самое патч, что и git stash show -p stash
. (И, если вы хотите сравнить w
в [email protected]{1}
с commit C
, вам просто нужно запустить git diff
, чтобы вы назвали эти две коммиты. Конечно, проще просто git stash show -p [email protected]{1}
.) 5
Как насчет простой git show
? Это немного сложнее. git show
счастлив показать фиксацию, и вы дали ей ссылку stash
(либо stash
, либо один из вариантов reflog). То, что действительный идентификатор фиксации, и он разрешает одно из рабочих деревьев w
, фиксируется в одном из пакетов. Но git show
действует по-разному, когда видит слияние. Как говорится в документации:
Он также представляет фиксацию слияния в специальном формате, создаваемом
git diff-tree --cc
.
Итак, git show [email protected]{1}
показывает вам "комбинированный diff", предполагая, что commit w
является нормальным слиянием commits C
и i
, создавая w
. В конце концов, это не нормальное слияние, хотя комбинация различий может быть действительно полезной, если вы знаете, что вы смотрите. Прочитайте документацию --cc
в разделе git diff-tree
, чтобы увидеть, как это работает подробно, но я должен заметить, что --cc
подразумевает -c
, который включает этот бит:
... перечислены только файлы, которые были изменены из всех родителей.
В случае stash
, если у вас есть git add
-ed файлы перед запуском git stash
, так что diff i
-vs- w
пуст, вы не увидите эти файлы на выходе здесь.
Наконец, если вы git diff [email protected]{M} [email protected]{N}
: это просто запрашивает git diff
, чтобы сравнить разные теги w
ork-tree. Сколько значения, которое имеет, зависит от того, что вы сравниваете, что обычно зависит от того, где прикреплены сумочки.
1 Два или три, действительно, но я собираюсь сделать это как два. Вы получаете две коммиты с git stash save
(или простой git stash
, что означает git stash save
). Вы получаете три фиксации, если вы добавляете параметры -u
или -a
для сохранения невоспроизводимых или всех файлов. Это влияет на восстановление косой черты, но не на результат команды git stash show
.
2 "Имя ссылки" - это просто имя, скорее как имя ветки или тега. Существует много возможных форм ссылочного названия. Филиалы и теги - это просто имена с особыми целями. "Удаленные ветки" - это еще одна форма этих ссылок, а "stash" также является ссылкой.
Фактически, HEAD
- это еще одна ссылка, хотя это очень специальная ссылка. Мне так важно, что если вы удалите файл HEAD
, git решит, что ваш репозиторий больше не является репозиторием.
С некоторыми исключениями для особых случаев - HEAD
, ORIG_HEAD
, MERGE_HEAD
, и так далее-ссылки все начинаются со строки refs/
. Филиалы начинаются с refs/heads/
, теги начинаются с refs/tags/
, а "удаленные ветки" начинаются с refs/remotes/
. Другими словами, ссылки имеют "пространство имен", обычно начиная с refs/
, а затем подбирают под ним другое слово, чтобы определить, где они живут.
Ссылка на stash написана refs/stash
(и останавливается там, нет refs/stash/jimmy_kimmel
или что-то в этом роде).
3 На самом деле это действительно использует reflog. Это означает, среди прочего, что задерживается, кроме "основного", refs/stash
, будет может истечь. (К счастью, как примечания musiphil, значение по умолчанию с git 1.6.0 заключается в том, что они не истекают, вы должны настроить время истечения для них, чтобы это произошло, вероятно, это не то, что вы хотите.)
4 Умный способ сделать это, используя нотацию суффикса ^
, изложено в моем другом ответе.
5 Что делать, если вы хотите посмотреть на i
ndex-коммиты в этих сумках? Ах, хороший вопрос!:-) Начертание script не имеет хорошего ответа. Легкий способ увидеть это - использовать суффикс ^2
, чтобы назвать второго родителя каждого тайника, который является фиксацией i
. И если у вас есть тайник с третьей фиксацией, содержащей неотслеживаемые или все файлы, то третий родитель: commit w
выглядит как слияние с тремя родителями, а stash^3
- третьим. Но опять же, w
не является нормальным слиянием, поэтому это сложно. Вероятно, лучший простой способ взглянуть на все части тайника - превратить его в свою отдельную ветвь, используя git stash branch
.