Wie kann ich einen Git-Stash umbenennen?

202

Ich habe ein Versteck mit einem falschen Namen. Ich möchte den Namen so korrigieren, dass er korrekt ist.

Wie kann ich einen Stash umbenennen?

Mikemaccana
quelle
5
Pop es und speichern Sie es erneut unter einem anderen Namen?
Bartlomiej Lewandowski
5
Das erneute Poppen und Verstauen ist nicht immer eine Option, da das Verstauen möglicherweise auf einem veralteten Status basiert und zu Konflikten beim Poppen führt. (Der veraltete Zustand muss nicht einmal mehr irgendwo in der Geschichte existieren.)
Tom

Antworten:

258

Nehmen wir an, Ihre Stash-Liste sieht folgendermaßen aus:

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

Zuerst müssen Sie den Stash-Eintrag entfernen, den Sie umbenennen möchten:

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

Fügen Sie es jetzt einfach erneut mit einer neuen Nachricht hinzu, indem Sie sha of commit verwenden, die nach dem Löschen zurückgegeben wurde:

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

Und das ist es:

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

Diese Lösung erfordert Git 1.8.4 oder höher und funktioniert auch mit Dirty Working Directory.

qzb
quelle
3
git show stash@{0}zeigt danach immer noch die alten Informationen. Wie kann man das beheben? (Bitte beachten Sie, dass der Vorrat dann eine andere SHA bekommt.)
Tino
4
Es fühlt sich besser an, den Hash zu bekommen git showund damit zu beginnen git stash store. Dann sehen git stash listSie mit Ihnen das alte und das neue Versteck. Endlich können Sie den alten Vorrat mit aufräumen git stash drop.
Hogi
6
Wird Git Stash Drop die Änderungen nicht verlieren?
Shravya Boggarapu
4
@ShravyaBoggarapu, nein, git entfernt Commit erst, wenn git gces ausgeführt wird. Nachdem stash dropSie dieses normalerweise unzugängliche Commit mit dem git fsck | grep commitBefehl leicht finden können .
QZB
2
@ ÐerÆndi Das einfache Anwenden und Speichern ist eine einfache Option, funktioniert jedoch nicht, wenn Änderungen aufgrund von Konflikten nicht erneut angewendet werden können. In der Zwischenzeit kann das Ablegen und Lagern unter keinen Umständen funktionieren. Ich habe meine Lösung noch einmal getestet - sie funktioniert einwandfrei mit der neuesten Git-Version (2.17.0).
QZB
62

Sofern Sie dies nicht manuell tun oder zu einer Verbesserung von Git beitragen, können Sie einen Alias ​​verwenden:

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}; }; _'

Verwendung: " git stash-rename <stash> [save options] [<message>]"

Mit [save options]jeder Option von git stash save:[-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [-u|--include-untracked] [-a|--all]

Beispiel:

$ 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

Das funktioniert auch, wenn Sie lokale, nicht bereitgestellte Änderungen haben :)

EDIT 2016/02/22

Vereinfachtes Skript, Credits für 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; }; _'

Verwendung: " git stash-rename <stash> [<message>]"

Julien Carsique
quelle
1
Genial! Noch cooler, wenn Sie könntengit stash-rename 'tests with deployAtEnd' 'NXP-13971-deployAtEnd'
Mikemaccana
3
Die Antwort lautet also 1) saubere Arbeitskopie, 2) Stash anwenden, den Sie umbenennen möchten, 3) aus der Stash-Liste löschen, 4) einen neuen Stash mit der richtigen Nachricht erstellen.
GCB
2
Zur Verdeutlichung benennen Sie das letzte Versteck um, und nach einer solchen Aktion wird es zum obersten Versteck?
Onebree
2
Ich lösche den zu umbenennenden Stash, speichere aktuelle Änderungen, falls vorhanden, erstelle den gelöschten Stash mit dem gewünschten Namen neu und wende aktuelle Änderungen erneut an, falls vorhanden.
Julien Carsique
3
Diese Version überprüft, ob beide Argumente vorhanden sind, damit Ihr letzter Vorrat nicht versehentlich gelöscht wird. Es wird auch nur die Stash-Nummer benötigt, nicht die gesamte stash@{0}Referenz. 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

Es ist sehr einfach. Machen Sie zuerst den letzten Vorrat rückgängig mit:

git stash pop

Danach können Sie den Vorrat auf folgende Weise unter einem benutzerdefinierten Namen speichern:

git stash save "your explanatory name"

Ich hoffe es ist nützlich für dich. :) :)

Sandra
quelle
Der umbenannte Vorrat ist möglicherweise nicht der aktuellste.
Mikemaccana
Daumen hoch, da dies (NUR) für den neuesten Vorrat einfacher ist.
Kaihua
3

Ich denke nicht, dass das möglich ist. Es gab einen Vorschlag für die Umbenennung von Verstecken, der jedoch noch nicht umgesetzt wurde.

Meine allgemeine Idee ist:

  1. Implementieren Sie einen neuen git reflog updateBefehl, der die einem bestimmten Reflog-Eintrag zugeordnete Nachricht aktualisiert. Zu diesem Zweck würde eine neue update_reflog_ent()Funktion (in reflog.c ) die Nachricht ändern, die dem jeweiligen zu aktualisierenden Reflog-Eintrag zugeordnet ist. Eine update_reflog()Funktion würde for_each_reflog_ent()mit verwenden update_reflog_ent, um die Änderung tatsächlich durchzuführen.

  2. Ein git stash renameBefehl müsste dann nur git reflog updatemit dem entsprechenden Verweis und der neuen Nachricht aufrufen .

