Git stash при изменении последней фиксации (в gui) - поп ничего не делает

Итак, у меня были некоторые неустановленные изменения и некоторые поэтапные. Я выпустил

Welcome to Git (version 1.8.3-preview20130601)
$ git stash save --keep-index
Saved working directory and index state WIP on master: ab0d18d Setup of alarms f
or network service + Logging exceptions + long arithmetic
HEAD is now at ab0d18d Setup of alarms for network service + Logging exceptions
+ long arithmetic
$ git stash
Saved working directory and index state WIP on master: ab0d18d Setup of alarms f
or network service + Logging exceptions + long arithmetic
HEAD is now at ab0d18d Setup of alarms for network service + Logging exceptions
+ long arithmetic

Затем я нажимаю "Изменить последний фиксатор" в gui, чтобы разделить фиксацию ab0d18d на более мелкие. Я отключил некоторые файлы, и я нажал

$ git stash save --keep-index
Saved working directory and index state WIP on master: ab0d18d Setup of alarms f
or network service + Logging exceptions + long arithmetic
HEAD is now at ab0d18d Setup of alarms for network service + Logging exceptions
+ long arithmetic

Повторите описанную выше процедуру:

$ git stash save --keep-index
Saved working directory and index state WIP on master: ab0d18d Setup of alarms f
or network service + Logging exceptions + long arithmetic
HEAD is now at ab0d18d Setup of alarms for network service + Logging exceptions
+ long arithmetic

Затем я отредактировал сообщение фиксации, и я сделал. Затем я выпустил git stash pop, чтобы начать возвращать мои штампы и фиксировать их один за другим.

$ git stash pop
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       TODO.txt
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/[email protected]{0} (43facd88ea3548071b196324523bd017d680d6dd)

Бедствие!

У меня были резервные копии с радостью (длинный live dropbox)

2 вопроса:

  • Что я сделал не так?
  • Как можно оправиться от такого сценария?

EDIT: gitk после того, как я восстановил изменения (измененная фиксация - SETUP ALARMS)

enter image description here

ИЗМЕНИТЬ

Нашел способ воспроизвести проблему - будет ее корректировать (возможно, нужна только последняя часть - пыталась точно воспроизвести мой оригинальный сценарий), но для начинающих:

mkdir test_stash; cd  test_stash;git init
echo f1 >> f1 ; echo f2 >> f2 ; echo f3 >> f3 ; echo f4 >> f4 ; echo f5 >> f5
git add f1 f2 f3 f4 f5
git commit -m base123
echo change f1 to be amended >> f1
echo change f2 to be amended >> f2
echo change f3 to be amended >> f3
git add .
git commit -m tobeamended123
echo change f4 >> f4; git add f4
echo change f5 >> f5
git stash save --keep-index
git stash
git gui &

Теперь удалите команду fix commit в gui. Не уверен, какая команда ему соответствует, но git commit --amend не выполняет трюк.

enter image description here

В то время как в файле состояния изменения состояния f3 в gui снова (щелкните по нему, чтобы он перемещался по не прошедшей стадию области - был бы git reset HEAD f3, но это тоже не работает), затем

git stash save --keep-index
git commit -m amended # not really amended - a new commit altogether
git stash pop

Получение:

# # On branch master
nothing to commit, working directory clean
Dropped refs/[email protected]{0} (898687d73b65ccc9e10cd826bc12fda1a4759651)

Ожидание: изменения f3 для отображения

Ответ 1

/Я сохраняю первый длинный ответ ниже (может попытаться перенести его на новый вопрос позже), но теперь, когда есть "воспроизвести пример", я пройду через это. Позвольте мне сделать здесь список пунктов.

  • git stash всегда фиксирует индекс и рабочий каталог. Можно подумать, что --keep-index заставляет его зависеть больше или изменяет способ обработки спрятанного значения на pop. Это не так! Оба git stash apply и git stash pop смешивают разделенное изменение индекса по умолчанию. Добавление --keep-index не меняет этого. Только аргумент --index для apply и pop пытается избежать их смешивания.

  • "Рабочий каталог", который git stash экономит суммы, по сути, на изменение от текущего HEAD. Это означает, что если индекс имеет изменение от HEAD, но в текущем рабочем каталоге этого нет, в команде "WIP on branch..." не сохраняется никаких изменений. (Это, я думаю, ошибка в git stash. Я отправил тестовый пример и возможное исправление в список рассылки git. Для "нормальных" случаев это нормально, но если вы разделили некоторые части, а затем хотите восстановить ваше точное состояние позже с помощью git stash branch, оно перестает работать с каталогом, и это вызывает вашу проблему здесь.)

  • Применение stash пытается внести изменения в текущее состояние, которое отражает изменения в состоянии сшивания. Это может быть сложно, потому что текущее состояние не обязательно похоже на то, что было, когда вы сохранили тайник.

