2009-08-15 18 views
64

E 'possibile in git passare ad un altro ramo senza estrarre tutti i file? Dopo aver cambiato ramo ho bisogno di cancellare tutti i file, rigenerarli, commetterli e tornare indietro. Quindi il controllo dei file è solo una perdita di tempo (e ci sono circa 14000 file - è un'operazione lunga).switch git branch senza file checkout

per rendere il tutto chiaro:

ho bisogno di tutto questo per caricare documentation a github.

Ho repo con ramo gh-pages. Quando ricostruisco la documentazione localmente, la copio nella directory repo, commetto e spingo su github. Ma non ero felice perché avevo due copie di documentazione a livello locale. E ho deciso di creare un ramo vuoto e dopo aver commesso passare a vuoto ed eliminare i file. Ma tornare indietro è un'operazione lunga, quindi ho fatto questa domanda.

so che posso solo lasciare in gh-pagine filiale ed eliminare i file, ma non mi piace alberi di lavoro sporchi)

+0

Quanto è "lungo" per te? Su quale piattaforma stai lavorando? Stai lavorando su una rete come con NFS o altri file sharing? –

+0

Qual è lo scopo di questo esercizio? Vuoi avere due rami, uno con i commit dettagliati, la seconda registrazione solo i principali cambiamenti (a grana grossa)? –

+0

