Как я могу переименовать git stash?

203

У меня есть тайник с неправильным именем. Я хотел бы исправить имя, чтобы оно было точным.

Как я могу переименовать тайник?

mikemaccana
источник
5
всплыть и сохранить его снова под другим именем?
Бартломей Левандовски,
5
Повторная загрузка и сохранение не всегда возможны, поскольку тайник может основываться на устаревшем состоянии и приводить к конфликтам при получении. (Устаревшее государство больше не должно существовать нигде в истории.)
Том

Ответы:

259

Давайте предположим, что ваш список тайников выглядит так:

$ git stash list
stash@{0}: WIP on master: Add some very important feature 
stash@{1}: WIP on master: Fix some silly bug

Во-первых, вы должны удалить запись stash, которую хотите переименовать:

$ git stash drop stash@{1}
Dropped stash@{1} (af8fdeee49a03d1b4609f294635e7f0d622e03db)

Теперь просто добавьте его снова с новым сообщением, используя sha commit, возвращенный после удаления:

$ git stash store -m "Very descriptive message" af8fdeee49a03d1b4609f294635e7f0d622e03db

И это все:

$ git stash list
stash@{0}: Very descriptive message
stash@{1}: WIP on master: Add some very important feature

Это решение требует git 1.8.4 или новее, и да, оно работает и с грязным рабочим каталогом.

QZB
источник
3
git show stash@{0}все еще показывает старую информацию потом. Как это исправить? (Обратите внимание, что тайник получает другой SHA.)
Tino
4
Чувствуется лучше получить хэш git showи начать с git stash store. Тогда вместе с git stash listвами увидите старый и новый тайник. Наконец вы можете очистить старый тайник с помощью git stash drop.
хоги
6
Git Stash Drop не потеряет изменения?
Шравья Боггарапу
4
@ShravyaBoggarapu, нет, git не удаляет коммит до git gcзапуска. После stash dropтого, как вы можете легко найти этот обычно недоступный коммит, используя git fsck | grep commitкоманду.
qzb
2
@ ÐerÆndi простое применение и сохранение - это простой вариант, но он не работает, когда изменения не могут быть применены повторно из-за конфликтов. Тем временем сбрасывание и хранение работ при любых обстоятельствах. Я еще раз протестировал свое решение - оно отлично работает на последней версии git (2.17.0).
qzb
62

Если вы не делаете это вручную или не вносите улучшения в Git, вы можете использовать псевдоним:

git config --global alias.stash-rename '!_() { rev=$(git rev-parse $1) && git stash drop $1 || exit 1 ; git diff-index --quiet HEAD; s=$?; [ $s != 0 ] && git stash save "tmp stash from stash-rename"; git stash apply $rev && shift && git stash save "$@" && [ $s != 0 ] && git stash pop stash@{1}; }; _'

Использование: " git stash-rename <stash> [save options] [<message>]"

С [save options]любой опцией git stash save:[-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [-u|--include-untracked] [-a|--all]

Пример:

$ git stash list
stash@{0}: On master: Pep8 format
stash@{1}: On master: co other than master with local changes
stash@{2}: On master: tests with deployAtEnd

# Let's say I want to rename the stash@{2} adding an issue reference:
$ git stash-rename stash@{2} NXP-13971-deployAtEnd

$ git stash list
stash@{0}: On master: NXP-13971-deployAtEnd
stash@{1}: On master: Pep8 format
stash@{2}: On master: co other than master with local changes

Это будет работать, даже если у вас есть локальные неустановленные изменения :)

РЕДАКТИРОВАТЬ 2016/02/22

Упрощенный скрипт, кредиты на qzb , https://stackoverflow.com/a/35549615/515973

git config --global alias.stash-rename '!_() { rev=$(git rev-parse $1) && git stash drop $1 || exit 1 ; git stash store -m "$2" $rev; }; _'

Использование: " git stash-rename <stash> [<message>]"

Жюльен Карсик
источник
1
Потрясающие! Еще круче, если бы вы могли это сделатьgit stash-rename 'tests with deployAtEnd' 'NXP-13971-deployAtEnd'
mikemaccana
3
поэтому ответ 1) очистить рабочую копию, 2) применить тайник, который вы хотите переименовать, 3) удалить его из списка, 4) создать новый тайник с правильным сообщением.
ГКБ
2
Чтобы уточнить, вы переименовываете последний тайник, и после такого действия он становится верхним тайником?
2015 в 15:05
2
Я удаляю тайник для переименования, сохраняю текущие изменения, если таковые имеются, воссоздаю удаленный тайник с требуемым именем, повторно применяю текущие изменения, если таковые имеются.
Жюльен Карсик
3
Эта версия проверяет, чтобы убедиться, что оба аргумента присутствуют, поэтому она не просто случайно удаляет ваш последний тайник. Также требуется только номер тайника, а не вся stash@{0}ссылка. gist.github.com/jdforsythe/f248bf6c72fc020225cc3e315a32e922 git config --global alias.stash-rename '!_() { if [ -z \"$1\" ] || [ -z \"$2\" ]; then echo \"git stash-rename 0 NewName\" && echo \"\" && git stash list && exit 1; else stash=\"stash@{$1}\"; rev=$(git rev-parse \"${stash}\"); git stash drop \"${stash}\" || exit 1; git stash store -m \"$2\" \"$rev\" || exit 1; git stash list; fi }; _'
jdforsythe
6

