2013-07-30 17 views
7

Dire che ho un repository che ha un numero di revisione A. E vorrei aggiornarlo alla revisione B, mentre l'ultima revisione è C. (la revisione A è precedente a B, e B è precedente a C). Sono nuovo di git così ho fatto qualche ricerca e ho trovato this, che mi ispira una soluzione:Git: aggiornare un repository a determinate revisioni

git pull # update from A to the latest revision C 
git reset --hard B 

che fa il lavoro. Ma dal momento che non posso git reset --hard B da A direttamente, l'aggiornamento precedente alla più recente è ancora troppo pesante, mi chiedo che ci potrebbe essere qualche comando di una sola riga per abbinare il mio bisogno. Qualche suggerimento per favore?

risposta

14

non c'è un "aggiornamento di un repository per una certa versione". È repository è tutte le versioni, questo è quello che git fetch/git pull fa.

Se si desidera inserire una revisione specifica del repository nell'albero di lavoro corrente localmente, ci sono diversi modi per farlo. Il più vicino alle vostre domande è:

aggiornamento repository locale:

git fetch origin 

creare un nuovo ramo (da qualunque ramo siete attualmente in poi, sarà difficile ripristinare in seguito in modo non importa):

git branch yourbranchname 
git checkout yourbranchname 

le suddette operazioni 2 può essere abbreviato in uno (HEAD corrente è assunta come fonte del ramo):

git checkout -b yourbranchname 

quindi posizionare il puntatore di quel ramo della commettere è necessario (B):

git reset --hard sha1-of-B 

git azzerato --hard sarà sempre lavorare, ma non dipende dalla storia del vostro ramo, l'unica condizione per poter il lavoro è che il commit B è in te oggetto locale base (es B deve esistere e deve essere stato prelevato da un repository remoto, non è il tuo lavoro).

Come @Hasturkun fa notare, si può anche diramano direttamente da hash arbitraria con un argomento in più:

git checkout -b yourbranchname SHA-1 
+4

Non hai davvero bisogno di resettare il ramo, dato che puoi semplicemente crearlo con il punto d'inizio dove si desidera, cioè.'git branch newbranch SHA1-of-B', o' git checkout -b newbranch SHA1-of-B' – Hasturkun

+0

@ Sébastien Grazie per avermi presentato alcuni concetti di base. –

+0

@Hasturkun la tua risposta funziona perfettamente per me, grazie. –

5

Per questo è necessario utilizzare git checkout. Basta fare:

git checkout B

e avrete quella revisione.

+0

Grazie, ma ho ricevuto un errore usando 'git checkout':' reference is not a tree'. –

+0

Penso che il commento di Hasturkun nella risposta di Sébastien Dawans risolverà il problema per voi. – jbr

1

Il tuo approccio è del tutto sbagliato. Stai modificando qualcosa che non vuoi modificare: il tuo attuale ramo (presumibilmente master).

Un semplice, lineare repository git è una catena di commit come questo

*---A---*---*---B---*---*---C 
    ^     ^
    |      | 
    master    origin/master 
    ^
    | 
    HEAD 

Questo è lo stato del repository dopo aver chiamato git fetch. Tieni presente che l'intera cronologia con tutti i passaggi intermedi è proprio lì sul tuo disco rigido locale. È solo che si è verificato lo stato al commit A estratto (HEAD punti a master che punta a A), quindi i file che si vedono appartengono a quello stato.

Ora, se si vuole solo vedere lo stato che è stato commesso come B, è sufficiente verificare che il commit con git checkout B. Questo aggiorna i file che si vedono allo stato di B, e ricorda HEAD in quel commit:

*---A---*---*---B---*---*---C 
    ^  ^  ^
    |   |   | 
    master  HEAD origin/master 

HEAD fa riferimento sempre il/ramo commit che git pensa che tu sia, e al quale confronterà vostra cartella di lavoro quando chiami git status.

Il semplice git checkout B è sufficiente, se si vuole solo vedere quel commit. Se in realtà vuoi apportare modifiche che impegni e vuoi preservare, devi introdurre un nuovo ramo per registrare tali modifiche. Questo è ottenuto da un semplice git checkout -b newBranch dopo il git checkout B. Questo vi darà lo stato

*---A---*---*---B---*---*---C 
    ^  ^  ^
    |   |   | 
    master newBranch origin/master 
       ^
       | 
       HEAD 

Questo dà solo un nome per commettere B altro rispetto al suo valore di hash. Dopo qualche altro commit, il tuo stato sarebbe simile a questa:

*---A---*---*---B---*---*---C 
    ^   |   ^
    |   |   | 
    master   \ origin/master 
        \ 
        *---*---D 
          ^
          | 
         newBranch 
          ^
          | 
          HEAD 

Il punto è che, dopo aver controllato un altro ramo/commit con git checkout ..., si può sempre tornare facilmente a commettere D chiamando git checkout newBranch, e la arresti di riferimento permanenti git dal commit della garbage collection D.


Ora, perché si sta utilizzando git reset --hard male? Prima di tutto, elimina tutte le modifiche locali che non hai ancora commesso senza ulteriore avviso. Secondo, potrebbe perdere la tua storia se non stai attento con esso.

Considerare, ad esempio, il caso in cui sono state apportate alcune modifiche dopo l'ultima immissione al repository upstream e si desidera dare un'occhiata ad un commit storico B. (. Un po 'l'opposto del caso in questione) La storia si presenta così:

*---A---*---*---B---*---*---C 
    ^     ^
     |      | 
origin/master    master 
          ^
           | 
          HEAD 

Con git reset --hard B, si ottiene questo stato:

*---A---*---*---B-(-*---*---C) 
    ^  ^
     |   | 
origin/master master 
       ^
        | 
       HEAD 

i commit tra parentesi, non si fa riferimento direttamente o indirettamente da qualsiasi ramo più, e possono essere spazzatura raccolti in qualsiasi momento. git potrebbe non essere molto aggressivo con la raccolta dei dati inutili, , ma se raccoglie dati inutili mentre ci si trova in questo stato, non è possibile eseguire il commit C indietro, sarà perso per sempre. Non vuoi che questo accada, quindi non è una buona idea prendere l'abitudine di usare git reset --hard leggermente.

Aveva si è utilizzato git checkout invece, il ramo master sarebbe ancora indicando C, e si sarebbe ancora in grado di tornare ad essa con un semplice git checkout master.

Problemi correlati