Как назвать и получить тайник по имени в git?

У меня всегда создавалось впечатление, что вы можете указать имя для стаи, выполнив git stash save stashname, который позже вы можете применить, выполнив git stash apply stashname. Но кажется, что в этом случае все, что происходит, это то, что stashname будет использоваться как описание закладок.

Нет ли способа называть кошелек? Если нет, что бы вы рекомендовали достичь эквивалентной функциональности? По сути, у меня есть небольшой тайник, который я бы периодически хотел применить, но не хочу, чтобы всегда нужно было искать в git stash list, каков его фактический номер зашибки.

Ответ 1

Это не то решение, которое вы ищете!

Вам повезет больше, если посмотреть на решения, опубликованные в других ответах, в комментариях ниже:

Я оставляю эту ветку здесь для потомков, так как не могу не принять ответ.


Вы можете найти тайник по имени, используя синтаксис регулярных выражений git для адресации объектов:

stash^{/<regex>}
:/<regex>

Например, при сохранении вашего тайника с именем сохранения:

git stash save "guacamole sauce WIP"

... вы можете использовать регулярное выражение для адресации этого тайника:

git stash apply stash^{/guacamo}

Это применит самый младший тайник, который соответствует регулярному выражению guacamo. Таким образом, вам не нужно знать, какой номер тайника в стеке, вы просто должны знать его имя. Для этого нет более краткого синтаксиса, но вы можете создать псевдоним в своем файле .gitconfig:

[alias]
sshow = "!f() { git stash show stash^{/$*} -p; }; f"
sapply = "!f() { git stash apply stash^{/$*}; }; f"

Затем вы можете использовать git sapply <regex> чтобы применить этот тайник (не опускаясь).
Затем вы можете использовать git sshow <regex> чтобы показать: файлы изменены, вставки и удаления

РЕДАКТИРОВАТЬ: Переходит к fooobar.com/questions/4095/... о том, как использовать аргументы bash в псевдонимах git.

РЕДАКТИРОВАТЬ 2: Этот ответ раньше содержал псевдонимы drop и list, но с тех пор я удалил их, так как drop требует синтаксиса stas[email protected]{n} то время как list вообще не фильтрует stashes. Если кто-нибудь знает, как разрешить хэш-хранилище SHA-1 в ссылочном хранилище, я мог бы реализовать и другие команды.

РЕДАКТИРОВАТЬ 3: В соответствии с предложением я добавил флаг патча, чтобы показать, каково содержимое тайника при его отображении.

Ответ 2

Вот как вы это делаете:

git stash save "my_stash"

Где "my_stash" - это имя "my_stash".

Еще несколько полезных вещей: все тайники хранятся в стеке. Тип:

git stash list

Это перечислит все ваши тайники.

Чтобы применить тайник и удалить его из стека, введите:

git stash pop [email protected]{n}

Чтобы применить тайник и сохранить его в стеке, введите:

git stash apply [email protected]{n}

Где n - индекс сохраненного изменения.

Ответ 3

git stash save устарело с 2.15.x/2.16, вместо этого вы можете использовать git stash push -m "message"

Вы можете использовать это так:

git stash push -m "message"

где "сообщение" - это ваша заметка для этого тайника.

Чтобы получить тайник, вы можете использовать: git stash list. Это выведет такой список, например:

[email protected]{0}: On develop: perf-spike
[email protected]{1}: On develop: node v10

Тогда вы просто используете apply давая ему [email protected]{index}:

git stash apply [email protected]{1}

Справочная страница по git stash

Ответ 4

Вы можете превратить тайник в ветку, если считаете это достаточно важным:

git stash branch <branchname> [<stash>]

со страницы руководства:

Это создает и проверяет новую ветвь с именем <branchname> начиная с коммита, при котором изначально был создан <stash>, применяет изменения, записанные в <stash> к новому рабочему дереву и индексу, а затем удаляет <stash> если это завершается успешно. Когда <stash> не указан, применяется последний.

Это полезно, если ветвь, в которой вы запустили git stash save, изменилась настолько, что git stash не удалось применить из-за конфликтов. Поскольку хранилище применяется поверх коммита, который был HEAD во время запуска git stash, он восстанавливает исходное хранилище без конфликтов.

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

Ответ 5

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

# save your working copy changes
git diff > some.patch

# re-apply it later
git apply some.patch

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

Ответ 6

Штампы не предназначены для постоянных вещей, как вы хотите. Вероятно, вам лучше будет использовать теги на фиксации. Постройте вещь, которую вы хотите зашить. Извлеките фиксацию. Создайте тег для этой фиксации. Затем открутите ветвь до HEAD^. Теперь, когда вы захотите повторно применить этот тайник, вы можете использовать git cherry-pick -n tagname (-n is --no-commit).

Ответ 7

У меня есть две эти функции в моем файле .zshrc:

function gitstash() {
    git stash push -m "zsh_stash_name_$1"
}