Это очень просто. Во-первых, отмените последний тайник с:

git stash pop

После этого вы можете сохранить тайник с настроенным именем следующим образом:

git stash save "your explanatory name"

Я надеюсь, что это полезно для вас. :)

Sandra
источник
Переименованный тайник может быть не самым последним.
mikemaccana
Так как это более просто (ТОЛЬКО) для самого последнего тайника.
Кайхуа
3

Я не думаю, что это возможно. Было предложение переименовать тайник, но оно еще не было реализовано.

Моя общая идея:

  1. git reflog updateРеализуйте новую команду, которая обновляет сообщение, связанное с определенной записью reflog. Для этого новая update_reflog_ent()функция (в reflog.c ) будет изменять сообщение, связанное с конкретной записью reflog, для обновления. update_reflog()Функция будет использовать for_each_reflog_ent()с update_reflog_entфактически делать изменения.

  2. git stash renameКоманда только тогда нужна будет звонить git reflog updateс соответствующими исм и новым сообщением.

Или вы могли бы, конечно, открыть тайник и сделать git stash save [message]

A1ternat1ve
источник
3

Для удобства читателя, это расширение принятого и правильного ответа .

Если вы не только хотите исправить сообщение о тайнике, но также хотите исправить сообщение о фиксации тайника, чтобы

git stash list

и

git log --oneline -1 stash

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

Чтобы быть в состоянии сделать это, git commit --amendвы должны быть на СОВЕТЕ филиала. Следовательно, решение:

git checkout -b scratch stash@{1}
git stash drop stash@{1}
git commit --amend -m "$MESSAGE"
git stash store -m "$MESSAGE" HEAD
git checkout master
git branch -D scratch

Разъяснение:

  • Создайте новую (еще не существующую) ветку «нуля» из «рассматриваемого тайника» и переключитесь на нее
  • Удалите старый тайник. Это безопасно, так как у нас все еще есть это на ветке.
  • Используйте, git commit --amendчтобы заменить сообщение коммита, это изменяет SHA "тайника в вопросе"
  • Храните тайник, основываясь на ответе qzb
  • Вернитесь назад (что предполагает, что вы пришли от «мастера») и очистите

Недостатки:

  • Это временно переключает ветви. Так что этот рецепт можно применять только тогда, когда git status --porcelainон чистый (читай: ничего не выводится)

  • Он перенумеровывает тайники, поэтому измененный тайник становится stash@{0}

  • Вы должны войти в $MESSAGEдва раза или использовать некоторую переменную окружения (в примере: MESSAGE)

  • Вам нужно найти неиспользуемое название ветки

Есть способы сделать это без переключения веток, но это выходит за рамки этого ответа.

пример

git init scratch
cd scratch
for a in A B C D; do date >$a; git add $a; git commit -m $a; done
for a in X Y; do echo $a > Z; git stash save --all; done
git log --oneline --graph --decorate --all; git stash list

Вывод

*-.   e0e281b (refs/stash) WIP on master: 8bdcc32 D
|\ \  
| | * 4d62f52 untracked files on master: 8bdcc32 D
| * 096f158 index on master: 8bdcc32 D
|/  
* 8bdcc32 (HEAD, master) D
* c84c659 C
* 49bb2da B
* b1852c6 A
stash@{0}: WIP on master: 8bdcc32 D
stash@{1}: WIP on master: 8bdcc32 D

Теперь без изменения фиксации (обратите внимание: SHA в следующем будет отличаться на вашей стороне):

git stash drop stash@{1}
git stash store -m ...changed... 2fbf9007dfdfb95ae269a19e13b8b9ca3e24181c
git log --oneline --graph --decorate --all; git stash list

Вывод

*-.   2fbf900 (refs/stash) WIP on master: 8bdcc32 D
|\ \  
| | * 246dc5c untracked files on master: 8bdcc32 D
| * 80c5ea0 index on master: 8bdcc32 D
|/  
* 8bdcc32 (HEAD, master) D
* c84c659 C
* 49bb2da B
* b1852c6 A
stash@{0}: ...changed...
stash@{1}: WIP on master: 8bdcc32 D