Вот что делает git-gui. В то время, когда вы запускаете его, у вас есть это (фактические числа фиксации, конечно, будут меняться). Немаркированный "WIP on master" является "первым" типом, теперь [email protected]{1}.

$ git stash list
[email protected]{0}: WIP on master: c93c8fe tobeamended123
[email protected]{1}: WIP on master: c93c8fe tobeamended123
$ git log --decorate --oneline --graph --all '[email protected]{1}'
*   3d01942 (refs/stash) WIP on master: c93c8fe tobeamended123
|\  
| * 6be9135 index on master: c93c8fe tobeamended123
|/  
| *   de8038c WIP on master: c93c8fe tobeamended123
| |\  
|/ /  
| * 3db6cfc index on master: c93c8fe tobeamended123
|/  
* c93c8fe (HEAD, master) tobeamended123
* 828d5cf base123

Теперь в git gui, когда вы выберете "modify last commit", он находит ref для фиксации HEAD (c93c8fe, в моем случае). На самом деле он ничего не делает (пока). Но как только вы нажмете на f3, чтобы его отключить, он делает что-то: он захватывает предыдущую версию f3 (я не уверен, что использует gui под собой, моя догадка будет HEAD^ copy) и материал это в индекс. Если вы просмотрите f3, в нем все еще есть лишняя строка, но если вы git show :0:f3, чтобы увидеть версию в индексе, она больше не имеет этой строки.

Обратите внимание, что никакие ссылки не были изменены из-за кликов с помощью мыши, а новых коммитов не было. Все действия произошли внутри индекса.

Затем вы вернулись в командную строку и запустили:

$ git stash save --keep-index

Это сделало третью пару коммитов, одну с индексом и одну с текущим каталогом. Версия индекса имеет дополнительную строку в f1 и f2 и не имеет дополнительной строки в f3. Текущая версия каталога должна (как она думает) иметь дополнительную строку во всех трех файлах, но, увы, это не так, потому что git stash save сравнивает текущий dir vs HEAD commit, а дополнительная строка находится в HEAD commit, поэтому он не находится в скрытой версии.

К сожалению, вы использовали этот аргумент --keep-index, поэтому теперь версия рабочего каталога такая же, как и сложенная версия индекса. Файл f3 больше не имеет дополнительной строки.

С этого момента проблема сохраняется (изменение не прошло, --keep-index перебросило его). Разумеется, вы можете восстановить его из первоначальной фиксации ( "tobeamended123" ). Но в этом случае в этом случае все пошло не так: командная строка stash сохранила индекс, а затем сравнила рабочий каталог с HEAD, который не изменился, поэтому не сохранил (без изменений) до f3.


Я не вижу катастрофы, но вижу что-то запутанное, что, по-моему, смущает вас. Я не знаю, почему вы использовали --keep-index выше. (На самом деле, я не уверен, какой прецедент --keep-index может быть предназначен для 1 и мне кажется, что apply и pop должны, вероятно, по умолчанию --index, но это совсем другое дело.) И вы сделали четыре тотальных "заталкивания", и только "выскочили", оставив троих.

[ 1 Я нашел предполагаемый прецедент, прямо там, в документации: для проверки того, что сейчас находится в индексе, перед его выполнением. Но подождите, huhwha?, --keep-index делает это, на stash ref. В любом случае, вы можете просто сделать это, используя git checkout -b test-stash, чтобы он был безопасно разделен, пока вы не удовлетворены этим. Если вы протестируете его, и он терпит неудачу, и вам нужно его изменить, это будет иметь конфликты. Если вы протестируете, и он работает, вы можете просто перетащить/ускорить-слияние сработавшего коммита в свою более раннюю ветвь.]

Короткий ответ "tl; dr"

Запустите git stash list. Вы увидите список:

