Ist es möglich, einen Git-Stash in ein Remote-Repository zu verschieben?


204

Ist es in git möglich, einen Stash zu erstellen, den Stash in ein Remote-Repository zu verschieben, den Stash auf einem anderen Computer abzurufen und den Stash anzuwenden?

Oder sind meine Optionen:

  • Erstellen Sie einen Patch und kopieren Sie den Patch auf den anderen Computer
  • Eine Nebenniederlassung erstellen und die unvollständige Arbeit an diese Niederlassung übergeben?

Antworten:


68

Es ist nicht möglich, es über Fetch oder so zu erhalten, die Spiegel-Refspec ist es fetch = +refs/*:refs/*, und obwohl Stash ist, wird refs/stashes nicht gesendet. Ein expliziter refs/stash:refs/stashhat auch keine Wirkung!

Es wäre sowieso nur verwirrend, da dies nicht alle Verstecke abrufen würde, nur die neuesten; Die Liste der Verstecke ist das Reflog des Ref refs/stashes.


4
Sie können den neuesten Vorrat von einer Git-Fernbedienung abrufen, aber nicht in Ihren Vorrat, sondern nur in einen anderen Ref. So etwas wie git fetch some-remote +refs/stash:refs/remotes/some-remote/stashdas git stash apply some-remote/stash. Sie können jedoch keine älteren Stashes erhalten, da diese im Reflog gespeichert sind, das nicht abgerufen werden kann. Siehe stackoverflow.com/questions/2248680/…
sj26

75

Hinweis: Ich habe diese Antwort gerade mit 24 Stunden mehr Git-Fu umgeschrieben :) In meiner Shell-Geschichte besteht der gesamte Shebang jetzt aus drei Einzeilern. Ich habe sie jedoch für Ihre Bequemlichkeit nicht komprimiert.

Auf diese Weise hoffe ich, dass Sie sehen können, wie ich Dinge getan habe, anstatt nur blind Dinge kopieren / einfügen zu müssen.


Hier ist Schritt für Schritt.

Angenommen, die Quelle in ~ / OLDREPO enthält Verstecke. Erstellen Sie einen TEST-Klon ohne Stashes:

cd ~/OLDREPO
git clone . /tmp/TEST

Schieben Sie alle Verstecke als temporäre Zweige:

git send-pack /tmp/TEST $(for sha in $(git rev-list -g stash); \
    do echo $sha:refs/heads/stash_$sha; done)

Schleife am Empfangsende, um sich wieder in Verstecke zu verwandeln:

cd /tmp/TEST/
for a in $(git rev-list --no-walk --glob='refs/heads/stash_*'); 
do 
    git checkout $a && 
    git reset HEAD^ && 
    git stash save "$(git log --format='%s' -1 HEAD@{1})"
done

Bereinigen Sie Ihre temporären Zweige, wenn Sie so wollen

git branch -D $(git branch|cut -c3-|grep ^stash_)

Wenn Sie eine Git-Stash-Liste erstellen, werden Sie ungefähr so ​​aussehen:

stash@{0}: On (no branch): On testing: openmp import
stash@{1}: On (no branch): On testing: zfsrc
stash@{2}: On (no branch): WIP on sehe: 7006283 fixed wrong path to binary in debianized init script (reported as part of issue
stash@{3}: On (no branch): WIP on debian-collab: c5c8037 zfs_pool_alert should be installed by default
stash@{4}: On (no branch): WIP on xattrs: 3972694 removed braindead leftover -O0 flag
stash@{5}: On (no branch): WIP on testing: 3972694 removed braindead leftover -O0 flag
stash@{6}: On (no branch): WIP on testing: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{7}: On (no branch): WIP on xattrs: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{8}: On (no branch): WIP on testing: 28716d4 fixed implicit declaration of stat64
stash@{9}: On (no branch): WIP on emmanuel: bee6660 avoid unrelated changes

Auf dem ursprünglichen Repository sah das genauso aus

stash@{0}: WIP on emmanuel: bee6660 avoid unrelated changes
stash@{1}: WIP on testing: 28716d4 fixed implicit declaration of stat64
stash@{2}: WIP on xattrs: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{3}: WIP on testing: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{4}: WIP on testing: 3972694 removed braindead leftover -O0 flag
stash@{5}: WIP on xattrs: 3972694 removed braindead leftover -O0 flag
stash@{6}: WIP on debian-collab: c5c8037 zfs_pool_alert should be installed by default
stash@{7}: WIP on sehe: 7006283 fixed wrong path to binary in debianized init script (reported as part of issue #57)
stash@{8}: On testing: zfsrc
stash@{9}: On testing: openmp import

1
Ich lerne viel in kurzer Zeit und ich denke, ich sollte in meinem früheren Ansatz wahrscheinlich einfach viele Befehlsverwendungen verwenden, was ich später versuchen werde.
sehe

9
Dies funktionierte gut für mich, außer dass ich git add .vor dem git stash save ...Schritt eine brauchte, da ich mich git stashweigere, neue Dateien zu speichern, es sei denn, sie wurden bereitgestellt. Auch das Ergebnis der Rohrleitungen git rev-list ...durch tacKehrt die Reihenfolge des stashes so kommen sie in der gleichen Reihenfolge.
Alan Krueger

1
@sehe Ausgezeichnetes Skript !! Zwei Vorschläge: 1) - Kehren Sie die endgültige Ref-Liste um, sodass die Verstecke im Ziel-Repo in derselben Reihenfolge wie im Original sind. 2) Beenden Sie die letzte forSchleife mit git branch -D stash_$a(Bereinigen, wenn Stashes erstellt werden), damit wir Commits, die bereits erfolgreich gespeichert wurden, nicht erneut verarbeiten, wenn etwas schief geht und wir es erneut versuchen.
Keith Robertson

1
Vielen Dank, dass Sie sich die Zeit genommen haben, zu erklären, was Sie getan haben, anstatt "nur die Lösung zu veröffentlichen".
Marjan Venema

1
Die Lösung kann weiter verbessert werden: Wenn Sie ersetzen git stash save "$(git log --format='%s' -1 HEAD@{1})"mit git update-ref --create-reflog -m "$(git show -s --format=%B $rev)" refs/stash $revIhnen die Original Stash Nachricht bekommen ( update-refist das, was git stash savehinter den Kulissen).
Sebastian Schrader

31

Ich bin etwas spät zur Party, aber ich glaube, ich habe etwas gefunden, das für mich funktioniert, und es könnte auch für Sie sein, wenn Ihre Umstände gleich oder ähnlich sind.

Ich arbeite an einem Feature in einem eigenen Zweig. Der Zweig wird nicht zum Master zusammengeführt und verschoben, bis er fertig ist, oder ich habe Verpflichtungen eingegangen, die ich der Öffentlichkeit gerne zeigen möchte. Was ich also mache, wenn ich nicht bereitgestellte Änderungen auf einen anderen Computer übertragen möchte, ist:

  • Machen Sie ein Commit mit einer Commit-Nachricht wie " [non-commit] FOR TRANSFER ONLY", die den Inhalt enthält, den Sie übertragen möchten.
  • Melden Sie sich am anderen Computer an.
  • Dann mach:

    git pull ssh+git://<username>@<domain>/path/to/project/ rb:lb

    Die URL kann für Sie unterschiedlich sein, wenn Sie auf andere Weise auf Ihr Repository zugreifen. Dadurch werden Änderungen von dieser URL vom Remote-Zweig "rb" in den lokalen Zweig "lb" gezogen. Beachten Sie, dass auf meinem eigenen Computer ein SSH-Server ausgeführt wird und ich auf diese Weise auf das Repository zugreifen kann.

  • git reset HEAD^(impliziert --mixed)

    Dadurch wird der HEAD so zurückgesetzt, dass er auf den Status vor dem Commit "[non-commit]" verweist.

Von git-reset (1): " --mixed: Setzt den Index zurück, aber nicht den Arbeitsbaum (dh die geänderten Dateien werden beibehalten, aber nicht für das Festschreiben markiert) [...]"

Sie werden also am Ende Ihre Änderungen an den Dateien haben, aber es werden keine Commits zum Master gemacht und es ist kein Stash erforderlich.

Dies erfordert jedoch, dass Sie sich git reset --hard HEAD^in dem Repository befinden, in dem Sie "[non-commit]" vorgenommen haben, da es sich bei diesem Commit um Müll handelt.


Dies ist viel schmutziger, als nur einen neuen Feature-Zweig zu erstellen und ihn anschließend zu löschen ....
Taegost

@ Taegost hängt von Ihrer Umgebung ab, denke ich. Könnte ein CI / CD-Zeug sein, das verhindert, dass Zweige wohl oder übel stromaufwärts geschoben werden. Aber ja, je nachdem, was Sie bevorzugen, möchten Sie möglicherweise nur einen Zweig erstellen, um dasselbe zu erreichen.
Victor Zamanian

22

Es ist etwas spät, aber diese Antwort könnte jemandem helfen. Ich wollte das wissen, weil ich in der Lage sein wollte, eine laufende Funktion / einen Fehler / was auch immer zu pushen und von demselben Punkt aus auf einem anderen Computer zu arbeiten.

Was für mich funktioniert, ist das Festschreiben meines in Bearbeitung befindlichen Codes (in einem Zweig, an dem ich alleine arbeite). Wenn ich an meinen anderen Computer komme, ziehen Sie und machen Sie das Commit rückgängig mit:

git reset --soft HEAD^

Arbeiten Sie weiter wie bisher, mit all Ihren laufenden Änderungen, unverbindlich und nicht inszeniert.

Ich hoffe es hilft.


Wenn ich dies versuche, behält der Origin immer noch das Commit bei, das nicht festgeschrieben wurde. Nah dran, aber keine Zigarre für mich.
rezwits

@rezwits Ja, die Fernbedienung behält es, aber es ist einfach genug, den temporären Zweig einfach vom Ursprung zu löschen.
Sir Robert

Tatsächlich habe ich das getan!
rezwits

19

Es scheint einen sehr guten Trick zu geben, um dies zu lösen. Sie können git diff > file.diffdie Datei verwenden (und die Datei festschreiben) und dann die Änderungen mithilfe git apply file.diff(von überall) wiederherstellen , um das gleiche Ergebnis zu erzielen.

Dies wurde auch hier erklärt .


5
Wenn Sie nicht verfolgte Dateien haben: 1. Git hinzufügen. 2. Git Diff HEAD> file.diff
Trickpatty

Wenn Sie den Diff an sich selbst senden, werden keine Commits / Footprints auf dem Repo angezeigt! (zB: Notiz an sich selbst über die Signal-Desktop-App) oder per E-Mail.
John Mee

9

Ich würde mich für den zweiten Ansatz entscheiden, obwohl ich keine Ahnung habe, warum Sie ihn nicht für den Master / Featured Branch festlegen können. Es ist auch möglich, Kirschen zu pflücken.


27
Es gibt keinen technischen Grund, sich nicht auf Master / Feature festzulegen, nur dass ich sagen möchte: "Dies ist kein echtes Commit, es speichert nur meine Arbeit, damit ich sie auf einen anderen Computer übertragen kann."
Andrew Grimm

4

AFAIK die ganze Idee von Stash ist es, etwas nicht so Wichtiges unter dem lokalen Teppich zu verstecken . Niemand sollte etwas über deinen Lieblingsmist wissen ;-) Das einzige "aber" ist: Aber wenn ich mich auf ein paar Workstations entwickle? Dann scpist es viel besser.


9
Etwas so Lustiges sollte ein Kommentar sein. ;-)
Andrew Grimm

2
Total git-ssh-newbie hier, aber kannst du dann scp mit github verwenden?
Koen

Nein, das git-ssh-Frontend von github ist so programmiert, dass Sie nie eine ssh-Shell / -Konsole haben. Es kann nur ein serverseitiger Git-Prozess ausgeführt werden.
argent_smith

1
Also ist scp nicht wirklich eine Option für dieses Szenario, wenn sich Ihr Hauptzweig auf Github befindet? Irgendwelche anderen Vorschläge, um in diesem Fall einen Vorrat zu übertragen?
Koen

1
Ich habe versucht zu betonen, dass Stash Transfer überhaupt nicht möglich ist, AFAIK.
argent_smith

2

Die derzeit akzeptierte Antwort ist technisch korrekt. Sie können Git nicht direkt anweisen, alle Ihre Stashes auf eine Fernbedienung zu übertragen und dann alles in Ihre lokalen Stashes auf einem anderen Computer zu ziehen.

Und obwohl die aktuell am besten bewertete Antwort funktionieren sollte, hat es mir nicht gefallen, dass sie eine Reihe von temporären Zweigen erstellt und das Stash-Commit manuell überprüft und als Stash gespeichert werden muss, was zu Problemen wie diesem Kommentar führen kann erwähnt und führt zu einem Duplikat On (no branch): On testing:. Sicher muss es einen besseren Weg geben!

Während Sie Stashes nicht direkt pushen können, ist ein Stash nur ein Commit (eigentlich zwei Commits), und pro git pushManpage können Sie Commits pushen:

Das <src>ist oft der Name des Zweigs, den Sie pushen möchten, aber es kann ein beliebiger "SHA-1-Ausdruck" sein ...

Ich entschied mich dafür, die Verstecke zu verschieben, refs/stashes/*damit ich meine Fernbedienung nicht mit zusätzlichen Zweigen überfüllte. Also kann ich das machen mit:

git push origin stash@{0}:refs/stashes/$(git rev-parse --short stash@{0})

(Der rev-parseBefehl erhält den kurzen Hash des Stashs, der für das Repo eindeutig ist.)

Als nächstes muss ich den Vorrat vom anderen Computer holen. Git ruft standardmäßig nur Zweige ab, daher muss ich die Stashes speziell abrufen:

git fetch origin refs/stashes/*:refs/stashes/*

Nun konvertieren Sie das Stash-Commit zurück in ein tatsächliches Stash. Wie bereits erwähnt, kann ich das Festschreiben, Zurücksetzen und Verstecken des Stashs zwar wie gewohnt überprüfen, es gefällt mir jedoch nicht, dass zusätzliche Schritte erforderlich sind oder der Indexstatus für das Stash möglicherweise nicht beibehalten wird. Ich habe online nach einer Möglichkeit gesucht, dies automatisch zu tun, aber mein Such-Fu hat mich gescheitert. Schließlich habe ich in der Manpage nachgesehen git stash, wo ich Folgendes gefunden habe:

create
Erstellt einen Stash (ein reguläres Commit-Objekt) und gibt seinen Objektnamen zurück, ohne ihn irgendwo im ref-Namespace zu speichern. Dies soll für Skripte nützlich sein. Es ist wahrscheinlich nicht der Befehl, den Sie verwenden möchten. siehe "Speichern" oben.

Geschäft
Speichern Sie einen bestimmten Stash, der über git stash create (ein baumelndes Merge-Commit) erstellt wurde, in der Stash-Referenz und aktualisieren Sie das Stash-Reflog. Dies soll für Skripte nützlich sein. Es ist wahrscheinlich nicht der Befehl, den Sie verwenden möchten. siehe "Speichern" oben.

Da ich bereits das Commit habe, storeklingt es wie das, was ich will. Also kann ich tun:

git stash store --message "$(git show --no-patch --format=format:%s <SHA>)" <SHA>

Ersetzen <SHA> durch das gerade abgerufene Versteck.

(Das git show Befehl ruft die Festschreibungsnachricht aus dem Stash-Commit ab, um sie als Nachricht für das Stash-Protokoll zu verwenden.)

Der Vorrat wird jetzt wie gewohnt in meinem lokalen Repo angezeigt:

$ git stash list
stash@{0}: On master: temp
...

Um die Fernbedienung zu bereinigen, können die Verstecke wie folgt von der Fernbedienung gelöscht werden:

git push origin :refs/stashes/<SHA>

Diese Methode hat auch den Vorteil, dass sie idempotent ist: Wenn Sie den pushBefehl erneut ausführen , wird er gemeldet Everything up-to-date. Der fetchBefehl kann auch sicher wiederholt ausgeführt werden. Während das stash storeSpeichern des Stashs übersprungen wird, wenn es mit dem letzten Stash identisch ist, werden Duplikate älterer Stashes nicht verhindert. Dies kann jedoch umgangen werden, wie ich es in meinem git-rstashSkript tue , siehe unten.


Zum Abschluss können Sie auch einfach alle Verstecke schieben (mit ):

for i in $(seq 0 $(expr $(git rev-list --walk-reflogs --count stash) - 1))
do
  git push origin stash@{$i}:refs/stashes/$(git rev-parse --short stash@{$i})
done

oder importiere alle abgerufenen Stashes:

for stash in $(ls .git/refs/stashes)
do
  git stash store --message "$(git show --no-patch --format=format:%s $stash)" $stash
done

Ich habe eine erstellt Skript, das als Unterbefehl aufgerufen werden kann (z. B. git rstash push 0), damit ich mich nicht an all das erinnern muss. git-rstashfinden Sie hier.


1

Das Folgende funktioniert nicht mit dem Stash, sondern mit den nicht festgeschriebenen Änderungen im Arbeitsverzeichnis. Es erstellt eine Verzweigung, schreibt alle aktuellen Änderungen automatisch fest und überträgt sie an die Fernbedienung:

commit_and_push_ ( ) {
    # This will:
    #  1. checkout a new branch stash-XXX
    #  2. commit the current changes in that branch
    #  3. push the branch to the remote
    local locbr=${1:-autostash-XXX}
    git checkout -b $locbr
    git add .
    git commit -a -m "Automatically created commit"
    git push origin $locbr
    echo "Autocommitted changes in branch $locbr ..."
}

Verwenden Sie wie:

commit_and_push_ my-temp-branch
commit_and_push_

0

Ich würde einfach einen neuen Stash-Zweig erstellen und ihn entfernen, wenn dieser Zweig nicht benötigt wird.

git add . // Add work-in-progress job
git checkout -b stash-branch // Create and checkout to stash-branch
git commit -m 'WIP: job description' // Commit message
git push origin stash-branch // Push to remote
git pull origin stash-branch // Pull the stash-branch
git checkout master // Checkout to working branch
git rebase stash-branch // Rebase the stash-branch
git reset --soft // Equivalent to stash!!
git branch -d stash-branch // Delete when not needed from local
git push -d origin stash-branch // Delete when not needed from remote

-9

Benutze einfach Dropbox wie dieser Typ. Auf diese Weise müssen Sie sich keine Gedanken über das Verschieben von Stashes machen, da Ihr gesamter Code gesichert wird.

http://blog.sapegin.me/all/github-vs-dropbox


2
Bevor jemand eine Knie-Ruck-Reaktion hat, sage ich nicht, Dropbox anstelle von Github zu verwenden, sondern Code zu speichern, der nicht für ein Commit in Dropbox bereit ist, das lokal noch unter Versionskontrolle steht.
NYC Tech Engineer

4
Das Kopieren des gesamten Projekts in die Remote-Cloud dauert zu lange.
Stav Alfi
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.