Как видите, по- stash@{0}прежнему отображается как 2fbf900 (refs/stash) WIP on master: 8bdcc32 Dв git log. Если вы посмотрите внимательно, вы увидите, что несколько коммитов изменили SHA. Это связано с тем, как обрабатываются тайники (родители входят в SHA, а тайники имеют свои тайники как родительские).

Исправьте это:

git checkout -b scratch stash
git stash drop
git commit --amend -m ...changed...
git stash store -m ...changed... HEAD
git checkout master
git branch -D scratch
git log --oneline --graph --decorate --all; git stash list

Вывод

*-.   4d55186 (refs/stash) ...changed...
|\ \  
| | * 246dc5c untracked files on master: 8bdcc32 D
| * 80c5ea0 index on master: 8bdcc32 D
|/  
* 8bdcc32 (HEAD, master) D
* c84c659 C
* 49bb2da B
* b1852c6 A
stash@{0}: ...changed...
stash@{1}: WIP on master: 8bdcc32 D

Как вы также видите, refs/stashизменился SHA тоже.

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

Вот модифицированная версия псевдонима Жюльена, которая позволяет вам правильно работать с On <branch>префиксом, обычно добавляемым к имени тайника:

git config --global alias.stash-rename '!_() { newmsg="$1" && stash=${2:-"stash@{0}"} && newbranch="$3" && sha=$(git rev-parse "$stash") && olddesc="$(git stash list --format=%gs -1 "$stash")" && newdesc="$(if [[ "$newbranch" = "." ]]; then echo "$newmsg"; else if [[ -n "$newbranch" ]]; then echo "On $newbranch: $newmsg"; else if [[ "$olddesc" =~ ":" ]]; then echo "$(echo "$olddesc" | cut -f1 -d":"): $newmsg"; else echo "$newmsg"; fi; fi; fi)" && git stash drop "$stash" > /dev/null || exit 1; git stash store -m "$newdesc" "$sha" && git stash list; }; _'

Синтаксис:

git stash-rename <new-name> [<stash> [<new-branch-name> | .]]

Пример использования:

repo[master] % touch tmp && git add tmp && git stash save first
Saved working directory and index state On master: first
HEAD is now at bd62064 Initial commit
repo[master] % touch tmp && git add tmp && git stash save second
Saved working directory and index state On master: second
HEAD is now at bd62064 Initial commit
repo[master] % git stash list
stash@{0}: On master: second
stash@{1}: On master: first
repo[master] % git stash-rename renamed
stash@{0}: On master: renamed
stash@{1}: On master: first
repo[master] % git stash-rename also-renamed stash@{1}
stash@{0}: On master: also-renamed
stash@{1}: On master: renamed
repo[master] % git stash-rename branch-changed stash@{0} new-branch
stash@{0}: On new-branch: branch-changed
stash@{1}: On master: renamed
repo[master] % git stash-rename branch-name-persists
stash@{0}: On new-branch: branch-name-persists
stash@{1}: On master: renamed
repo[master] % git stash-rename no-branch stash@{0} .
stash@{0}: no-branch
stash@{1}: On master: renamed
repo[master] % git stash-rename renamed
stash@{0}: renamed
stash@{1}: On master: renamed
repo[master] % git stash-rename readd-branch stash@{0} develop
stash@{0}: On develop: readd-branch
stash@{1}: On master: renamed

Большая часть команды предназначена для разбора аргументов и выяснения того, что следует сделать с именем ветви. Используемые gitинструменты следующие:

  • git rev-parse <stash> найти ША тайника.
  • git stash list --format=%gs -1 <stash>найти рефлог предмет тайника . Обратите внимание, что это отличается от сообщения фиксации тайника, которое не изменяется этой командой. Тема reflog - это то, что отображается в git stash list, и вы можете изменить тему reflog, не изменяя хеши коммитов, связанных с тайниками. Однако вы всегда можете найти исходное сообщение о коммите, поэтому не используйте его git stash-renameдля удаления конфиденциальной информации!
  • git stash drop <stash>удалить старую ссылку на тайник (но у нас все еще есть SHA, поэтому он не потерян).
  • git stash store -m <new-message> <sha>сохранить новую ссылку на тайник с той же информацией о фиксации, но с другой темой reflog .
  • git stash listперечислить тайники после завершения операции. Обратите внимание, что новые тайники всегда помещаются в начало списка. Было бы необходимо повторно подтолкнуть все тайники перед интересующим тайником, чтобы восстановить свое первоначальное положение.
Радон Росборо
источник
0

Самый простой способ: вытолкнуть свой тайник с помощью git stash pop, затем сохранить его снова с помощью git stash save your-name

Йоэль Нейман
источник
Переименованный тайник может быть не самым последним.
mikemaccana