Когда я делаю git stash, а затем git stash, мои изменения всегда неизменны - PullRequest
1 голос
/ 11 декабря 2019

Если у меня есть несколько готовых файлов и несколько неподготовленных файлов, и мне нужно временно их спрятать, я запускаю:

git stash

Затем, когда я хочу вернуть их позже, я делаю:

git stash pop

Тем не менее, файлы теперь все не установлены, даже если они были предварительно подготовлены перед сохранением. Есть ли какой-нибудь способ вставить тайник так, чтобы он запомнил, какие файлы были размещены и не размещены, и восстанавливает их до того состояния, в котором они находились до того, как вы их спрятали?

Ответы [ 2 ]

4 голосов
/ 11 декабря 2019

Вы можете использовать git stash pop --index или git stash apply --index для ваших поэтапных коммитов.

1 голос
/ 12 декабря 2019

Когда Сэм ответил , вы хотите использовать опцию --index. Хотя полезно понять, что происходит внутри.

Когда вы делаете тайник - с git stash save или более новым глаголом, git stash push 1 -Git фактически выписывает два коммита. Это потому, что коммит является основной единицей хранения Git. 2 Причина, по которой два из них, заключается в том, что один из них хранит то, что находится в index Gitа другие хранят то, что находится в вашем рабочем дереве .

Вы выполняете свою работу - просматриваете и редактируете свои файлы - с обычными файлами, которые вы можете просматривать и редактировать. Они находятся в вашем рабочем дереве (также называется рабочее дерево или любое количество похожих слов и фраз; старая версия Git также использовала фразу рабочий каталог или рабочий каталог ). Это все довольно просто, потому что все инструменты и программы вашего компьютера могут работать с этими файлами.

Но Git не делает коммиты из рабочего дерева. Git делает новые коммиты из index . Индекс настолько важен (и / или так плохо назван), что в Git он имеет три имени: Git иногда называет его «индексом», как этот, но иногда называет его промежуточной областью , а иногда - редков наши дни - называет это кеш . Вы уже знакомы с идеей использования его для создания обновленных файлов;отсюда и название область подготовки . Но на самом деле индекс содержит копию 3 из каждого файла, который будет добавлен в ваш следующий коммит. Эта копия начинается так же, как в текущем коммите, и когда вы обновляете файлы и git add их, индексная копия заменяется обновленным файлом.

Другими словами,индекс содержит то, что вы предложили сделать следующий коммит. Запуск git add обновляет этот предложенный следующий коммит. Чтобы сказать вам, чем отличается между вашим текущим коммитом и вашим предлагаемым следующим коммитом, git status просто сравнивает файлы в текущем коммите с файлами в индексе. Когда они одинаковы, они ничего не говорят, а когда они разные, они говорят «готовятся к коммиту».

Итак: когда вы запускаете git stash save или git stash push, Git сначала делает коммит изиндекс, так же, как он может сделать любой коммит из индекса. Затем stash-код создает временный индекс - копируя обычный / реальный - и git add s все файлы из рабочего дерева во временный индекс, например git add -u. Затем он делает коммит из этого временного индекса, который соответствует вашему рабочему дереву.

Отсюда и два коммита. Все тайники имеют как минимум эти два коммита. Если вы создаете тайник с флагом -u или -a, это добавляет третий коммит ... который становится грязным, поэтому давайте просто предположим, что вы никогда этого не сделаете.

Когда вы применяете или pop a stash - pop просто означает apply затем drop - в этот момент вы выбираете, использовать ли первый коммит stash с содержимым индекса или нет. Если вы используете флаг --index, Git попытается применить фиксацию индекса к вашему текущему индексу. Это, по сути, запускает операцию git diff, переданную по каналу git apply --cached (это гораздо легче увидеть в старом сценарии оболочки git stash, который буквально выполнялся git diff-tree --binary $s^2^..$s^2 | git apply --cached).

Если вы не't используйте опцию --index, git stash apply просто игнорирует спрятанный индекс! Он просто выполняет оставшуюся часть git stash apply, то есть запускает git merge-recursive 4 непосредственно на трех коммитах, необходимых для объединения спрятанного рабочего дерева с вашим текущим рабочим деревом. Если этот шаг завершится успешно, git stash pop сделает сброс тайник, что очень затрудняет восстановление индекса.

Я обычно рекомендую избегать git stash полностью, 5 но если вы используете его, я рекомендую избегать git stash pop. Легко забыть флаг --index. Если вы использовали git stash apply, у вас все еще есть тайник, и вы можете сбросить настройки (см. Сноску 4) и повторить попытку с помощью --index.


1 Tон save глагол был единственным доступным до Git 2.13. В этой версии Git добавлен глагол push, позволяющий использовать несколько дополнительных опций.

2 Существует внутренняя единица хранения меньшего размера, называемая blob ,но он не подходит для тайников: вам нужно много больших двоичных объектов с именами, хранящимися во внутренних объектах Git tree , и чтобы собрать их все вместе, вам нужен объект commit , поэтомуcommit - это основная единица хранения в Git.

3 Технически, индекс содержит ссылки на внутренние объекты BLOB-объектов , упомянутые в сноске. 2. Эти объекты BLOB-объектов хранят данные файлов в сжатом, доступном только для чтения формате, который Git использует, чтобы файлы были небольшими и готовыми для совместного использования. Поскольку они предназначены только для чтения, скажем, копия, скажем, README.md, которая находится в десятках или сотнях коммитов, может быть совместно используемой , когда это такая же копия. Индекс также может поделиться им. Запись нового файла в индекс с git add на самом деле просто сжимает содержимое файла в формат BLOB-объектов. Это автоматически разделяет любую существующую копию файла или создает новый BLOB-объект, если необходимо.

4 Вы, вероятно, никогда не должны запускать git merge-recursive самостоятельно, так как он обходит "все безопасно передано"" проверить. Эта проверка гарантирует, что в случае неудачного слияния вы можете восстановить с помощью git reset --hard. Код git stash обходит эту проверку и, следовательно, может сделать невозможным восстановление после попытки применить тайник. Поэтому хорошая идея, если вы вообще используете git stash, чтобы убедиться, что git status говорит, что сначала все чисто.

5 Я все еще использую его сам, но оченьредко и только если я уверен, что это сработает. Даже тогда я могу случайно сжечь себя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...