È possibile inviare un git stash a un repository remoto?


205

In git, è possibile creare uno stash, spingere lo stash in un repository remoto, recuperare lo stash su un altro computer e applicare lo stash?

O sono le mie opzioni:

  • Creare una patch e copiarla sull'altro computer o
  • Creare un ramo secondario e affidare il lavoro incompleto a quel ramo?

Risposte:


68

Non è possibile ottenerlo tramite fetch o giù di lì, il mirror refspec è fetch = +refs/*:refs/*, e anche se lo stash è refs/stashche non viene inviato. Neanche un esplicito refs/stash:refs/stashha alcun effetto!

Sarebbe solo fonte di confusione, dal momento che non avrebbe recuperato tutte le scorte, solo l'ultima; l'elenco degli stash è il reflog del ref refs/stashes.


4
Puoi recuperare l'ultima scorta da un telecomando Git, ma non nella tua scorta, solo in un altro riferimento. Qualcosa come git fetch some-remote +refs/stash:refs/remotes/some-remote/stashil git stash apply some-remote/stash. Ma non puoi ottenere stash più vecchi perché sono memorizzati nel reflog che non è intercettabile. Vedere stackoverflow.com/questions/2248680/...
sj26

75

Nota: ho appena riscritto questa risposta con 24 ore in più di git-fu sotto la cintura :) Nella mia storia delle conchiglie, l'intero shebang ora è composto da tre battute. Tuttavia, li ho incondensati per tua comodità.

In questo modo, spero che sarai in grado di vedere come ho fatto le cose, invece di dover semplicemente copiare / incollare alla cieca le cose.


Ecco passo dopo passo.

Supponiamo che l'origine in ~ / OLDREPO contenga stash. Crea un clone TEST che non contiene stash:

cd ~/OLDREPO
git clone . /tmp/TEST

Spingi tutti gli stash come rami temporanei:

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

Ciclo sull'estremità ricevente per trasformarlo in stash:

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

Se vuoi, pulisci i tuoi rami temporanei

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

Fai una lista di git stash e farai qualcosa del genere:

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

Sul repository originale, lo stesso sembrava

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
Sto imparando molto in poco tempo e penso che probabilmente dovrei semplicemente usare molti comandi nel mio approccio precedente, che proverò a fare in seguito.
vedi

9
Questo ha funzionato bene per me, tranne che avevo bisogno di una git add .prima che il git stash save ...passo in quanto git stashsi rifiuta di riporre i nuovi file a meno che non sono stati in scena. Inoltre, il piping del risultato di git rev-list ...through tacinverte l'ordine degli stash in modo che escano nello stesso ordine.
Alan Krueger,

1
@sehe sceneggiatura eccellente !! Due suggerimenti: 1) - indietro l'elenco di riferimento finale in modo che gli stash siano nello stesso ordine nel repository target come nell'originale. 2) Termina il forciclo finale con git branch -D stash_$a(ripulisci quando vengono creati gli stash) in modo che se qualcosa va storto e riproviamo, non rielaboriamo i commit già stashed con successo.
Keith Robertson,

1
Grazie mille per aver dedicato del tempo a spiegare cosa hai fatto invece di "solo pubblicare la soluzione".
Marjan Venema,

1
La soluzione può essere ulteriormente migliorata: se si sostituisce git stash save "$(git log --format='%s' -1 HEAD@{1})"con git update-ref --create-reflog -m "$(git show -s --format=%B $rev)" refs/stash $revsi ottiene il messaggio originale ( update-refè ciò che sta git stash savedietro le quinte).
Sebastian Schrader,

31

Sono un po 'in ritardo alla festa, ma credo di aver trovato qualcosa che funzioni per me a riguardo e potrebbe anche per te se le tue circostanze sono uguali o simili.

Sto lavorando a una funzione nel suo ramo. La filiale non è fusa in maestro e spinta fino alla fine o non mi sono impegnata a sentirmi a mio agio nel mostrare al pubblico. Quindi, quello che faccio quando voglio trasferire le modifiche non organizzate su un altro computer è:

  • Effettua un commit, con un messaggio di commit come " [non-commit] FOR TRANSFER ONLY", con il contenuto che desideri trasferire.
  • Accedi all'altro computer.
  • Quindi fa:

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

    L'URL potrebbe differire per te se accedi al tuo repository in modo diverso. Ciò estrarrà le modifiche dall'URL dal ramo remoto "rb" nel ramo locale "lb". Nota che ho un server SSH in esecuzione sul mio computer e sono in grado di accedere al repository in quel modo.

  • git reset HEAD^(implica --mixed)

    Ciò reimposta HEAD in modo che punti allo stato prima del commit "[non-commit]".

Da git-reset (1): " --mixed: reimposta l'indice ma non l'albero di lavoro (ovvero, i file modificati vengono conservati ma non contrassegnati per il commit) [...]"

Quindi alla fine avrai le tue modifiche ai file, ma non vengono fatti commit per master e non c'è bisogno di una scorta.

Ciò tuttavia richiederà di farlo git reset --hard HEAD^nel repository in cui è stato effettuato il "[non commit]", poiché quel commit è immondizia.


Questo è molto più sporco quindi solo creando un nuovo ramo di funzionalità per poi eliminarlo in seguito ....
Taegost,

@Taegost dipende dal tuo ambiente immagino. Potrebbe trattarsi di alcune cose CI / CD che impediscono di spingere i rami a monte, volenti o nolenti. Ma sì, a seconda di ciò che preferisci, potresti voler semplicemente creare un ramo per realizzare la stessa cosa.
Victor Zamanian,

22

È un po 'tardi, ma questa risposta potrebbe aiutare qualcuno. Volevo saperlo perché volevo poter inviare una funzione / bug / qualunque cosa in corso e lavorare dallo stesso punto su un altro computer.

Ciò che funziona per me è impegnare il mio codice in corso (in un ramo su cui sto lavorando da solo). Quando arrivo sull'altro computer, eseguo un pull, quindi annulla il commit con:

git reset --soft HEAD^

Continua a lavorare come eri, con tutte le modifiche in corso lì, non impegnate e non messe in scena.

Spero che sia d'aiuto.


Quando provo a fare questo, Origin mantiene ancora il Commit, che era senza impegno. Vicino ma niente sigaro per me.
riattiva il

@rezwits Sì, il telecomando lo mantiene, ma è abbastanza facile eliminare semplicemente il ramo temporaneo dall'origine.
Sir Robert,

infatti è quello che ho fatto!
rezwits il

19

Sembra esserci un trucco molto accurato per risolvere questo problema. è possibile utilizzare git diff > file.diff(e eseguire il commit del file), quindi ripristinare le modifiche utilizzando git apply file.diff(da qualsiasi luogo) per ottenere lo stesso risultato.

Questo è stato spiegato anche qui .


5
se hai file non tracciati: 1. git add. 2. git diff HEAD> file.diff
trickpatty,

Inviare messaggi al diff a te stesso non consente alcun commit / footprint sul repository! (ad es. note-to-self tramite l'app desktop Signal) o e-mail.
John Mee,

9

Andrei con il secondo approccio, anche se non ho idea del perché non puoi impegnarlo nel ramo master / in primo piano. È anche possibile fare la raccolta delle ciliegie.


27
Non c'è motivo tecnico per non impegnarmi in master / in primo piano, solo che voglio dire "Questo non è un vero commit, sta solo salvando il mio lavoro in modo da poterlo ottenere su un'altra macchina".
Andrew Grimm,

4

AFAIK l'idea della scorta è quella di nascondere qualcosa di non così importante sotto il tappeto locale . Nessuno dovrebbe sapere della tua merda preferita ;-) L'unico "ma" è: Ma se mi sviluppassi su un paio di workstation? Quindi scpè molto meglio.


9
Qualcosa di così divertente dovrebbe essere un commento. ;-)
Andrew Grimm,

2
Total git-ssh-newbie qui ma puoi usare scp con github allora?
Koen,

No, il frontend git-ssh di github è programmato in modo da non avere mai una shell / console ssh. Può solo eseguire il processo git lato server.
argent_smith,

1
Quindi scp non è davvero un'opzione per questo scenario se il tuo ramo master è su github? Qualche altro suggerimento per trasferire una scorta in quel caso?
Koen,

1
Ho cercato di sottolineare che il trasferimento di oggetti non è affatto possibile, AFAIK.
argent_smith,

2

La risposta attualmente accettata è tecnicamente corretta, non puoi dire direttamente a Git di trasferire tutti i tuoi stash su un telecomando, quindi inserire tutto nei tuoi stash locali su un altro computer.

E mentre la risposta attualmente top-up dovrebbe funzionare, non mi è piaciuto che crea un mucchio di rami temporanei e che richiede il controllo manuale dello stash commit e il salvataggio come stash, il che può portare a problemi come questo commento menzionato e porta a un duplicato On (no branch): On testing:. Sicuramente ci deve essere un modo migliore!

Quindi, sebbene non sia possibile inviare direttamente gli stash, uno stash è solo un commit (in realtà due commit), e per la git pushpagina man è possibile eseguire il push dei commit:

Il <src>è spesso il nome del ramo che si vorrebbe per spingere, ma può essere qualsiasi arbitraria "SHA-1" ...

Ho scelto di spingere gli stash in refs/stashes/*modo da non ingombrare il mio telecomando con rami extra. Quindi posso farlo con:

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

(Il rev-parsecomando ottiene il breve hash dello stash, che sarà unico per il repository.)

Successivamente, devo recuperare la scorta dall'altro computer. Git recupera solo i rami per impostazione predefinita, quindi ho bisogno di recuperare specificamente gli stash:

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

Ora per riconvertire lo stash commit in uno stash reale. Come accennato, mentre potevo semplicemente controllare lo stash commit, ripristinare e stash come al solito, non mi piace che richieda passaggi aggiuntivi o che potrebbe non mantenere lo stato dell'indice per lo stash. Stavo cercando online un modo per farlo automaticamente, ma la mia ricerca non mi ha fallito. Alla fine ho cercato nella pagina man git stashdove ho trovato questo:

create
Crea uno stash (che è un oggetto commit regolare) e restituisce il nome dell'oggetto, senza memorizzarlo in nessun punto dello spazio dei nomi ref. Questo è utile per gli script. Probabilmente non è il comando che vuoi usare; vedi "salva" sopra.

store
Memorizza un dato stash creato tramite git stash create (che è un commit merge penzolante) nel ref stash, aggiornando il reflog stash. Questo è utile per gli script. Probabilmente non è il comando che vuoi usare; vedi "salva" sopra.

Dal momento che ho già il commit, storesuona come quello che voglio. Quindi posso fare:

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

Sostituendo <SHA>con la scorta che è stata appena recuperata.

(Il git showcomando ottiene il messaggio di commit dal commit stash, da usare come messaggio per il registro stash.)

Lo stash ora appare normalmente nel mio repository locale:

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

Per ripulire il telecomando, gli stash possono essere eliminati dal telecomando in questo modo:

git push origin :refs/stashes/<SHA>

Questo metodo ha anche il vantaggio di essere idempotente: se si esegue di pushnuovo il comando, verrà segnalato Everything up-to-date. Il fetchcomando può anche essere eseguito ripetutamente in modo sicuro. Mentre stash storesalterà la memorizzazione dello stash se è lo stesso dello stash più recente, non impedisce i duplicati degli stash più vecchi. Questo può essere risolto però, come faccio nella mia git-rstashsceneggiatura, vedi sotto.


Per il completamento, puoi anche spingere facilmente tutti gli stash (con ):

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

o importa tutti gli stetch recuperati:

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

Ho creato un script che può essere chiamato come sottocomando (ad esempio git rstash push 0), quindi non devo ricordare tutto questo. git-rstashpuò essere trovato qui


1

Quanto segue non funziona con lo stash, ma con le modifiche senza commit nella directory di lavoro. Crea un ramo, inserisce automaticamente tutte le modifiche correnti e invia al telecomando:

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 ..."
}

Usa come:

commit_and_push_ my-temp-branch
commit_and_push_

0

Vorrei semplicemente creare un nuovo ramo stash e rimuoverlo ogni volta che quel ramo non è richiesto.

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

Usa Dropbox come ha fatto questo ragazzo. In questo modo non devi preoccuparti di inviare gli stash poiché verrà eseguito il backup di tutto il codice.

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


2
Prima che qualcuno abbia una reazione istintiva, non sto dicendo di usare Dropbox invece di Github, ma di archiviare il codice che non è pronto per un commit in Dropbox che sarebbe comunque sotto il controllo della versione localmente.
Ingegnere tecnico di New York,

4
ci vorrà troppo tempo per copiare tutto il progetto su cloud remoto.
Stav Alfi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.