Come effettuare il checkout in Git per data?


314

Sto lavorando a una regressione nel codice sorgente. Vorrei dire a Git: "controlla la fonte in base a una data / ora parametrizzata". È possibile?

Ho anche messo in scena cambiamenti nella mia visione attuale che non voglio perdere. Idealmente, vorrei alternare tra la fonte corrente e alcune versioni a cui sono interessato in base a una data precedente.


9
Nel caso in cui non lo sapessi, Git Bisect è abbastanza grande per trovare regressioni. Direi, usa la sintassi {1 year ago} come ha detto Andy, per trovare un commit noto, quindi usalo come git bisect goodpunto iniziale .
MatrixFrog,

Sento che questo è un buon caso d'uso per tags.
Jess,

Risposte:


365

Per mantenere le modifiche correnti

Puoi tenere il tuo lavoro nascosto, senza impegnarlo, con git stash. Dovresti usarlo git stash popper riaverlo. Oppure puoi (come diceva carleeto ) git commitin un ramo separato.

Acquista per data usando rev-parse

Puoi effettuare il checkout di un commit entro una data specifica usando in rev-parsequesto modo:

git checkout 'master@{1979-02-26 18:30:00}'

Maggiori dettagli sulle opzioni disponibili sono disponibili in git-rev-parse.

Come notato nei commenti, questo metodo utilizza il reflog per trovare il commit nella cronologia. Per impostazione predefinita, queste voci scadono dopo 90 giorni . Sebbene la sintassi per l'utilizzo del reflog sia meno dettagliata, è possibile risalire a soli 90 giorni.

Acquista per data usando rev-list

L'altra opzione, che non utilizza il reflog, è utilizzare rev-listper ottenere il commit in un determinato momento con:

git checkout `git rev-list -n 1 --first-parent --before="2009-07-27 13:37" master`

Nota: - first-parent se vuoi solo la tua cronologia e non le versioni introdotte da una fusione. Questo è quello che di solito vuoi.


2
@ Rocky Puoi fornirci maggiori dettagli Rocky? Cosa stai inserendo dalla riga di comando e perché dici che non funziona? stai ricevendo un messaggio di errore?
Andy,

8
@Rocky: il problema è che il parametro deve essere racchiuso tra virgolette, altrimenti bash separa gli argomenti negli spazi. Prova git co 'master@{2 days ago}'.
Mark Wilden,

13
Nota: a seconda di quanto indietro, potrebbe non funzionare perché utilizza il reflog (che scade dopo qualche tempo). Verrà visualizzato "avviso: il registro per" master "torna solo a ...". La soluzione di Rocky funzionerà sempre. git checkoutgit rev-list -n 1 --before="2009-07-27 13:37" master
Mark Nadig

3
Ho modificato la tua risposta perché i backtick sono obsoleti e difficili da leggere. Le conchiglie $(...)sono preferite.
Amedee Van Gasse,

1
@Andy Buon 40 ° compleanno, Andy! (supponendo che questo significhi il 1979-02-26 :))
David Blevins,

123

La soluzione di Andy non funziona per me. Qui ho trovato un altro modo:

git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`

Git: checkout per data


3
Quando eseguo il comando sopra ho error: unknown switch `n'qualche idea su come aggirare questo?
Tim

15

Sembra che tu abbia bisogno di qualcosa del genere: Git checkout in base alla data

In altre parole, si utilizza rev-listper trovare il commit e quindi utilizzare il checkout per ottenerlo effettivamente.

Se non si desidera perdere le modifiche organizzate, la cosa più semplice sarebbe creare un nuovo ramo e impegnarli in quel ramo. Puoi sempre alternare tra i rami.

Modifica: il collegamento non è attivo, quindi ecco il comando:

git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`

2
Ottimo collegamento! Quindi git checkout branch@{date}smette di funzionare quando il reflog scade, ma puoi usarlo git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`.
cdunn2001,

10

A chi preferisce una pipa per comandare la sostituzione

git rev-list -n1 --before=2013-7-4 master | xargs git checkout

9

Nel mio caso l' -n 1opzione non funziona. Su Windows ho scoperto che la seguente sequenza di comandi funziona bene:

git rev-list -1 --before="2012-01-15 12:00" master

Ciò restituisce lo SHA del commit appropriato per la data specificata e quindi:

git checkout SHA

4

La git rev-parsesoluzione proposta da @Andy funziona bene se la data che ti interessa è la data del commit . Se tuttavia desideri effettuare il checkout in base alla data dell'autore , rev-parsenon funzionerà, perché non offre un'opzione per utilizzare quella data per selezionare i commit. Invece, puoi usare quanto segue.

git checkout $(
  git log --reverse --author-date-order --pretty=format:'%ai %H' master |
  awk '{hash = $4} $1 >= "2016-04-12" {print hash; exit 0 }
)

(Se si desidera anche specificare il tempo utilizzato $1 >= "2016-04-12" && $2 >= "11:37"nel predicato awk .)


3

Andando oltre con l' rev-listopzione, se si desidera trovare il commit di unione più recente dal ramo master nel ramo di produzione (come esempio puramente ipotetico):

git checkout `git rev-list -n 1 --merges --first-parent --before="2012-01-01" production`

Avevo bisogno di trovare il codice che era sui server di produzione a partire da una data specifica. Questo l'ho trovato per me.


2

Se si desidera poter tornare alla versione precisa del repository nel momento in cui si esegue una build, è meglio contrassegnare il commit da cui si effettua la build.

Le altre risposte forniscono tecniche per riportare il repository al commit più recente in un ramo a partire da un certo momento, ma potrebbero non essere sempre sufficienti. Ad esempio, se si crea da un ramo e successivamente si elimina il ramo o si crea da un ramo che viene successivamente riformulato, il commit da cui si è creati può diventare "irraggiungibile" in git da qualsiasi ramo corrente. Gli oggetti non raggiungibili in git possono eventualmente essere rimossi quando il repository viene compattato.

Mettere un tag sul commit significa che non diventa mai irraggiungibile, qualunque cosa tu faccia con i rami in seguito (escludendo la rimozione del tag).


Sebbene questo non mi dia la risposta che cerco, merita una buona menzione per sottolineare un aspetto non menzionato finora. Questa potrebbe essere la fonte di problemi che ti impediscono di raggiungere la versione giusta.
manuelvigarcia,

1
git rev-list -n 1 --before="2009-07-27 13:37" origin/master

prendi la stringa stampata (ad esempio XXXX) ed esegui:

git checkout XXXX

2
Questo non è un duplicato della risposta di @bartoszkp? basta aggiungere il riferimento all'origine, dovrebbe essere un commento sull'altra risposta ...
manuelvigarcia,

sì, in effetti quasi, solo chiarendo cosa copiare per chi non sa cosa sia SHA (come me), nel mio caso quel testo non era chiaro e questo è il mio codice dopo aver fondato la soluzione, non copiato, infatti puoi vedere anche le opzioni sono leggermente diverse
Luca C.
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.