¿Cómo nombrar y recuperar un alijo por nombre en git?

1423

Siempre tuve la impresión de que podrías darle un nombre a un alijo haciendo git stash save stashname, que luego podrías aplicar haciendogit stash apply stashname . Pero parece que en este caso todo lo que sucede es que stashnamese usará como la descripción del alijo.

¿No hay forma de nombrar realmente un alijo? Si no, ¿qué recomendaría para lograr una funcionalidad equivalente? Esencialmente tengo un pequeño alijo que periódicamente me gustaría aplicar, pero no quiero tener que buscar siempre git stash listcuál es su número real de alijo.

Suan
fuente
68
git stash push -m stashnamees la sintaxis actual . git stash save stashnameha quedado en desuso
SherylHohman
1
git stash push -m stashname no funciona en 2.8.0.windows.1.
Jac
Git para Windows 2.26.0 se lanzó hace unos días. Tal vez ahora está arreglado. github.com/git-for-windows/git/releases/tag/v2.26.0.windows.1
tom_mai78101

Respuestas:

818

Así es como lo haces:

git stash save "my_stash"

¿Dónde "my_stash"está el nombre del alijo?

Algunas cosas más útiles para saber: todas las reservas se almacenan en una pila. Tipo:

git stash list

Esto mostrará una lista de todos tus escondites.

Para aplicar un alijo y eliminarlo de la pila de alijo, escriba:

git stash pop stash@{n}

Para aplicar un alijo y mantenerlo en la pila de alijo, escriba:

git stash apply stash@{n}

¿Dónde nestá el índice del cambio oculto?

Sri Murthy Upadhyayula
fuente
88
Esto no responde la pregunta. De forma predeterminada, terminas con un montón de números para tu alijo, pero esto no responde cómo puedes poner un nombre para identificarlo fácilmente.
GoodSp33d
16
OP está tratando explícitamente de evitar los nombres stash @ {n} para nombre personalizado. git stash apply <custom-name>
stewSquared
10
No responde la pregunta sobre cómo recuperar un alijo por nombre.
nullsteph
47
git stash push -m my_stashes la sintaxis actual . git stash save my_stashha quedado en desuso
SherylHohman
21
No es irrelevante. Es útil.
Gayan Weerakutti
444

git stash saveestá en desuso a partir de 2.15.x / 2.16, en su lugar puede usargit stash push -m "message"

Puedes usarlo así:

git stash push -m "message"

donde "mensaje" es su nota para ese alijo.

Con el fin de recuperar el alijo puede utilizar: git stash list. Esto generará una lista como esta, por ejemplo:

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

Entonces simplemente usas applydándole el stash@{index}:

git stash apply stash@{1}

Referencias git stash man page

EssaidiM
fuente
99
documentos que muestran en pushlugar de savesintaxis: git stash push
SherylHohman
30
Esta es la verdadera respuesta. Desafortunadamente, hay un montón de respuestas antiguas por encima.
malan
1
Para más información sobre las git stash push
novedades
fuente (en el último documento actual) para el aviso de desaprobación: git-scm.com/docs/git-stash/2.24.0#Documentation/…
Gabriel Devillers
1
FWIW: Cuando se ejecuta git stash apply stash@{1}en Powershell, obtendrá un error: unknown switch 'e'respaldo. En su lugar, use git stash apply --index 1o git stash apply 'stash@{1}'o escape }y {con una marca de retroceso '.
LosManos
105

Puedes convertir un alijo en una rama si crees que es lo suficientemente importante:

git stash branch <branchname> [<stash>]

de la página del manual:

Esto crea y desprotege una nueva rama llamada a <branchname>partir de la confirmación en la que <stash>se creó originalmente, aplica los cambios registrados en <stash>el nuevo árbol de trabajo e índice, luego descarta <stash>si se completa con éxito. Cuando no <stash>se da, se aplica el último.

Esto es útil si la rama en la que ejecutó git stash saveha cambiado lo suficiente como para que la aplicación git stash falle debido a conflictos. Dado que el alijo se aplica encima del commit que era HEAD en el momento en que se ejecutó git stash, restaura el estado escondido originalmente sin conflictos.

Más tarde, puede cambiar la base de esta nueva rama a otro lugar que sea un descendiente de donde estaba cuando se escondió.

Adam Dymitruk
fuente
1
Dado que las ramas son bastante baratas en git, esta sugerencia es muy útil para mí.
Jayan
55
Claro, pero esto no ayuda si desea volver a aplicar este alijo en diferentes ramas más adelante, como lo pregunta el OP. Tendrías que elegir su cabeza.
stewSquared
@AdamDymitruk ¿Hay alguna forma de realizar esto mientras se mantiene el alijo sin aparecer? (como en git stash apply)
Kasun Siyambalapitiya
Curiosamente, cuando probé esto, recibí un mensaje de error que indicaba que uno de mis archivos se sobrescribiría al momento de pagar y que debería confirmar o ocultar (!) Mis cambios. git stash push -m 'name'trabajó.
wortwart
@AdamDymmitruk respuesta increíble. me voló la cabeza.
Dan
77

Si solo está buscando una forma liviana de guardar algunos o todos los cambios actuales de su copia de trabajo y luego volver a aplicarlos a voluntad, considere un archivo de parche:

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

# re-apply it later
git apply some.patch

De vez en cuando me pregunto si debería usar escondites para esto y luego veo cosas como la locura anterior y estoy contento con lo que estoy haciendo :)