[email protected]{0}: WIP on master: ab0d18d Setup of alarms ...
[email protected]{1}: WIP on master: ...

элементы. Используйте git stash apply --index '[email protected]{n}' (--index необязательно), чтобы попытаться применить каждый сохраненный штамп по имени и номеру, не выбирая ни один из них. Это стек, с [email protected]{0} самым последним нажатым и (по этой точке) [email protected]{3} нажатым первым (длиннее-назад).

Применить-без-поп означает, что вы можете git reset --hard вернуться к master и подготовиться к git stash apply другому типу. (Убедитесь, что вы запускаете всю последовательность с помощью чистого рабочего каталога, возможно, добавив еще один git stash, хотя это может снова запутаться.:-))

Если вы сделали особенно большой беспорядок, вы можете использовать use git stash branch name '[email protected]{n}'. Это большой, быстрый, эффективный молот, основным недостатком которого является то, что вам нужно придумать название ветки. (Вы можете git stash show заполнить, чтобы увидеть, что в них, чтобы помочь вам придумать имена.) Не позволяйте этому пугать вас, так как вы всегда можете переименовать ветвь или даже удалить ее позже. См. Подробное описание того, как это работает.

Когда вы все закончите со всеми вашими записями, используйте git stash clear, чтобы стереть их все.

Относительно git commit --amend vs git stash

На самом деле они несколько независимы. commit --amend работает в цепочке фиксации, основанной на любой ветке, в которой вы находитесь. Скажем, вы находитесь на master, и цепочка выглядит так (в git log --graph --oneline --decorate или gitk):

* 67dec43 (HEAD, master) "amendme" commit
* 9c37840 previous commit

Вы редактируете и git add некоторые вещи - я изменю файл f3 и добавлю его, а затем запустите git commit --amend. Это принимает индекс и совершает новое коммитирование, но новый родитель фиксации - это один назад, где master был, т.е. previous commit выше. Теперь вывод журнала выглядит следующим образом:

* 68c51f3 (HEAD, master) replacement for "amendme" commit
* 9c37840 previous commit

То, что вы не видите (потому что на нем нет метки ветвления), заключается в том, что 67dec43 все еще там (пока он не истечет и не получит мусор), но если вы скажете git log, чтобы посмотреть там, он будет:

$ git log --graph --decorate --oneline master 67dec43
* 68c51f3 (HEAD, master) replacement for "amendme" commit
| * 67dec43 "amendme" commit
|/  
* 9c37840 previous commit

У вас есть ветвь, отступающая от "предыдущей фиксации", с меткой master на новой замене фиксации и фиксацией "исправления" на немаркированной ветке.

Позвольте сделать это снова, с наложением на место на этот раз. Я начинаю с "известного плохого" файла в f3 в "исправлении". Затем я помещаю второй (но еще не правильный) f3 и запускаю git stash. Наконец, я исправляю f3 "для реального" и использую --amend. В stash содержится ссылка на теперь немаркированную ветку, потому что stash - это новая фиксация (действительно, две). Вот несколько последних шагов:

$ git log --graph --decorate --oneline
*   3c97241 (refs/stash) WIP on master: 67dec43 "amendme" commit
|\  
| * f3a50e9 index on master: 67dec43 "amendme" commit
|/  
* 67dec43 (HEAD, master) "amendme" commit
* 9c37840 previous commit
* 84408ef base
$ echo 'better changes for f3' > f3
$ git add f3
$ git commit --amend -m 'replacement for "amendme" commit'
$ git log --graph --decorate --oneline --all
* c1f1042 (HEAD, master) replacement for "amendme" commit
| *   3c97241 (refs/stash) WIP on master: 67dec43 "amendme" commit
| |\  
| | * f3a50e9 index on master: 67dec43 "amendme" commit
| |/  
| * 67dec43 "amendme" commit
|/  
* 9c37840 previous commit
* 84408ef base

Если вы попытаетесь применить stash, будет конфликт (потому что stash меняет файл f3, с моей промежуточной версией, "не совсем плохой, но не лучше" ):

$ git stash apply
git stash apply 
Auto-merging f3
CONFLICT (content): Merge conflict in f3
$ git reset --hard master
HEAD is now at c1f1042 replacement for "amendme" commit
$ git stash apply --index
Auto-merging f3
CONFLICT (content): Merge conflict in f3
Index was not unstashed.
$ git reset --hard master
HEAD is now at c1f1042 replacement for "amendme" commit

