Comment nommer et récupérer une cachette par son nom dans git?

1423

J'ai toujours eu l'impression que vous pouviez donner un nom à une cachette en faisant git stash save stashname, que vous pourriez ensuite appliquer en faisant git stash apply stashname. Mais il semble que dans ce cas, tout ce qui se passe est celui stashnamequi sera utilisé comme description de la cachette.

N'y a-t-il aucun moyen de nommer une cachette? Sinon, que recommanderiez-vous pour obtenir des fonctionnalités équivalentes? Essentiellement, j'ai une petite cachette que j'aimerais périodiquement appliquer, mais je ne veux pas toujours avoir à chercher git stash listquel est son numéro de cachette réel.

Suan
la source
68
git stash push -m stashnameest la syntaxe actuelle . git stash save stashnameest obsolète.
SherylHohman
1
git stash push -m stashname ne fonctionne pas dans 2.8.0.windows.1.
Jac
Git pour Windows 2.26.0 est sorti il ​​y a quelques jours. Peut-être que c'est maintenant corrigé. github.com/git-for-windows/git/releases/tag/v2.26.0.windows.1
tom_mai78101

Réponses:

818

Voici comment procéder:

git stash save "my_stash"

"my_stash"est le nom de la cachette.

Quelques choses plus utiles à savoir: Toutes les cachettes sont stockées dans une pile. Type:

git stash list

Cela répertoriera toutes vos réserves.

Pour appliquer une stash et la retirer de la pile de stash, tapez:

git stash pop stash@{n}

Pour appliquer une stash et la conserver dans la pile de stash, tapez:

git stash apply stash@{n}

nest l'indice du changement caché.

Sri Murthy Upadhyayula
la source
88
Cela ne répond pas à la question. Par défaut, vous vous retrouvez avec un tas de chiffres pour votre cachette, mais cela ne répond pas à la façon dont vous pouvez mettre un nom pour l'identifier facilement.
GoodSp33d
16
OP essaie explicitement d'éviter les noms de cachette mal nommés @ {n} pour les noms personnalisés. git stash apply <custom-name>
stewSquared
10
Ne répond pas à la question sur la récupération d'une cachette par son nom.
nullsteph
47
git stash push -m my_stashest la syntaxe actuelle . git stash save my_stashest obsolète.
SherylHohman
21
Ce n'est pas sans importance. C'est utile.
Gayan Weerakutti
444

git stash saveest obsolète à partir de 2.15.x / 2.16, à la place, vous pouvez utilisergit stash push -m "message"

Vous pouvez l'utiliser comme ceci:

git stash push -m "message"

où "message" est votre note pour cette cachette.

Afin de récupérer la planque , vous pouvez utiliser: git stash list. Cela produira une liste comme celle-ci, par exemple:

stash@{0}: On develop: perf-spike
stash@{1}: On develop: node v10

Ensuite, vous utilisez simplement applyen lui donnant stash@{index}:

git stash apply stash@{1}

Références page de manuel de git stash