Oder Sie könnten natürlich das Versteck aufschlagen und eine git stash save [message]

A1ternat1ve
quelle
3

Zum Nutzen des Lesers finden Sie hier eine Erweiterung der aktuell akzeptierten und korrekten Antwort .

Wenn Sie nicht nur die Stash-Nachricht korrigieren möchten, sondern auch die Commit-Nachricht des Stash korrigieren möchten, so dass

git stash list

und

git log --oneline -1 stash

beide stimmen dem zu, was gezeigt wird, du brauchst ein bisschen mehr. Es gibt vielleicht einen besseren Weg, aber dieses Rezept hier ist leicht zu verstehen, hoffe ich.

Um dies tun zu können, müssen git commit --amendSie sich auf dem Tipp einer Niederlassung befinden. Daher lautet die Lösung:

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

Erklärt:

  • Erstellen Sie einen neuen (noch nicht vorhandenen) "Scratch" -Zweig aus dem "fraglichen Stash" und wechseln Sie zu diesem
  • Entfernen Sie den alten Vorrat. Dies ist sicher, da wir dies immer noch in der Filiale haben.
  • Verwenden Sie git commit --amenddiese Option , um die Festschreibungsnachricht zu ersetzen. Dadurch wird die SHA des "fraglichen Stashs" geändert.
  • Speichern Sie den Vorrat basierend auf der Antwort des qzb
  • Schalten Sie zurück (was davon ausgeht, dass Sie vom "Master" stammen) und bereinigen Sie

Nachteile:

  • Dadurch werden die Zweige vorübergehend gewechselt. Dieses Rezept kann also nur angewendet werden, wenn git status --porcelaines sauber ist (lesen Sie: gibt nichts aus)

  • Die Vorräte werden neu nummeriert, sodass der geänderte Vorrat wird stash@{0}

  • Sie müssen die Eingabe $MESSAGEzweimal oder verwenden Sie eine Umgebungsvariable (im Beispiel: MESSAGE)

  • Sie müssen einen nicht verwendeten Filialnamen finden

Es gibt Möglichkeiten, dies zu tun, ohne die Zweige zu wechseln, aber dies würde den Rahmen dieser Antwort sprengen.

Beispiel

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

Ausgabe

*-.   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

Jetzt ohne Änderung des Commits (Hinweis: Der SHA im Folgenden wird an Ihrer Seite anders sein):

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

Ausgabe

*-.   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

Wie Sie sehen können, wird stash@{0}immer noch wie 2fbf900 (refs/stash) WIP on master: 8bdcc32 Din angezeigt git log. Wenn Sie genau hinschauen, werden Sie feststellen, dass mehrere Commits SHA geändert haben. Dies liegt daran, wie mit Stashes umgegangen wird (Eltern sind in der SHA enthalten, und Stashes haben ihre Stashes als Eltern).

Repariere das:

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

Ausgabe

*-.   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

Wie Sie auch sehen können, refs/stashhat sich auch die SHA geändert.

Tino
quelle
Erwähnenswert: Dadurch wird der Index zerstört, der mit dem ursprünglichen Stash gespeichert wurde, und durch einen neuen Index ersetzt, der dem übergeordneten Commit des ursprünglichen Stash entspricht. Wenn man nicht vorhatte, den ursprünglich gespeicherten Index zu verwenden (oder er bereits mit dem übergeordneten Index des ursprünglichen Stashs übereinstimmte), ist dies kein Problem.
Torek
1

Hier ist eine modifizierte Version von Juliens Alias , mit der Sie das On <branch>Präfix, das normalerweise vor dem Speichern von Namen steht, richtig behandeln können :

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; }; _'

Syntax:

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

Anwendungsbeispiel:

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

Der größte Teil des Befehls dient zum Parsen der Argumente und zum Herausfinden, was mit dem Zweignamen geschehen soll. Die verwendeten gitWerkzeuge sind wie folgt:

  • git rev-parse <stash> um die SHA des Versteckes zu finden.
  • git stash list --format=%gs -1 <stash>um das Reflog-Thema des Stashs zu finden . Beachten Sie, dass sich dies von der Festschreibungsnachricht des Stash unterscheidet, die durch diesen Befehl nicht geändert wird. Das Reflog-Betreff wird angezeigt git stash list, und Sie können das Reflog-Betreff ändern, ohne die Hashes der mit den Stashes verknüpften Commits zu ändern. Sie können jedoch immer die ursprüngliche Festschreibungsnachricht finden. git stash-renameEntfernen Sie daher keine vertraulichen Informationen!
  • git stash drop <stash>den alten Verweis auf das Versteck fallen zu lassen (aber wir haben immer noch die SHA, damit sie nicht verloren geht).
  • git stash store -m <new-message> <sha>Speichern eines neuen Verweises auf den Stash mit denselben Festschreibungsinformationen, jedoch einem anderen Reflog-Betreff .
  • git stash listum die Verstecke nach Abschluss des Vorgangs aufzulisten. Beachten Sie, dass neue Verstecke immer an den Anfang der Liste verschoben werden. Es wäre notwendig, alle Verstecke vor dem Versteck von Interesse erneut zu verschieben, um seine ursprüngliche Position wiederherzustellen.
Radon Rosborough
quelle
0

Einfachster Weg: Pop deines Stash mit Git Stash Pop, dann speichere es erneut mit Git Stash Save deinen Namen

yoel neuman
quelle
Der umbenannte Vorrat ist möglicherweise nicht der aktuellste.
Mikemaccana