Это то же самое, что и любой другой конфликт при выполнении коммитов, например cherry-pick или merge, и вы разрешаете их одинаково.

Если вам нравится, вы можете наклеить ярлык ветки или тега на "исправление":

$ git branch master-old 67dec43
$ git log --graph --oneline --decorate --all
* c1f1042 (HEAD, master) replacement for "amendme" commit
| *   3c97241 (refs/stash) WIP on master: 67dec43 "amendme" commit
| |\  
| | * f3a50e9 index on master: 67dec43 "amendme" commit
| |/  
| * 67dec43 (master-old) "amendme" commit
|/  
* 9c37840 previous commit
* 84408ef base

и теперь он легко доступен для справки. Затем вы можете проверить это и git stash pop --index этот конкретный штамп; это гарантированно работает (следовательно, pop безопасен, хотя вы можете захотеть apply в любом случае, пока не выполните несколько из них). См. Также "Использование git stash branch" ниже, что автоматизирует это.

Как работает stash, длинная версия

Позвольте немного отступить. Я хочу показать упрощенный пример с тремя файлами.

Сделайте make temp dir и git repo и передайте начальную точку с тремя файлами с одной строкой:

$ mkdir /tmp/tt; cd /tmp/tt; git init
... # create files f1, f2, f3; git add ...
$ git commit -m base
[master 84408ef] base
 3 files changed, 3 insertions(+)
 create mode 100644 f1
 create mode 100644 f2
 create mode 100644 f3
$ ls
f1      f2      f3
$ cat f1 f2 f3
this file stays the same
this file changes in the index
this file changes in the WIP

Теперь сделаем изменения:

$ echo more for f2 >> f2; git add f2
$ echo more for f3 >> f3

В этот момент f2 изменяется и выполняется:

$ git diff --cached
diff --git a/f2 b/f2
index 78991d3..3a2f199 100644
--- a/f2
+++ b/f2
@@ -1 +1,2 @@
 this file changes in the index
+more for f2

и f3 изменен, но не поставлен:

$ git diff
diff --git a/f3 b/f3
index d5943ba..188fe9b 100644
--- a/f3
+++ b/f3
@@ -1 +1,2 @@
 this file changes in the WIP
+more for f3

Здесь diff --cached показывает поэтапный материал (в индексе) и diff без --cached показывает неустановленный материал.

Теперь пусть git stash (по умолчанию op - save). stash добавит две транзакции к репо. Первый - это всего лишь материал, поставленный до сих пор (если ничего не поставлено, stash заставляет в no-changes commit), а второй - слияние, этого-плюс-work-dir. Итак:

$ git stash
Saved working directory and index state WIP on master: 84408ef base
HEAD is now at 84408ef base
$ git log --graph --oneline --decorate --all
*   753a6c8 (refs/stash) WIP on master: 84408ef base
|\  
| * 36b23f2 index on master: 84408ef base
|/  
* 84408ef (HEAD, master) base

Этот первый, index on master, имеет мое изменение на f2:

$ git show 36b23f2
[snip]
diff --git a/f2 b/f2
index 78991d3..3a2f199 100644
--- a/f2
+++ b/f2
@@ -1 +1,2 @@
 this file changes in the index
+more for f2

Вторая имеет оба изменения (f2 и f3), но является фиксацией слиянием, поэтому git show показывает комбинированный diff, только показывающий f3:

$ git show 753a6c8
[snip]
diff --cc f3
index d5943ba,d5943ba..188fe9b
--- a/f3
+++ b/f3
@@@ -1,1 -1,1 +1,2 @@@
  this file changes in the WIP
++more for f3

(Помимо этого: если вы хотите сравнить любое слияние M с каждым родителем, используйте git show -m M. Например, git show -m 753a6c8 сначала различает 753a6c8^1 -vs- 753a6c8, тогда 753a6c8 ^ 2- VS- 753a6c8.)

Что с этим --keep-index вещью?

Обычно, после того, как вы выполните git stash, у вас есть чистый каталог, так что ничего не нужно "перепроверять":

$ git status
# On branch master
nothing to commit, working directory clean
$ git stash
No local changes to save