Pat Niemeyer
fuente
2
¡Eso es todo! Gracias. También he actualizado mi .gitignore para ignorar los archivos .patch y estoy listo para tener tantos parches como quiera.
LINGS
Puedo ver la intención detrás de la pregunta, que consiste en aplicar algunos cambios locales cada vez que eliminas una rama del maestro y no los confirmas. Entonces, quizás la pregunta debería haberse corregido y esta respuesta debería haberse aceptado como la solución. Simple también.
ANK
46

Los escondites no están destinados a ser cosas permanentes como quieres. Probablemente te sirva mejor usar etiquetas en commits. Construye lo que quieres esconder. Haz un compromiso con eso. Crea una etiqueta para ese commit. Luego, retrocede tu rama hacia HEAD^. Ahora, cuando quieras volver a aplicar ese alijo, puedes usarlo git cherry-pick -n tagname( -nes --no-commit).

Lily Ballard
fuente
1
Definitivamente, como este enfoque, se siente un poco más limpio simplemente named commitpasar el rato en algún lugar. La única molestia leve es que no se compromete con la selección de cereza y se mantiene en el diferencial, lo que significa que será necesario que no se registre manualmente durante la próxima confirmación.
Aditya MP
1
Este es el más cercano. Creo que haré algunos alias para esto. No me gusta usar la descripción como un "nombre".
stewSquared
Es una pena que se agregue al índice y tienes que reiniciar, ¡alguien debería parchear una --no-stageopción! Relacionado: stackoverflow.com/questions/32333383/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
41

use git stash push -m aNameForYourStashpara guardarlo. Luego, use git stash listpara aprender el índice del alijo que desea aplicar. Luego use git stash pop --index 0para reventar el alijo y aplicarlo.

nota: estoy usando git versión 2.21.0.windows.1

Canbax
fuente
1
Su respuesta es nominalmente cuál sería la respuesta mejor calificada, teniendo en cuenta este comentario sobre la sintaxis actual degit stash {push,save}
Michael - Where's Clay Shirky
32

Tengo estas dos funciones en mi .zshrcarchivo:

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

Usándolos de esta manera:

gitstash nice

gitstashapply nice
iWheelBuy
fuente
¿Qué es "zsh_stash_name_"?
Sam Hasler
1
@SamHasler solo una cadena única aleatoria. En caso de que desee saber que el alijo se creó con el alijo git regular o con estas funciones
iWheelBuy
Solución elegante para fanáticos de alias
suarsenegger
22

¿Qué hay de esto?

