Comment commander dans Git par date?

314

Je travaille sur une régression dans le code source. Je voudrais dire à Git: "extraire la source en fonction d'une date / heure paramétrée". Est-ce possible?

J'ai également mis en scène des changements dans ma vue actuelle que je ne veux pas perdre. Idéalement, je voudrais basculer entre la source actuelle et une version qui m'intéresse en fonction d'une date précédente.

Amir Afghani
la source
9
Juste au cas où vous ne le sauriez pas, git bisect est très bien pour trouver des régressions. Je dirais, utilisez la syntaxe {il y a 1 an} comme Andy l'a dit, pour trouver un commit bien connu, puis utilisez-le comme git bisect goodpoint initial .
MatrixFrog
Je pense que c'est un bon cas d'utilisation tags.
Jess

Réponses:

365

Pour conserver vos modifications actuelles

Vous pouvez garder votre travail caché, sans le commettre, avec git stash. Vous seriez alors prêt git stash popà le récupérer. Ou vous pouvez (comme l' a dit Carleeto ) git commitdans une branche distincte.

Commander par date à l'aide de rev-parse

Vous pouvez extraire un commit à une date spécifique en utilisant rev-parsecomme ceci:

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

Vous trouverez plus de détails sur les options disponibles dans le git-rev-parse.

Comme indiqué dans les commentaires, cette méthode utilise le reflog pour trouver le commit dans votre historique. Par défaut, ces entrées expirent après 90 jours . Bien que la syntaxe d'utilisation du reflog soit moins détaillée, vous ne pouvez revenir en arrière que 90 jours.

Commander par date à l'aide de rev-list

L'autre option, qui n'utilise pas le reflog, est d'utiliser rev-listpour obtenir la validation à un moment donné avec:

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

Notez le --first-parent si vous ne voulez que votre historique et non les versions apportées par une fusion. C'est ce que tu veux d'habitude.

Andy
la source
2
@ Rocky Pouvez-vous nous donner plus de détails Rocky? Que saisissez-vous sur la ligne de commande et pourquoi dites-vous que cela ne fonctionne pas? Recevez-vous un message d'erreur?
Andy
8
@Rocky: Le problème est que le paramètre doit être placé entre guillemets, sinon bash sépare les arguments au niveau des espaces. Essayez git co 'master@{2 days ago}'.
Mark Wilden
13
Remarque: selon la distance parcourue, cela peut ne pas fonctionner car il utilise le reflog (qui expire après un certain temps). Vous verrez «avertissement: le journal pour« maître »ne remonte qu'à ...». La solution de Rocky fonctionnera toujours. git checkoutgit rev-list -n 1 --before="2009-07-27 13:37" master
Mark Nadig
3
J'ai modifié votre réponse parce que les backticks sont déconseillés et difficiles à lire. Les sous-coques $(...)sont préférées.
Amedee Van Gasse du
1
@Andy Joyeux 40e anniversaire, Andy! (en supposant que c'est ce que signifiait le 1979-02-26 :))
David Blevins
123

La solution d'Andy ne fonctionne pas pour moi. Ici, j'ai trouvé un autre moyen:

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

Git: paiement par date

Rocheux
la source
3
Lorsque j'exécute la commande ci-dessus, j'ai error: unknown switch `n'des idées pour contourner ce problème?
Tim
15

On dirait que vous avez besoin de quelque chose dans le sens de ceci: Git checkout basé sur la date

En d'autres termes, vous utilisez rev-listpour trouver le commit, puis utilisez checkout pour le récupérer.

Si vous ne voulez pas perdre vos modifications par étapes, la chose la plus simple serait de créer une nouvelle branche et de les valider dans cette branche. Vous pouvez toujours basculer entre les branches.

Edit: Le lien est en panne, voici donc la commande:

git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`
Carl
la source
2
Excellent lien! git checkout branch@{date}Arrête donc de fonctionner lorsque le reflog expire, mais vous pouvez l'utiliser git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`.
cdunn2001 du
10

À ceux qui préfèrent une pipe pour commander la substitution

git rev-list -n1 --before=2013-7-4 master | xargs git checkout
Steven Penny
la source
9

Dans mon cas, l' -n 1option ne fonctionne pas. Sous Windows, j'ai constaté que la séquence de commandes suivante fonctionne correctement:

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

Cela renvoie le SHA du commit approprié pour la date donnée, puis:

git checkout SHA
BartoszKP
la source
4

La git rev-parsesolution proposée par @Andy fonctionne bien si la date qui vous intéresse est la date du commit . Si toutefois vous souhaitez commander en fonction de la date de l' auteur , rev-parsecela ne fonctionnera pas, car il ne propose pas l'option d'utiliser cette date pour sélectionner les validations. Au lieu de cela, vous pouvez utiliser ce qui suit.

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

(Si vous souhaitez également spécifier l'utilisation du temps $1 >= "2016-04-12" && $2 >= "11:37"dans le prédicat awk .)

Diomidis Spinellis
la source
3

Pour aller plus loin avec l' rev-listoption, si vous souhaitez trouver le commit de fusion le plus récent de votre branche principale dans votre branche de production (à titre d'exemple purement hypothétique):

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

J'avais besoin de trouver le code qui était sur les serveurs de production à une date donnée. Cela me l'a trouvé.

egerlach
la source
2

Si vous souhaitez pouvoir revenir à la version précise du référentiel au moment où vous effectuez une génération, il est préférable de baliser le commit à partir duquel vous effectuez la génération.

Les autres réponses fournissent des techniques pour renvoyer le référentiel à la validation la plus récente dans une branche à partir d'un certain temps, mais elles peuvent ne pas toujours suffire. Par exemple, si vous générez à partir d'une branche, puis supprimez la branche ou créez à partir d'une branche qui est ensuite rebasée, la validation à partir de laquelle vous avez créé peut devenir "inaccessible" dans git à partir de n'importe quelle branche actuelle. Les objets inaccessibles dans git peuvent éventuellement être supprimés lorsque le référentiel est compacté.

Mettre une balise sur la validation signifie qu'elle ne devient jamais inaccessible, quoi que vous fassiez avec les branches par la suite (sauf en supprimant la balise).

antlersoft
la source
Bien que cela ne me donne pas la réponse que je recherche, elle mérite une bonne mention pour avoir souligné un aspect non mentionné jusqu'à présent. Cela pourrait être la source de problèmes qui vous empêcheraient d'atteindre la bonne version.
manuelvigarcia
1
git rev-list -n 1 --before="2009-07-27 13:37" origin/master

prenez la chaîne imprimée (par exemple XXXX) et faites:

git checkout XXXX
Luca C.
la source
2
N'est-ce pas un double de la réponse @bartoszkp? il suffit d'ajouter la référence à l'origine, devrait être un commentaire sur l'autre réponse ...
manuelvigarcia
oui, en fait presque, juste clearifiant quoi copier pour qui ne sait pas ce qu'est SHA (comme moi), dans mon cas ce texte n'était pas clair et c'est mon code après avoir trouvé la solution, non copié, en fait vous pouvez voir les options sont également légèrement différentes
Luca C.