Но вы запросили тайник --keep-index. Это все еще делает обычную запись, но затем извлекает содержимое фиксации индекса, помещая его как в рабочий каталог, так и в индекс. Позвольте всплывать текущую шкатулку, посмотрите на состояние (git status - pop автоматически status, а затем git log --graph --oneline --decorate --all), и убедитесь, что мы вернулись к состоянию работы, но ничего не поставлено на этот раз:

$ git stash pop
...
$ git log --graph --oneline --decorate --all
* 84408ef (HEAD, master) base

Теперь переустановите f2 и переделайте stash save, но на этот раз с --keep-index:

$ git add f2
$ git stash save --keep-index
Saved working directory and index state WIP on master: 84408ef base
HEAD is now at 84408ef base

Выглядит так же, как раньше... но не совсем:

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   f2
#

Используйте git log --graph --oneline --decorate --all, и вы увидите в основном то же самое (с другими хэшами коммит), как и раньше: stash зафиксировал индекс, а затем совершил слияние-объединение дерева работ. Но на этот раз он также повторно извлек индекс, так что теперь у вас есть "изменения, которые нужно совершить". Это просто f2, а не f3.

Это означает, что вы можете (несколько бессмысленно) git stash save снова. И ты это сделал! Позвольте использовать эту функцию для создания логарифма-одной строки (я использую ее много), как до, так и после:

$ git log --graph --oneline --decorate --all
*   7efe9a6 (refs/stash) WIP on master: 84408ef base
|\  
| * 76c840e index on master: 84408ef base
|/  
* 84408ef (HEAD, master) base
$ git stash save
Saved working directory and index state WIP on master: 84408ef base
HEAD is now at 84408ef base
$ git log --graph --oneline --decorate --all
$ git lola
*   eb383e0 (refs/stash) WIP on master: 84408ef base
|\  
| * aba15e6 index on master: 84408ef base
|/  
* 84408ef (HEAD, master) base

Выглядит одинаково до и после, сначала краснеть. Но посмотрите на идентификаторы SHA-1. Они изменились! Перед вторым git stash save, refs/stash с именем commit 7efe9a6. Теперь он называет eb383e0!

reflog (или, обратите внимание, он становится сложным)

Хорошо, это не так уж плохо, но теперь вам нужно узнать о "рефлоге". Куда отправился другой stash? Ответ в том, что он "толкнул" и исчез в рефлоге. Там тоже небольшая лишняя морщина: "кошелек" не является регулярной ветвью или тегом. Вместо этого он находится в refs/stash. Итак, вот один из способов увидеть это, используя git log -g, что означает "посмотреть на логги":

$ git log -g --oneline refs/stash
eb383e0 refs/[email protected]{0}: WIP on master: 84408ef base
7efe9a6 refs/[email protected]{1}: WIP on master: 84408ef base

Aha, там они, как 7efe9a6, так и eb383e0. У них есть "полные имена пользовательских форм" (например, refs/[email protected]{1}), которые немного больны для использования. К счастью, stash работает (если вы не назовёте ветку stash), чтобы получить "самый верхний" {0}, и вы можете написать [email protected]{1} для другого. Или мы можем пойти на полномасштабную автоматизацию:

$ git log -g --pretty=format:%H refs/stash

Это выгружает их полные хэши, которые мы можем использовать в качестве аргументов для git log --graph --decorate, чтобы получить это:

$ git log --graph --oneline --decorate $(git log -g --pretty=format:%H refs/stash)
*   eb383e0 (refs/stash) WIP on master: 84408ef base
|\  
| * aba15e6 index on master: 84408ef base
|/  
| *   7efe9a6 WIP on master: 84408ef base
| |\  
|/ /  
| * 76c840e index on master: 84408ef base
|/  
* 84408ef (HEAD, master) base

Чтобы просто посмотреть, что еще "там", в репо.

(Или, конечно, вы можете использовать gitk, как вы, чтобы их видеть. gitk достаточно умен, чтобы искать блокировки stash.)

(Кроме того, вы также можете использовать git reflog show refs/stash. Подкоманда reflog show запускает git log -g --oneline.)

Вернемся к нашей проблеме, снова

Теперь, когда мы сделали первый git stash save --keep-index, а затем бессмысленный git stash save, теперь что?

Итак, мы можем git stash pop получить последний (самый верхний стек):

$ git stash pop
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   f2
#
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/[email protected]{0} (eb383e050d150a8ce5b69a3662849ffdd7070c89)