Forse è più economico creare un clone temporaneo (o permanente?) Della tua copia di lavoro. [La mia risposta correlata] (http://stackoverflow.com/a/29616287/946850) e un [writeup] (http://krlmlr.github.io/git-subbranch) mostrano come funziona anche come sottodirectory del repository principale. – krlmlr

risposta

70

Sì, puoi farlo.

git symbolic-ref HEAD refs/heads/otherbranch 

Se è necessario impegnarsi in questo ramo, ti consigliamo di reimpostare l'indice troppo altrimenti si finirà per commettere qualcosa in base all'ultimo ramo controllato.

git reset 
+0

Usa 'echo" ebff34ffb665de0694872dceabe0edeaf50ec5a9 "> .git/HEAD' seguito da' git reset' per indicare un riferimento invece di un ramo. – cadorn

+1

La scrittura diretta nel file HEAD è meno affidabile. Cosa succede se ci si trova in una sottodirectory? Per la testa staccata (testa che punta direttamente a SHA1), prova questo: 'git update-ref HEAD ref/heads/otherbranch' –

+2

Se vuoi controllare un ramo nuovo dal ramo attuale, un altro modo per farlo è 1. 'git stash' 2.' git checkout -b altroBranch' 3. 'git stash pop' – Winny

8

è possibile sovrascrivere il file HEAD con un diverso nome del ramo:

echo "ref: refs/heads/MyOtherBranch"> .git/HEAD

+13

Probabilmente è meglio usare il comando symbolic-ref per fare ciò: 'git symbolic-ref HEAD ref/head/MyOtherBranch' http://www.kernel.org/pub/software/scm/git/docs/git -symbolic-ref.html –

+0

@GregHewgill, questo è l'unico modo che conosco per spostare l'HEAD su un hash di commit. Puoi farlo con 'git symbolic-ref'? – tomekwi

7

Penso che stiate cercando il comando idraulico git read-tree. Questo aggiornerà l'indice ma non aggiornerà alcun file nella tua directory di lavoro. Per esempio, supponendo che branch è il nome del ramo da leggere:

git read-tree branch

Se si vuole poi impegnarsi per il ramo che hai appena letto, è inoltre necessario:

git symbolic-ref HEAD refs/heads/branch
+0

no Devo solo cambiare ramo, nessun altro cambiamento - quindi il ref simbolico è abbastanza buono – tig

0

Con così tanti file, potrebbe essere meglio tenere solo due repository, uno per ogni ramo. Puoi tirare le modifiche avanti e indietro secondo necessità. Questo sarà meno sorprendente di provare a fare scherzi di scorbuto con git.

+0

Puoi usare 'git-new-worktree' per quello invece (in' contrib/') –

+0

Ah sì, per ogni problema, git ha una nuova funzionalità ... –

+0

Ho fatto spesso qualcosa di simile, che sta copiando la mia directory locale prima di fare qualsiasi "roba da git spaventoso" come novellino (come cambiare rami, ecc.). Incoraggerei le persone a seguire questa strada fino a quando non ti sentirai sicuro nel tuo git-fu, ma ad allontanarti da esso quando possibile. Mantenere due repository distinti è ok, ma aggiunge un livello di complicazione e non ti consente di sfruttare le molte utili funzionalità di git (fusione, selezione delle ciliegie, ecc.). – David

14

Non sarebbe una soluzione migliore avere due directory di lavoro (due aree di lavoro) con un repository, o anche due repository?

C'è lo strumento git-new-workdir nella sezione contrib/ per aiutarti con questo.

+0

+1 Non lo sapevo, grazie – MBO

+0

git-new-workdir è lo stesso del comando worktree di git? Io uso worktree quando voglio controllare un ramo in una cartella diversa (senza dover clonare l'intero repo). – Ryuu

+0

Lo script 'git-new-worktree' è antecedente al sottocomando' git worktree'; questo comando non era disponibile quando la risposta è stata scritta. Lo script ad esempio richiede il supporto per i collegamenti simbolici; IMHO è meglio usare il supporto nativo. –

0

Se si sta semplicemente tentando di modificare il punto in cui punta un ramo remoto, è possibile farlo con "git push" senza toccare la copia locale.

http://kernel.org/pub/software/scm/git/docs/git-push.html

Il formato di un < refspec> parametro è un più facoltativa +, seguito dalla fonte ref < src>, seguito da due punti:, seguito da l'arbitro destinazione < dst>. Viene utilizzato per specificare con quale oggetto < src> il riferimento allo < dst> nel repository remoto deve essere aggiornato.

ad esempio, per aggiornare foo a commettere c5f7eba effettuare le seguenti operazioni:

git push origin c5f7eba:foo 

Non sono sicuro se questo è ciò che si erano dopo o no.

+0

La domanda ha già una risposta: http://stackoverflow.com/questions/1282639/switch-git-branch-without-files-checkout/1282706#1282706 – tig

24

Utilizzando git base solo i comandi:

Questa risposta è un po 'più lungo di quello di Carlo, ma consiste esclusivamente di comandi Git di base che posso capire e ricordare in tal modo, eliminando la necessità di continuare a cercare essa su.

contrassegnare la posizione corrente (commit prima se necessario):

git checkout -b temp 

RESET (mosse) il marcatore per l'altro ramo senza cambiare dir di lavoro:

git reset <branch where you want to go> 

ora temp e altro ramo punto allo stesso commit, e la tua directory di lavoro non è stata modificata.

git checkout <branch where you want to go> 

poiché la testa è già rivolta verso la stessa impegnarsi, dir di lavoro non viene toccato

git branch -d temp 

Si noti che questi comandi sono facilmente disponibili da qualsiasi client grafico.

+3

Preferirei 'git reset --soft 'per evitare di aggiornare l'indice – JoelFan

+6

Sono d'accordo con la vostra strategia di evitare i comandi di git plumbing e di favorire quelli in porcellana. – user64141

0

si può fare uso di

 1. git checkout -f <new-branch> 
     2. git cherry-pick -x <previous-branch-commit-id> 

precedente-ramo-commit-id è il commit da cui si desidera copiare i dati vecchi.

3

A beneficio del lettore:

Mentre penso che Charles Bailey's solution è una corretta, questa soluzione ha bisogno di un ritocco quando si passa a qualcosa, che non è una filiale locale. Inoltre dovrebbe esserci un modo come farlo con i comandi regolari che è facile da capire. Ecco quello che mi si avvicinò con:

git checkout --detach 
git reset --soft commitish 
git checkout commitish 

spiegato:

  • git checkout --detach è lo stesso git checkout HEAD^{} che lascia il ramo corrente dietro e va in "stato capo distaccato". Quindi la prossima modifica di HEAD non influisce più su nessun ramo. Lo scollegamento di HEAD non ha alcun effetto sul worktree né sull'indice.
  • git reset --soft commitish quindi sposta HEAD sullo SHA del dato commitish. Se si desidera aggiornare anche l'indice, lasciare --soft, ma io non consiglio di farlo. Questo, ancora, non tocca l'albero di lavoro e (--soft) non l'indice.
  • git checkout commitish quindi collega HEAD allo commitish (diramazione) specificato. (Se commitish è uno SHA non accade nulla.) Anche questo non ha effetto sull'indice né sull'albero di lavoro.

Questa soluzione accetta tutto ciò che fa riferimento a un commit, quindi questo è l'ideale per alcuni alias git. Lo rev-parse di seguito è solo un test per essere sicuro, niente si rompe nella catena, in modo tale che gli errori di battitura non si spostino accidentalmente nello stato di testa staccata (il recupero degli errori sarebbe molto più complesso).

Questo porta alla seguente git switch treeish alias:

git config --global alias.switch '!f() { git rev-parse --verify "$*" && git checkout "HEAD^{}" && git reset --soft "$*" && git checkout "$*"; }; f' 

Cordiali saluti, lo si può trovare nella mia lista di git aliases.

+0

Approccio interessante. +1 – VonC

+0

Molto utile. Grazie! –