EssaidiM
la source
9
documents montrant pushplutôt que la savesyntaxe: git stash push
SherylHohman
30
Telle est la vraie réponse. Malheureusement, il y a une tonne d'anciennes réponses au-dessus.
malan
1
Pour en savoir plus sur le plus récent git stash push: stackoverflow.com/a/47231547/6309
VonC
source (sur le dernier document actuel) pour l'avis de dépréciation: git-scm.com/docs/git-stash/2.24.0#Documentation/…
Gabriel Devillers
1
FWIW: Lorsque vous exécutez git stash apply stash@{1}dans Powershell, vous obtiendrez un error: unknown switch 'e'dos. Utilisez plutôt git stash apply --index 1ou git stash apply 'stash@{1}'ou escape }et {avec un backtick `.
LosManos
105

Vous pouvez transformer une cachette en branche si vous pensez qu'elle est suffisamment importante:

git stash branch <branchname> [<stash>]

à partir de la page de manuel:

Cela crée et extrait une nouvelle branche nommée à <branchname>partir de la validation à laquelle le <stash>a été créé à l'origine, applique les modifications enregistrées dans <stash>la nouvelle arborescence de travail et l'index, puis supprime le <stash>si cela se termine avec succès. Si non <stash>est donné, applique le dernier.

Cela est utile si la branche sur laquelle vous avez exécuté git stash savea suffisamment changé pour que git stash apply échoue en raison de conflits. Étant donné que le stash est appliqué au-dessus du commit qui était HEAD au moment où git stash a été exécuté, il restaure l'état initialement stashé sans conflits.

Vous pouvez ultérieurement rebaser cette nouvelle branche vers un autre endroit qui est un descendant de l'endroit où vous vous trouviez lorsque vous vous êtes caché.

Adam Dymitruk
la source
1
Étant donné que les branches sont assez bon marché en git, cette suggestion est très utile pour moi.
Jayan
5
Bien sûr, mais cela n'aide pas si vous souhaitez continuer à réappliquer cette cachette dans différentes branches plus tard, comme le demande l'OP. Vous auriez à choisir sa tête.
stewSquared
@AdamDymitruk Existe-t-il un moyen d'effectuer cela tout en conservant la cachette sans éclater. (comme dans git stash apply)
Kasun Siyambalapitiya
Étrangement, lorsque j'ai essayé cela, j'ai reçu un message d'erreur indiquant qu'un de mes fichiers serait écrasé lors de la vérification et que je devrais valider ou cacher (!) Mes modifications. git stash push -m 'name'travaillé.
wortwart
@AdamDymmitruk réponse incroyable. a soufflé mon esprit.
Dan
77

Si vous cherchez simplement un moyen léger d'enregistrer tout ou partie de vos modifications de copie de travail actuelles, puis de les réappliquer plus tard à volonté, envisagez un fichier de correctif:

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

# re-apply it later
git apply some.patch

De temps en temps, je me demande si je devrais utiliser des cachettes pour cela, puis je vois des choses comme la folie ci-dessus et je me contente de ce que je fais :)

Pat Niemeyer
la source
2
Ça y est ...! Je vous remercie. J'ai également mis à jour mon .gitignore pour ignorer les fichiers .patch et je suis prêt à avoir autant de correctifs que je le souhaite.
LINGS
Je peux voir l'intention derrière la question, qui est d'avoir appliqué des changements locaux chaque fois que vous supprimez une branche de master et ne les validez pas. Donc, peut-être que la question aurait dû être corrigée et cette réponse aurait dû être acceptée comme la solution. Simple aussi.
ank
46

Les cachettes ne sont pas censées être des choses permanentes comme vous le souhaitez. Vous seriez probablement mieux servi en utilisant des balises lors des validations. Construisez la chose que vous voulez cacher. Faites-en un commit. Créez une balise pour ce commit. Faites ensuite reculer votre succursale vers HEAD^. Maintenant, lorsque vous souhaitez réappliquer cette réserve, vous pouvez utiliser git cherry-pick -n tagname( -nest --no-commit).

Lily Ballard
la source
1
Certainement, comme cette approche, se sent un peu plus propre d'avoir juste un named commitendroit quelque part. Le seul inconvénient léger est qu'il n'est pas engagé lors de la sélection et reste dans le diff, ce qui signifie qu'il ne devra pas être enregistré manuellement lors du prochain commit.
Aditya MP
1
C'est le plus proche. Je pense que je vais faire quelques alias pour cela. Je n'aime pas utiliser la description comme "nom".
stewSquared
Dommage que cela ajoute à l'index et que vous devez réinitialiser, quelqu'un devrait patcher une --no-stageoption! Connexe: stackoverflow.com/questions/32333383/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
41

utiliser git stash push -m aNameForYourStashpour l'enregistrer. Utilisez ensuite git stash listpour connaître l' index de la cachette que vous souhaitez appliquer. Ensuite, utilisez git stash pop --index 0pour éclater la cachette et l'appliquer.

remarque: j'utilise git version 2.21.0.windows.1

canbax
la source
1
Votre réponse est nominalement la réponse la mieux notée, en tenant compte de ce commentaire sur la syntaxe actuelle degit stash {push,save}
Michael - Où est Clay Shirky
32

J'ai ces deux fonctions dans mon .zshrcdossier:

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)
}

En les utilisant de cette façon:

gitstash nice

gitstashapply nice
iWheelBuy
la source
Qu'est-ce que "zsh_stash_name_"?
Sam Hasler
1
@SamHasler juste une chaîne unique aléatoire. Dans le cas où vous voulez savoir que la cachette a été créée avec la cachette git régulière ou avec ces fonctions
iWheelBuy
Solution élégante pour les fans d'alias
suarsenegger
22

Et ça?

git stash save stashname
git stash apply stash^{/stashname}
AdamB
la source
1
Cela ressemble à quelque chose comme ça qui était la réponse acceptée, mais a depuis été supprimé.
Michael - Où est Clay Shirky
Hm, alors pourquoi il a été supprimé?
AdamB
Je ne sais pas, car je n'ai pas posté la réponse et je n'ai pas 10 000 points de réputation, mais je suppose que cela a quelque chose à voir avec les commentaires disant que ça ne marche pas: c'est malheureux que git stash apply stash^{/<regex>}ça ne marche pas (ça ne marche pas effectuez une recherche dans la liste cachée, voir les commentaires sous la réponse acceptée ).
Michael - Où est Clay Shirky
c'est LA réponse que vous cherchez!
kiedysktos
1
pour récupérer je vais 1. git stash listqui me montre les cachettes avec leur numéro d'index associé, je vais ensuite 2. git stash apply 0- où 0 est le numéro d'index que j'aurais recherché à partir de la première commande
ambidextre le
8

Alias

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

Usage

git sapply "<regex>"

  • compatible avec Git pour Windows

Edit: je suis resté sur ma solution d'origine, mais je vois pourquoi la majorité préférerait la version d'Etan Reisner (ci-dessus). Donc, pour mémoire:

sapply = "!f() { git stash apply \"$(git stash list | grep -E \"$*\" | awk \"{ print $ 1; }\" | sed -n \"s/://;1p\")\"; }; f"
Vlastimil Ovčáčík
la source
L'utilisation awk -F: '{print $1}'éliminerait complètement le besoin de sed. Aussi pourquoi envelopper cela dans une fonction? Et l'utilisation awk -F: -vpat="$*" '$0 ~ pat {print $1}'devrait également permettre de supprimer le grep. Bien que cela puisse nécessiter des devis légèrement différents pour le modèle.
Etan Reisner
@EtanReisner: votre extrait de code génère plusieurs lignes.
Vlastimil Ovčáčík
Effectuez l'action {print $1; exit}pour quitter après la première ligne correspondante.
Etan Reisner
@EtanReisner: Après quelques tests, j'ai pu me débarrasser du sed, mais le wrapper et le grep restent.
Vlastimil Ovčáčík
Vous n'avez pas besoin de la grep bien que, comme je l'ai dit, la citation de modèle puisse différer sans elle. Je suppose que par wrapper vous voulez dire la fonction shell? Vous n'avez jamais expliqué pourquoi vous pensez que vous en avez besoin, je ne peux donc pas dire si vous en avez réellement besoin, mais je pense que vous n'en avez probablement pas. (Vous devrez peut-être appeler manuellement un shell au lieu de git stash directement, mais peut-être même pas.)
Etan Reisner
8

Il est regrettable que git stash apply stash^{/<regex>}cela ne fonctionne pas (il ne recherche pas réellement la liste cachée, voir les commentaires sous la réponse acceptée ).

Voici des remplaçants sans git stash listrendez-vous qui recherchent par expression régulière pour trouver le premier (le plus récent) stash@{<n>}, puis le transmettent à 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")

Notez que les codes de résultat appropriés sont renvoyés afin que vous puissiez utiliser ces commandes dans d'autres scripts. Cela peut être vérifié après l'exécution de commandes avec:

echo $?

Faites juste attention aux exploits d'expansion variable car je n'étais pas sûr de la --grep=$1portion. Cela devrait peut-être l'être, --grep="$1"mais je ne suis pas sûr que cela interfère avec les délimiteurs d'expressions régulières (je suis ouvert aux suggestions).

Zack Morris
la source
6

Cette réponse doit beaucoup à Klemen Slavič. J'aurais juste commenté la réponse acceptée mais je n'ai pas encore assez de représentants :(

Vous pouvez également ajouter un alias git pour trouver la référence cachée et l'utiliser dans d'autres alias pour afficher, appliquer, supprimer, etc.

[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"

Notez que la raison du ref=$( ... ); echo ${ref:-<no_match>};motif est qu'aucune chaîne vierge n'est renvoyée, ce qui entraînerait sshow, sapply et sdrop à cibler la dernière cachette au lieu d'échouer comme on pourrait s'y attendre.

Nathanael
la source
1
Cela fonctionne pour moi alors que la réponse acceptée ne semble pas fonctionner (voir mon éloge pour la réponse acceptée)
Jan Rüegg
4

Alias Cela pourrait être une syntaxe plus directe pour les systèmes de type Unix sans avoir besoin d'encapsuler dans une fonction. Ajoutez ce qui suit à ~ / .gitconfig sous [alias]

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

Utilisation: regex sapply

Exemple: git sshow MySecretStash

Le tiret à la fin indique prendre l'entrée de l'entrée standard.

Rohanthewiz
la source
4

Utilisez un petit script bash pour rechercher le numéro de la cachette. Appelez ça "gitapply":

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

Usage:

gitapply foo

... où foo est une sous-chaîne du nom de la cachette que vous souhaitez.

Will Sheppard
la source
3

Utilisez git stash save NAMEpour enregistrer.

Ensuite ... vous pouvez utiliser ce script pour choisir lequel appliquer (ou pop):

#!/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

J'aime pouvoir voir les noms des cachettes et choisir. J'utilise également Zshell et je ne savais franchement pas comment utiliser certains des alias Bash ci-dessus;)

Remarque: Comme Kevin le dit, vous devriez plutôt utiliser des balises et des choix de cerise.

Dan Rosenstark
la source
git stash saveest déconseillé en faveur de git stash push.
wranvaud
2

C'est une façon d'y parvenir à l'aide de 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 "stash@{0}"
#>
function Restore-Stash  {
    [CmdletBinding()]
    [Alias("Apply-Stash")]
    PARAM (
        [Parameter(Mandatory=$true)] $message,         
        [switch]$drop
    )

    $stashId = $null

    if ($message -match "stash@{") {
        $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''
    }
}

Plus de détails ici

Geoffrey Hudik
la source
2

dans ma coquille de poisson

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

utilisation

gsap name_of_stash

Matsumoto Kazuya
la source
Oui! Je vous remercie!!!
clozach
1

Tard dans la soirée ici, mais si vous utilisez VSCode, un moyen rapide de le faire est d'ouvrir la palette de commandes (CTRL / CMD + SHIFT + P) et de taper "Pop Stash", vous pourrez récupérer votre stash par nom sans avoir besoin d'utiliser git CLI

Alexandre Gomes
la source
1

git stash applyfonctionne également avec d'autres références que stash@{0}. Vous pouvez donc utiliser des balises ordinaires pour obtenir un nom persistant. Cela a également l'avantage que vous ne pouvez pas accidentellement git stash dropou git stash popcela.

Vous pouvez donc définir un alias pstash(alias "stash persistant") comme ceci:

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

Vous pouvez maintenant créer une cachette balisée:

git pstash x-important-stuff

et showet applyencore , comme d' habitude:

git stash show x-important-stuff
git stash apply x-important-stuff
AH
la source
0

Je ne pense pas qu'il y ait un moyen de faire sauter une cachette par son nom.

J'ai créé une fonction bash qui le fait.

#!/bin/bash

function gstashpop {
  IFS="
"
  [ -z "$1" ] && { echo "provide a stash name"; return; }
  index=$(git stash list | grep -e ': '"$1"'$' | cut -f1 -d:)
  [ "" == "$index" ] && { echo "stash name $1 not found"; return; }
  git stash apply "$index"
}

Exemple d'utilisation:

[~/code/site] on master*
$ git stash push -m"here the stash name"
Saved working directory and index state On master: here the stash name

[~/code/site] on master
$ git stash list
stash@{0}: On master: here the stash name

[~/code/site] on master
$ gstashpop "here the stash name"

J'espère que ça aide!

franzisk
la source
0

Pour tout autre que la création de stash, je proposerais une autre solution en introduisant fzf comme dépendance. Je recommande de prendre 5 minutes de votre temps et de vous y familiariser, car c'est un excellent booster de productivité.

Quoi qu'il en soit, un extrait connexe de leur page d'exemples proposant une recherche cachée. Il est très facile de changer le scriptlet pour ajouter des fonctionnalités supplémentaires (comme l'application stash ou la suppression):

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
}
laur
la source
0

Donc, je ne sais pas pourquoi il y a tant de consternation sur ce sujet. Je peux nommer une cachette git avec à la fois une poussée et la sauvegarde obsolète, et je peux utiliser une expression régulière pour la retirer avec une application:

Méthode Git Stash pour utiliser un nom à appliquer

$ git stash push -m "john-hancock"

$ git stash apply stash^{/john-hancock}

Comme cela a été mentionné précédemment, la commande save est déconseillée, mais elle fonctionne toujours, vous pouvez donc l'utiliser sur des systèmes plus anciens où vous ne pouvez pas les mettre à jour avec un appel push. Contrairement à la commande push, le commutateur -m n'est pas requis avec save.

// save is deprecated but still functional  
$ git stash save john-hancock

Il s'agit de Git 2.2 et de Windows 10.

Preuve visuelle

Voici un beau GIF animé illustrant le processus.

Un GIF animé montrant une cachette Git s'applique en utilisant un nom identifiable.

Séquence d'événements

Le GIF s'exécute rapidement, mais si vous regardez, le processus est le suivant:

  1. La commande ls affiche 4 fichiers dans le répertoire
  2. touch example.html ajoute un 5ème fichier
  3. git stash push -m "john-hancock" -a (Le -a inclut les fichiers non suivis)
  4. La commande ls affiche 4 fichiers après la cachette, ce qui signifie que la cachette et la réinitialisation matérielle implicite ont fonctionné
  5. git stash applique stash ^ {/ john-hancock} s'exécute
  6. La commande ls répertorie 5 fichiers, montrant que le fichier example.html a été ramené, ce qui signifie que la commande git stash apply a fonctionné.

Est-ce même logique?

Pour être franc, je ne sais pas vraiment quel est l'avantage de cette approche. Il est utile de donner un nom à la cachette, mais pas la récupération. Peut-être pour le script du shelve et unshelve processus , il serait utile, mais il est encore plus facile de pop juste une planque par son nom.

$ git stash pop 3
$ git stash apply 3

Cela me semble beaucoup plus facile que l'expression régulière.

Cameron McKenzie
la source