Як трохи додаткового пояснення зверніть увагу, що git stash
робиться або два коміти, або три коміти. За замовчуванням два; Ви отримуєте три, якщо використовуєте будь-яке написання параметрів --all
або --include-untracked
.
Ці два, або три, коміти є особливими одним важливим чином: вони не знаходяться в жодному відділенні. Git знаходить їх за спеціальною назвою stash
. 1 Найголовніше, однак, це те, що Git дозволяє вам - і змушує - робити ці два-три коміти. Щоб зрозуміти це, нам потрібно подивитися, що в цих комітах.
Що всередині схованки
У кожному коміті може бути перелік одного або декількох батьківських комітів. Вони утворюють графік, де пізніше коміти вказують на попередні. Зазвичай сховище містить два коміти, які я люблю називати i
для вмісту індексу / області прогону та w
для вмісту робочого дерева. Пам'ятайте також, що кожен коміт містить знімок. У звичайному коміті цей знімок зроблений із вмісту індексу / області прогону. Тож i
коміт насправді є цілком нормальним комітом! Це просто не на жодній гілці:
...--o--o--o <-- branch (HEAD)
|
i
Якщо ви робите звичайний тайник, git stash
код робить w
зараз, копіюючи всі ваші відстежувані файли робочого дерева (у тимчасовий допоміжний індекс). Git встановлює першого з батьків цього w
коміту вказувати на HEAD
коміт, а другого з батьків - на фіксацію i
. Нарешті, він встановлює stash
вказівку на цей w
коміт:
...--o--o--o <-- branch (HEAD)
|\
i-w <-- stash
Якщо ви додаєте --include-untracked
або --all
, Git робить додатковий коміт, u
між перервами i
та w
. Вміст знімка для - u
це ті файли, які не відстежуються, але не ігноруються ( --include-untracked
), або файли, які не відслідковуються, навіть якщо вони ігноруються ( --all
). Це додаткове u
зобов'язання не мають ні батьків, а потім , коли git stash
марка w
, вона встановлює w
«s третього батька це u
зробити, так що ви отримаєте:
...--o--o--o <-- branch (HEAD)
|\
i-w <-- stash
/
u
На цьому етапі Git також видаляє будь-які файли робочого дерева, які заводились у u
коміті (використовуючи git clean
для цього).
Відновлення схованки
Коли ви хочете відновити схованку, у вас є можливість використовувати її --index
або не використовувати. Це говорить git stash apply
(або який - або з команд , які внутрішньо використовувати apply
, наприклад pop
) , що він повинен використовуватиi
зробити , щоб спробувати змінити свій поточний індекс. Ця модифікація виконується за допомогою:
git diff <hash-of-i> <hash-of-i's-parent> | git apply --index
(більш-менш; тут є купа дрібних деталей, які заважають цій основній ідеї).
Якщо ви пропустите --index
, git stash apply
повністю ігнорує i
коміт.
Якщо схованка має лише два коміти, git stash apply
тепер можна застосувати w
коміт. Він робить це, викликаючи git merge
2 (не дозволяючи йому фіксувати або розглядати результат як звичайне злиття), використовуючи вихідний коміт, для якого було зроблено сховище ( i
батьківський та w
перший батьківський) як основу злиття, w
як --theirs
commit, а ваш поточний (HEAD) коміт як ціль злиття. Якщо злиття вдається, все добре - ну, принаймні Git так думає - і git stash apply
само успіх. Якщо раніше ви git stash pop
застосовували схованку, код тепер скидає схованку. 3 Якщо злиття не вдається, Git оголошує заявку невдалою. Якщо ви використовувалиgit stash pop
, код зберігає схованку і надає той самий статус відмови, що і для git stash apply
.
Але якщо у вас є третій коміт - якщо u
у сховищі, яке ви застосовуєте, є коміт - тоді все змінюється! Немає можливості робити вигляд, що u
коміт не існує. 4 Git наполягає на вилученні всіх файлів із цього u
коміту в поточне дерево роботи. Це означає, що файли або не повинні взагалі існувати, або мати такий самий вміст, як у u
коміті.
Щоб це сталося, ви можете скористатися git clean
собою, але пам’ятайте, що файли, що не відстежуються (ігноруються чи ні), не існують у сховищі Git, тому будьте впевнені, що ці файли можуть бути знищені! Або ви можете створити тимчасовий каталог і перенести туди файли на зберігання - або навіть зробити інший git stash save -u
або git stash save -a
, оскільки вони працюватимуть git clean
за вас. Але це просто залишає у вас інший u
запас у стилі, з яким слід мати справу пізніше.
1 Це насправді refs/stash
. Це має значення, якщо ви робите філію з іменем stash
: повне ім’я філії refs/heads/stash
, тому вони не суперечать. Але не робіть цього: Git не заперечить, але ви заплутаєте себе. :-)
2git stash
код на насправді використовує git merge-recursive
прямо тут. Це необхідно з багатьох причин, а також має побічним ефектом переконання, що Git не розглядає це як злиття, коли ви вирішуєте конфлікти та фіксуєте.
3 Ось чому я рекомендую уникати git stash pop
на користь git stash apply
. Ви отримуєте шанс розглянути то , що отримав застосовані, і вирішити , чи був він на самому справі застосовується правильно. Якщо ні, у вас все ще є схованка, це означає, що ви можете використати, git stash branch
щоб відновити все ідеально. Ну, якщо припустити відсутність цього докучливого u
коміту.
4 Справді повинно бути: git stash apply --skip-untracked
або щось інше. Також повинен бути варіант, який означає викинути всі ці u
файли комітів до нового каталогу , наприклад git stash apply --untracked-into <dir>
, можливо.
git stash show -p | git apply --3