git stash save stashname
git stash apply stash^{/stashname}
AdamB
fuente
1
Que suena como algo así como que solía ser la respuesta aceptada, pero desde entonces ha sido eliminado.
Michael - ¿Dónde está Clay Shirky?
Hm, entonces ¿por qué fue eliminado?
AdamB
No lo sé, ya que no publiqué la respuesta y no tengo 10,000 reputación, pero supongo que tiene algo que ver con los comentarios que dicen que no funciona: es desafortunado que git stash apply stash^{/<regex>}no funcione (no Realmente busque en la lista oculta, vea los comentarios debajo de la respuesta aceptada ).
Michael - ¿Dónde está Clay Shirky?
¡Esta es LA respuesta que estás buscando!
kiedysktos
1
para recuperarlo voy 1. git stash listque me muestra los escondites junto con su número de índice asociado, luego voy a 2. git stash apply 0- donde 0 es el número de índice que habría buscado desde el primer comando
ambidiestro
8

Alias

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

Uso

git sapply "<regex>"

  • compatible con Git para Windows

Editar: Me quedé con mi solución original, pero veo por qué la mayoría preferiría la versión de Etan Reisner (arriba). Tan solo para el registro:

sapply = "!f() { git stash apply \"$(git stash list | grep -E \"$*\" | awk \"{ print $ 1; }\" | sed -n \"s/://;1p\")\"; }; f"
Vlastimil Ovčáčík
fuente
El uso awk -F: '{print $1}'eliminaría por completo la necesidad de sed. Además, ¿por qué envolver esto en una función? Y el uso también awk -F: -vpat="$*" '$0 ~ pat {print $1}'debería permitir soltar el grep. Aunque podría requerir citas ligeramente diferentes para el patrón.
Etan Reisner
@EtanReisner: su fragmento genera más de una línea.
Vlastimil Ovčáčík
Realice la acción {print $1; exit}para salir después de la primera línea coincidente.
Etan Reisner
@EtanReisner: Después de algunas pruebas pude deshacerme del sed, pero el envoltorio y el grep se quedan.
Vlastimil Ovčáčík
No necesita el grep, aunque como dije, la cita del patrón podría diferir sin él. Supongo que por envoltura te refieres a la función de shell. Nunca explicaste por qué crees que necesitas eso, así que no puedo comentar si realmente lo haces, pero creo que es muy probable que no lo hagas. (Es posible que necesite invocar manualmente un shell en lugar de git stash directamente, pero posiblemente ni siquiera eso).
Etan Reisner
8

Es lamentable que git stash apply stash^{/<regex>}no funcione (en realidad no busca en la lista de alijo, vea los comentarios debajo de la respuesta aceptada ).

Aquí hay reemplazos git stash listdirectos que buscan por expresiones regulares para encontrar el primero (el más reciente) stash@{<n>}y luego pasarlo a 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")

Tenga en cuenta que se devuelven los códigos de resultado adecuados para que pueda usar estos comandos dentro de otros scripts. Esto se puede verificar después de ejecutar comandos con:

echo $?

Solo tenga cuidado con los exploits de expansión variable porque no estaba seguro de la --grep=$1porción. Tal vez debería ser, --grep="$1"pero no estoy seguro de si eso interferiría con los delimitadores de expresiones regulares (estoy abierto a sugerencias).

Zack Morris
fuente
6

Esta respuesta le debe mucho a Klemen Slavič. Hubiera comentado la respuesta aceptada pero todavía no tengo suficiente representante :(

También puede agregar un alias de git para encontrar la referencia de alijo y usarlo en otros alias para mostrar, aplicar, soltar, 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"

Tenga en cuenta que la razón del ref=$( ... ); echo ${ref:-<no_match>};patrón es que no se devuelve una cadena en blanco, lo que provocaría que sshow, sapply y sdrop apunten al último alijo en lugar de fallar como cabría esperar.

Natanael
fuente
1
Esto funciona para mí mientras que la respuesta aceptada no parece funcionar (vea mi recomendación sobre la respuesta aceptada)
Jan Rüegg
4

Alias Esta podría ser una sintaxis más directa para sistemas tipo Unix sin necesidad de encapsular en una función. Agregue lo siguiente a ~ / .gitconfig en [alias]

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

Uso: sapply regex

Ejemplo: git sshow MySecretStash

El guión al final dice tomar entrada de entrada estándar.

Rohanthewiz
fuente
4

Use un pequeño script bash para buscar el número de alijo. Llámalo "gitapply":

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

Uso:

gitapply foo

... donde foo es una subcadena del nombre del alijo que deseas.

Will Sheppard
fuente
3

Use git stash save NAMEpara guardar.

Entonces ... puede usar este script para elegir cuál aplicar (o 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

Me gusta poder ver los nombres de los escondites y elegir. También uso Zshell y, francamente, no sabía cómo usar algunos de los alias Bash anteriores;)

Nota: Como dice Kevin, debes usar etiquetas y selecciones de cereza.

Dan Rosenstark
fuente
git stash saveestá en desuso a favor de git stash push.
wranvaud
2

Esta es una forma de lograr esto usando 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''
    }
}