function gitstashapply() {
    git stash apply $(git stash list | grep "zsh_stash_name_$1" | cut -d: -f1)
}

Используя их таким образом:

gitstash nice

gitstashapply nice

Ответ 8

Алиас

sapply = "!f() { git stash apply \"$(git stash list | awk -F: --posix -vpat=\"$*\" \"$ 0 ~ pat {print $ 1; exit}\")\"; }; f"

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

git sapply "<regex>"

  • совместим с Git для Windows

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

sapply = "!f() { git stash apply \"$(git stash list | grep -E \"$*\" | awk \"{ print $ 1; }\" | sed -n \"s/://;1p\")\"; }; f"

Ответ 9

К сожалению, git stash apply stash^{/<regex>} не работает (на самом деле он не выполняет поиск в списке тайников, см. Комментарии под принятым ответом).

Вот вставные замены, которые ищут в git stash list помощью регулярных выражений, чтобы найти первый (самый последний) [email protected]{<n>} а затем передают его в git stash <command>:

# standalone (replace <stash_name> with your regex)
(n=$(git stash list --max-count=1 --grep=<stash_name> | cut -f1 -d":") ; if [[ -n "$n" ]] ; then git stash show "$n" ; else echo "Error: No stash matches" ; return 1 ; fi)
(n=$(git stash list --max-count=1 --grep=<stash_name> | cut -f1 -d":") ; if [[ -n "$n" ]] ; then git stash apply "$n" ; else echo "Error: No stash matches" ; return 1 ; fi)
# ~/.gitconfig
[alias]
  sshow = "!f() { n=$(git stash list --max-count=1 --grep=$1 | cut -f1 -d":") ; if [[ -n "$n" ]] ; then git stash show "$n" ; else echo "Error: No stash matches $1" ; return 1 ; fi }; f"
  sapply = "!f() { n=$(git stash list --max-count=1 --grep=$1 | cut -f1 -d":") ; if [[ -n "$n" ]] ; then git stash apply "$n" ; else echo "Error: No stash matches $1" ; return 1 ; fi }; f"

# usage:

$ git sshow my_stash
 myfile.txt | 1 +
 1 file changed, 1 insertion(+)

$ git sapply my_stash
On branch master
Your branch is up to date with 'origin/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:   myfile.txt

no changes added to commit (use "git add" and/or "git commit -a")

Обратите внимание, что возвращаются правильные коды результатов, поэтому вы можете использовать эти команды в других сценариях. Это можно проверить после запуска команд с:

echo $?

Просто будьте осторожны с эксплойтами расширения переменных, потому что я не был уверен в части --grep=$1. Возможно, это должно быть --grep="$1" но я не уверен, что это помешает разделителям регулярных выражений (я открыт для предложений).

Ответ 10

Этот ответ многим обязан Клемену Славичу. Я бы только прокомментировал принятый ответ, но мне пока не хватает представителя :(

Вы также можете добавить псевдоним git, чтобы найти ссылку на stash и использовать ее в других псевдонимах для show, apply, drop и т.д.

[alias]
    sgrep = "!f() { ref=$(git --no-pager stash list | grep "$1" | cut -d: -f1 | head -n1); echo ${ref:-<no_match>}; }; f"
    sshow = "!f() { git stash show $(git sgrep "$1") -p; }; f"
    sapply = "!f() { git stash apply $(git sgrep "$1"); }; f"
    sdrop = "!f() { git stash drop $(git sgrep "$1"); }; f"

Обратите внимание, что причина для ref=$(... ); echo ${ref:-<no_match>}; ref=$(... ); echo ${ref:-<no_match>}; шаблон так пустая строка не возвращается, что приведет к тому, что sshow, sapply и sdrop нацелятся на последний тайник вместо сбоя, как и следовало ожидать.

Ответ 11

Алиас Это может быть более прямой синтаксис для Unix-подобных систем без необходимости инкапсуляции в функцию. Добавьте в ~/.gitconfig следующее: [alias]

sshow = !sh -c 'git stash show stash^{/$*} -p' -
sapply = !sh -c 'git stash apply stash^{/$*}' -
ssave = !sh -c 'git stash save "${1}"' -

Использование:   регулярное выражение sapply

Пример:   git sshow MySecretStash

Дефис в конце говорит о вводе ввода со стандартного ввода.

Ответ 12

Используйте маленький скрипт bash, чтобы найти номер тайника. Назовите это "gitapply":

NAME="$1"
if [[ -z "$NAME" ]]; then echo "usage: gitapply [name]"; exit; fi
git stash apply $(git stash list | grep "$NAME" | cut -d: -f1)

Использование:

gitapply foo

... где foo является подстрокой имени тайника, который вы хотите.

Ответ 13

Как насчет этого?

git stash save stashname
git stash apply stash^{/stashname}

Ответ 14

используйте git stash push -m aNameForYourStash, чтобы сохранить его. Затем используйте git stash list, чтобы узнать индекс stashа, который вы хотите применить. Затем используйте git stash pop --index 0, чтобы открыть stash и применить его.

примечание: я использую git версии 2.21.0.windows.1

Ответ 15

Используйте git stash save NAME для сохранения.

Затем... вы можете использовать этот script для выбора, который нужно применить (или поп):

#!/usr/bin/env ruby
#git-stash-pick by Dan Rosenstark

# can take a command, default is apply
command = ARGV[0]
command = "apply" if !command
ARGV.clear

stashes = []
stashNames = []
`git stash list`.split("\n").each_with_index { |line, index|
    lineSplit = line.split(": ");
    puts "#{index+1}. #{lineSplit[2]}"
    stashes[index] = lineSplit[0]
    stashNames[index] = lineSplit[2]
}
print "Choose Stash or ENTER to exit: "
input = gets.chomp
if input.to_i.to_s == input
    realIndex = input.to_i - 1
    puts "\n\nDoing #{command} to #{stashNames[realIndex]}\n\n"
    puts `git stash #{command} #{stashes[realIndex]}`
end

Мне нравится, когда я могу видеть имена кошельков и выбирать. Также я использую Zshell и откровенно не знаю, как использовать некоторые из Bash псевдонимов выше;)