Что случилось с f3? Как мы отмечали ранее, второй git stash save сохранил только "сохраненный индекс", т.е. Только измененный f2. Нам нужно вернуться к первому титу.

$ git stash pop
error: Your local changes to the following files would be overwritten by merge:
    f2
Please, commit your changes or stash them before you can merge.
Aborting

Это не очень помогает, не так ли?: -)

Если вы не уверены, что вы делаете, сейчас самое подходящее время для создания ветки "сохранить материал" (вы всегда можете удалить ее позже). Просто git checkout -b help-me-spock или что-то еще, добавить и зафиксировать. Этот материал теперь находится на ветке и легче отслеживать. Но мы знаем, что делаем, и что у нас есть f2 в другом тайнике. Поэтому мы можем просто стереть это:

$ git reset --hard

Теперь мы вернемся к состоянию, которое у нас было бы, если бы мы выполнили только один git stash save, без --keep-index: мы находимся на master, при этом рабочий каталог очищен, и один сохраненный файл сохраняется, Мы можем git stash list it, git stash show и т.д. Итак, теперь:

$ git stash pop --index
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   f2
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   f3
#
Dropped refs/[email protected]{0} (7efe9a65c44156921bbbcb6a3df4edc5cb44492b)

и у нас все есть. (Или, без --index, stash будет просто применять все изменения к рабочему каталогу, а не восстанавливать индекс и work-dir.)

Использование git stash apply

Самое приятное в git stash pop заключается в том, что оно применяется, а затем удаляет самую верхнюю запись. Досадная вещь, она применяется, а затем бросает запись. Если вы используете git stash apply вместо этого, он зависает на нем.

Кроме всего прочего, это очень удобно, если вы пропустили --index как --keep-index (я делал это более одного раза, набрав это), или оставьте его, а потом решите, что было бы неплохо его использовать. Вы можете git reset --hard и повторно выполнить apply.

Если вы закончили с записью, git stash drop entry удалит ее из журнала. Например, предположим, что вы выполняете git stash apply --index '[email protected]{1}', а затем решите все это хорошо и захотите add и/или commit, а затем забудьте об этом тире. Затем вы можете git stash drop '[email protected]{1}'. Недостатком является то, что это повторяет остальные: что было [email protected]{2} становится [email protected]{1} и так далее. Мне иногда легче держать их вокруг и использовать git stash clear, чтобы избавиться от всех из них сразу, в конце.

Подождите минуту, что с этими --index -es?

По умолчанию git stash apply и git stash pop берут сохраненный индекс ( "изменения, поставленные для фиксации" ) и незавершенное производство ( "изменения не поставлены для фиксации" ), и вставляют их в действие как работу -прогресс. Часто это прекрасно, но если вы тщательно поставили несколько бит и оставили других неуправляемыми, вам вполне может понадобиться все это. Аргумент --index для applypop) пытается это сделать. Иногда это оказывается "слишком тяжелым". В этом случае у вас есть два варианта: оставьте --index или используйте git stash branch.

Использование git stash branch

Я упоминал выше, в разделе измененных коммитов против stashes, что вы можете добавить новую метку ветки в фиксацию, на которой есть набросок, а затем apply или даже pop соответствующий stash, с --index, и он всегда будет работать. Причина проста: stash - это фиксация слияния индекса и WIP, соответствующая фиксации, на котором они включены. Если вы проверите, что commit (как "отсоединенный HEAD" ), индекс и WIP будут применяться чисто.

Итак, предположим, что вы добавляете новое имя ветки в рассматриваемом коммите и переходите к новой ветке (git checkout -b newname). Теперь примените (и вытащите) stash, используя --index: теперь вы находитесь в точно таком же состоянии, что и при первом запуске git stash save, за исключением того, что ветка имеет другое имя. И это то, что делает git stash branch: вы даете ему новое имя ветки и указываете, какой кошелек использовать (по умолчанию это refs/stash, A.K.A. [email protected]{0}). Он использует эту запись stash для поиска родительского коммита, прикрепляет туда название ветки и затем выполняет git stash pop --index.

На этом этапе вы можете использовать git status, git diff --cached, git diff и т.д., чтобы узнать, что в индексе, а что нет, решить, что еще добавить, а затем git commit добавить новый материал к новой ветки, которую вы создали.