repositorio - git push
¿Cómo nombrar y recuperar un alijo por nombre en git? (15)
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 al hacer git stash apply stashname
. Pero parece que, en este caso, todo lo que sucede es que se utilizará stashname
como la descripción de stash.
¿No hay manera 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 en la git stash list
cuál es su número de alijo real.
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
Edición: me ceñí a mi solución original, pero veo por qué la mayoría preferiría la versión de Etan Reisner (arriba). Así que sólo para el registro:
sapply = "!f() { git stash apply /"$(git stash list | grep -E /"$*/" | awk /"{ print $ 1; }/" | sed -n /"s/://;1p/")/"; }; f"
Así es como lo haces:
git stash save "my_stash"
donde "my_stash" es el nombre oculto ...
Algunas cosas más útiles que debe saber: Todos los escondites se almacenan en una pila. Escribir :
git stash list
Esto hará una lista de todos sus escondites.
Para aplicar un alijo y quitarlo de la pila de alijo, puede dar,
git stash pop stash@{n}
Para aplicar un alijo y mantenerlo en la pila de alijo, escriba:
git stash apply stash@{n}
Donde n en el índice del cambio escondido.
En realidad, puede encontrar el alijo por nombre usando la sintaxis de expresión regular de git para direccionar objetos:
stash^{/<regex>}
:/<regex>
Por ejemplo, al guardar su alijo con un nombre para guardar:
git stash save "guacamole sauce WIP"
... puedes usar una expresión regular para abordar ese alijo:
git stash apply stash^{/guacamo}
Esto aplicará el alijo más joven que coincida con la expresión regular guacamo
. De esa manera, no tienes que saber en qué número está el alijo en la pila, solo tienes que saber su nombre. No hay una sintaxis de terser para esto, pero puede crear un alias en su archivo .gitconfig
:
[alias]
sshow = "!f() { git stash show stash^{/$*} -p; }; f"
sapply = "!f() { git stash apply stash^{/$*}; }; f"
Luego puede usar git sapply <regex>
para aplicar ese alijo (sin dejar caer).
Luego puede usar git sshow <regex>
para mostrar: archivos modificados, inserciones y eliminaciones
EDIT: Ayuda a esta respuesta de sobre cómo usar los argumentos de bash en los alias de git.
EDIT 2: esta respuesta solía contener alias drop
y list
, pero desde entonces los he eliminado, ya que drop
requiere la sintaxis stash@{n}
mientras que list
no filtra los stashes. Si alguien sabe cómo resolver un hash SHA-1 escondido en un ref. Escondido, entonces podría implementar los otros comandos también.
EDICIÓN 3: Según la sugerencia de isyi , he agregado una isyi parche para mostrar cuáles son los contenidos del alijo cuando se muestra uno.
Es desafortunado que git stash apply stash^{/<regex>}
no funcione (en realidad no busca en la lista de stash, vea los comentarios en la respuesta aceptada ).
Aquí están los reemplazos git stash list
que buscan en la git stash list
por regex para encontrar el primer stash@{<n>}
(más reciente) stash@{<n>}
y luego se lo pasan al 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 los códigos de resultado correctos se devuelven 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 las vulnerabilidades de expansión variable porque no estaba seguro acerca de la --grep=$1
. --grep="$1"
vez debería ser --grep="$1"
pero no estoy seguro de si eso podría interferir con los delimitadores de expresiones regulares (estoy abierto a sugerencias).
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''''
}
}
Esta respuesta se debe mucho a Klemen Slavič. Habría comentado la respuesta aceptada pero aún no tengo suficiente reputación :(
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 de la ref=$( ... ); echo ${ref:-<no_match>};
ref=$( ... ); echo ${ref:-<no_match>};
el patrón es así que no se devuelve una cadena en blanco, lo que causaría que sshow, sapply y sdrop se dirijan al último escondite en lugar de fallar como se podría esperar.
Los alijos no están destinados a ser permanentes como tú quieres. Probablemente te sirvan mejor usando etiquetas en confirmaciones. Construye lo que quieras esconder. Haz un compromiso de ello. Crea una etiqueta para ese commit. Luego enrolla tu rama hacia HEAD^
. Ahora, cuando quiera volver a aplicar ese alijo, puede usar git cherry-pick -n tagname
( -n
es --no-commit
).
Para todo, además de la creación de escondites, propondría otra solución introduciendo fzf como una dependencia. Recomiende tomarse 5 minutos de su tiempo y familiarizarse con él, ya que es, en general, un gran aumento de la productividad.
De todos modos, un extracto relacionado de la página de ejemplos que ofrece búsquedas ocultas. Es muy fácil cambiar el sciptlet para agregar una funcionalidad adicional (como aplicación oculta o 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
}
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 <branchname> a partir de la confirmación en la que se creó originalmente <stash>, aplica los cambios registrados en <stash> al nuevo árbol de trabajo e índice, luego deja caer <stash> si eso completa con éxito Cuando no se da <stash>, se aplica el último.
Esto es útil si la rama en la que ejecutó el guardado de git stash ha cambiado lo suficiente como para que la aplicación de git stash falle debido a conflictos. Dado que el alijo se aplica encima de la confirmación que era HEAD en el momento en que se ejecutó git stash, restaura el estado de enmascaramiento original sin conflictos.
Más tarde, puede cambiar de base esta nueva rama a otro lugar que sea un descendiente de donde estaba cuando se escondió.
Si solo está buscando una forma liviana de guardar algunos o todos los cambios de su copia de trabajo actual 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 de arriba y estoy contento con lo que estoy haciendo :)
Tengo estas dos funciones en mi archivo .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)
}
Usándolos de esta manera:
gitstash nice
gitstashapply nice
Usa git stash save NAME
para guardar.
Luego ... puedes usar este script para elegir cuál aplicar (o hacer clic):
#!/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 de Bash anteriores;)
Nota: como dice Kevin, debes usar etiquetas y selecciones de cereza en su lugar.
Use un pequeño script de bash para buscar el número del 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 desea.
git stash save
está en desuso ahora, en su lugar puedes usar git stash push -m "message"
Se puede procurar así:
git stash push -m "message"
donde "mensaje" es tu alijo ...
Alias Esta podría ser una sintaxis más directa para sistemas similares a Unix sin necesidad de encapsular en una función. Agregue lo siguiente a ~ / .gitconfig bajo [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 la entrada de la entrada estándar.