Как игнорировать добавленные фрагменты в `git stash -p` - PullRequest
0 голосов
/ 09 мая 2018

Представьте себе этот сценарий:

# edit two files
git add -p // add hunks from one file

Теперь, когда вы запустите git stash -p, он снова спросит вас, хотите ли вы спрятать блоки, которые вы только что выбрали с помощью git add -p. Есть ли способ настроить git на игнорирование этих уже добавленных блоков по умолчанию? Большую часть времени я не хочу прятать то, что я уже добавил.

Ответы [ 3 ]

0 голосов
/ 13 мая 2018

На странице руководства есть похожий пример:

Хитрость человека:

"Testing partial commits
You can use git stash save --keep-index when you want 
to make two or more commits out of the changes in the 
work tree, and you want to test each change before 
committing:

# ... hack hack hack ...
$ git add --patch foo            # add just first part to the index
$ git stash save --keep-index    # save all other changes to the stash"*

Я могу подтвердить:

Если вы используете git stash -p (что подразумевает --keep-index), вас все равно спросят, следует ли хранить изменения, которые уже есть в индексе (как вы уже описали).

Итак, кажется, что man-страница сбивает с толку, что также упоминается в другом месте: https://github.com/progit/progit2/issues/822

Подводя итог:

--keep-index (или -p, что подразумевает --keep-index) просто оставляет индекс без изменений. Уже внесенные изменения все еще вставляются в тайник. И AFAIK, нет способа сделать то, что вы описали.

Или, точнее (снова из справочной страницы):

With --patch, you can interactively select hunks from 
the diff between HEAD and the working tree to be stashed. 

The stash entry is constructed such that its index state 
is the same as the index state of your repository, and its 
worktree contains only the changes you selected interactively.

Альтернативы:

Есть как минимум 3 способа достичь желаемого (более или менее):

  • Не используйте -p с git stash. Спрятать все (с --keep-index и, возможно, --all, чтобы убедиться, что вы убрали все в безопасности).
  • Передайте ваши поэтапные изменения перед копированием. Таким образом у вас не будет различий между HEAD и рабочим деревом для тех изменений, которые вы хотите опустить в stash. Но что, если вы не уверены, что хотите это совершить? Вы всегда можете внести изменения позже и использовать --amend для изменения существующего коммита.
  • Отменить внесение изменений (удалить из индекса) и затем спрятать.
0 голосов
/ 28 мая 2018

Ладно, из комментариев нам нужен тайник всех изменений, которые еще не были добавлены (независимо от того, были ли они исключены во время git add -p или просто еще не добавлены).

Причина этого заключается в том, чтобы применить некоторые тесты / потенциальные настройки к промежуточному состоянию до его фиксации.

Это просто git stash -k, спрятать все как обычно, но сохранить индексируемое состояние и соответствующее рабочее дерево, то есть очистить от рабочего дерева все, что я не собираюсь фиксировать.

Итак:

git stash -k
git clang-format
git commit

и в репозитории теперь есть четыре интересных снимка: исходное содержимое, также называемое базой хранения, индекс моментального снимка, рабочее дерево моментального снимка и текущий индекс (, коммит и рабочее дерево), который является моментальным снимком индекса в stash^2 с чистками применяется. Обратите внимание, что все три из новых снимков, также известные как коммиты, имеют в качестве родительской базы тайник.

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

Если бы Git предложил то, что вы хотите напрямую, «спрятать все изменения рабочего дерева , за исключением изменений в индексе», вы могли бы использовать это, и тогда у всплывающего окна не было бы никаких проблем, прямо git stash pop сделает это. К счастью, если Git хорош во всем, он объединяет, объединяет, разделяет и объединяет все различия.

git cherry-pick -nm2 stash
# cherry-pick updated the index, too. maybe git reset here to unstage that stuff.
git stash drop

Stash pop - это слияние изменений из базы stash в состояние stashed с изменениями из базы stash (которая обычно очень похожа на текущую базу) в текущее состояние. Вы хотите, чтобы спрятанное рабочее дерево изменилось в вашем рабочем дереве, но только те, которые вы еще не добавили, поскольку те, к которым вы добавили , добавили , все еще здесь, они просто немного изменились.

Таким образом, вишневый пик - -n, без фиксации, -m2, основной строкой изменений является его второй родительский элемент, т. Е. Все различия, которые вы внесли, но не добавили при копировании.

Пример может помочь,

 cd `mktemp -d`
 git init
 printf >file %s\\n 1 2 3 4 5
 git add .;git commit -m1
 printf >file %s\\n 1 2a 3 4 5
 git add .
 printf >file %s\\n 1 2a 3 4a 5

теперь вы фактически git add -p изменили 2a, а изменение 4a только в вашем рабочем дереве.

 $ git stash -k
 $ cat file
 1
 2a
 3
 4
 5
 $ sed -i '2s,^,_,' file   # indent the 2a line
 $ git commit -am2

Теперь начальный коммит :/1 равен 1 2 3 4 5, ваш текущий коммит, индекс и рабочее дерево все 1 _2a 3 4 5, ваш спрятанный индекс 1 2a 3 4 5 и ваш спрятанный рабочий дерев 1 2a 3 4a 5.

Изменения, которые вы хотите вернуть, - это разница между вашим сохраненным индексом и вашим скрытым рабочим деревом, это отличие фиксации stash от его второго родителя. Отсюда и эта вишня.


Альтернативные способы написания вишни включают

git cherry-pick -nm1 -Xours stash

, который применяет все спрятанные изменения рабочего дерева, но принимает локальную версию в случае конфликта (в основном это поиск и выбрасывание конфликтующих различий вместо того, чтобы просто избегать их, как -m2 делает) и

git diff stash^2..stash|git apply -3

Облегчить все это для себя - это территория скриптинга, самый простой способ поговорить о настройке - это как псевдоним git,

git config --global alias.poptree '!git cherry-pick -nm2 stash; git reset; git stash pop'

и теперь у вас есть команда git poptree, чтобы делать то, что вы хотите.


edit: предположим, что вы продвинулись вперед и проделали еще некоторую работу, прежде чем запоминать изменения в своем спрятанном рабочем дереве, cherry-pick будет корректно обновлять рабочее дерево и индекс, но при сбросе будут отменены все изменения, которые вы уже добавили. к новому индексу. Теперь вы находитесь на территории основного командования,

( index=`git write-tree` &&
  git cherry-pick -nm2 stash &&
  git read-tree $index &&
  git stash drop
)

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

0 голосов
/ 13 мая 2018

Когда дело доходит до git stash push (поскольку вызов git stash без аргументов эквивалентен git stash push), рассмотрите возможность добавления опции --keep-index.

Это означает, что все изменения, уже добавленные в индекс, остаются без изменений.

Таким образом, опция -p (patch) не должна запрашивать эти (уже кэшированные) блоки.

Примечание: опция --patch подразумевает --keep-index, поэтому (для тестирования) убедитесь, что вы используете последнюю доступную версию Git (2.17), и попробуйте git stash push -p.

Если проблема не устранена, то, как было отмечено ранее, выполнение коммита сначала позволит stash -p работать с чистым индексом.
git reset --soft @~ восстановит зафиксированный индекс.

...