Примечание. Как говорит Кевин, вместо этого вы должны использовать теги и вишневые подборки.

Ответ 16

Это один из способов добиться этого с помощью PowerShell:

<#
.SYNOPSIS
Restores (applies) a previously saved stash based on full or partial stash name.

.DESCRIPTION
Restores (applies) a previously saved stash based on full or partial stash name and then optionally drops the stash. Can be used regardless of whether "git stash save" was done or just "git stash". If no stash matches a message is given. If multiple stashes match a message is given along with matching stash info.

.PARAMETER message
A full or partial stash message name (see right side output of "git stash list"). Can also be "@stash{N}" where N is 0 based stash index.

.PARAMETER drop
If -drop is specified, the matching stash is dropped after being applied.

.EXAMPLE
Restore-Stash "Readme change"
Apply-Stash MyStashName
Apply-Stash MyStashName -drop
Apply-Stash "[email protected]{0}"
#>
function Restore-Stash  {
    [CmdletBinding()]
    [Alias("Apply-Stash")]
    PARAM (
        [Parameter(Mandatory=$true)] $message,         
        [switch]$drop
    )

    $stashId = $null

    if ($message -match "[email protected]{") {
        $stashId = $message
    }

    if (!$stashId) {
        $matches = git stash list | Where-Object { $_ -match $message }

        if (!$matches) {
            Write-Warning "No stashes found with message matching '$message' - check git stash list"
            return
        }

        if ($matches.Count -gt 1) {
            Write-Warning "Found $($matches.Count) matches for '$message'. Refine message or pass 'stash{@N}' to this function or git stash apply"
            return $matches
        }

        $parts = $matches -split ':'
        $stashId = $parts[0]
    }

    git stash apply ''$stashId''

    if ($drop) {
        git stash drop ''$stashId''
    }
}

Подробнее здесь

Ответ 17

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

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

fstash() {
    local out q k sha
    while out=$(
            git stash list --pretty="%C(yellow)%h %>(14)%Cgreen%cr %C(blue)%gs" |
            fzf --ansi --no-sort --query="$q" --print-query \
                --expect=ctrl-d,ctrl-b); do
        mapfile -t out <<< "$out"
        q="${out[0]}"
        k="${out[1]}"
        sha="${out[-1]}"
        sha="${sha%% *}"
        [[ -z "$sha" ]] && continue
        if [[ "$k" == 'ctrl-d' ]]; then
            git diff $sha
        elif [[ "$k" == 'ctrl-b' ]]; then
            git stash branch "stash-$sha" $sha
            break;
        else
            git stash show -p $sha
        fi
    done
}

Ответ 18

Здесь поздно вечером, но если вы используете VSCode, быстрый способ сделать это - открыть палитру команд (CTRL/CMD + SHIFT + P) и набрать "Pop Stash", вы сможете получить свой тайник по имени без необходимости использовать git CLI

Ответ 19

в моей рыбной раковине

function gsap
  git stash list | grep ": $argv" | tr -dc '0-9' | xargs git stash apply
end

использование

gsap name_of_stash

Ответ 20

git stash apply также работает с другими ссылками, кроме [email protected]{0}. Таким образом, вы можете использовать обычные теги, чтобы получить постоянное имя. Это также имеет то преимущество, что вы не можете случайно git stash drop git stash pop или git stash pop.

Таким образом, вы можете определить псевдоним pstash (он же "постоянный stash") следующим образом:

git config --global alias.pstash '!f(){ git stash && git tag "$1" stash && git stash drop; }; f'

Теперь вы можете создать помеченный тайник:

git pstash x-important-stuff

и show и apply это снова как обычно:

git stash show x-important-stuff
git stash apply x-important-stuff