Más detalles aquí

Geoffrey Hudik
fuente
2

en mi concha de pescado

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

utilizar

gsap name_of_stash

Matsumoto Kazuya
fuente
¡Si! ¡¡¡Gracias!!!
clozach
1

Tarde para la fiesta aquí, pero si usa VSCode, una forma rápida de hacerlo es abrir la paleta de comandos (CTRL / CMD + SHIFT + P) y escribir "Pop Stash", podrá recuperar su alijo por nombre sin la necesidad de usar git CLI

Alexandre Gomes
fuente
1

git stash applyTambién funciona con otras referencias que stash@{0}. Por lo tanto, puede usar etiquetas comunes para obtener un nombre persistente. Esto también tiene la ventaja de que no se puede accidentalmente git stash dropo git stash popella.

Entonces puede definir un alias pstash(también conocido como "alijo persistente") como este:

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

Ahora puede crear un alijo etiquetado:

git pstash x-important-stuff

y showy applyotra vez como de costumbre:

git stash show x-important-stuff
git stash apply x-important-stuff
AH
fuente
0

No creo que haya una manera de hacer explotar un alijo por su nombre.

He creado una función bash que lo hace.

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

Ejemplo de uso:

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

¡Espero que ayude!

franzisk
fuente
0

Para todo, además de la creación de alijo, propondría otra solución introduciendo fzf como una dependencia. Recomiendo tomar 5 minutos de su tiempo y conocerlo, ya que es un gran refuerzo de productividad.

De todos modos, un extracto relacionado de su página de ejemplos que ofrece búsquedas ocultas. Es muy fácil cambiar el scriptlet para agregar funcionalidad adicional (como la aplicación oculta o la caída):

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
fuente
0

Entonces, no estoy seguro de por qué hay tanta consternación sobre este tema. Puedo nombrar un escondite de git con un empuje y el guardado en desuso, y puedo usar una expresión regular para recuperarlo con una aplicación:

Método de almacenamiento Git para usar un nombre para aplicar

$ git stash push -m "john-hancock"

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

Como se mencionó anteriormente, el comando guardar está en desuso, pero aún funciona, por lo que puede usarlo en sistemas más antiguos donde no puede actualizarlos con una llamada de inserción. A diferencia del comando push, el modificador -m no se requiere con save.

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

Este es Git 2.2 y Windows 10.

Prueba visual

Aquí hay un hermoso GIF animado que demuestra el proceso.

El GIF animado que muestra un alijo git se aplica usando un nombre identificable.

Secuencia de eventos

El GIF se ejecuta rápidamente, pero si nos fijamos, el proceso es el siguiente:

  1. El comando ls muestra 4 archivos en el directorio
  2. touch example.html agrega un quinto archivo
  3. git stash push -m "john-hancock" -a (El -a incluye archivos sin seguimiento)
  4. El comando ls muestra 4 archivos después del alijo, lo que significa que el alijo y el restablecimiento completo implícito funcionaron
  5. git stash apply stash ^ {/ john-hancock} se ejecuta
  6. El comando ls enumera 5 archivos, mostrando el archivo example.html que fue devuelto, lo que significa que el comando git stash apply funcionó.

¿Esto tiene sentido?

Para ser sincero, no estoy seguro de cuál es el beneficio de este enfoque. Tiene valor darle un nombre al alijo, pero no la recuperación. Tal vez escribir el proceso de archivar y dejar de lado sería útil, pero aún así es mucho más fácil simplemente abrir un alijo por nombre.

$ git stash pop 3
$ git stash apply 3

Eso me parece mucho más fácil que la expresión regular.

Cameron McKenzie
fuente