Comment puis-je obtenir la différence entre tous les commits qui se sont produits entre deux dates avec Git?


117

Ou juste tous les commits intervenus entre deux dates? Dans SVN, vous pouvez faire quelque chose comme

svn diff -r{date}:{date}

pour le faire! Je n'arrive pas à trouver un équivalent Git à ça.

Plus précisément, je cherche à écrire un script pour envoyer des courriels quotidiens avec tout le code engagé ce jour-là et par qui.

Réponses:


160

Vous pourriez utiliser git whatchanged --since="1 day ago" -p

Il faut aussi un --untilargument.

Docs


Merci! C'était juste ce que je voulais, il prend même le paramètre --committer, bien que ce ne soit pas répertorié dans sa documentation! aussi, 'git whatchanged' n'apparaissait pas dans 'git help'! Je ne sais pas pourquoi ... merci encore.
Chris

5
Vous devriez en faire votre réponse choisie pour que Seth reçoive du karma.
Scott

18
@brbob Je sais que cela a été répondu il y a longtemps, mais juste pour quelqu'un qui tombe dessus (comme je l'ai fait) Git help dit: The command is kept primarily for historical reasons; fingers of many people who learned Git long before git log was invented by reading Linux kernel mailing list are trained to type it. Donc, la documentation encourage l'utilisation git logau lieu de git whatchanged; cette dernière commande utilise également l'option --no-merge de git log, donc ils produisent les mêmes résultats.
Ramses

2
git whatchanged est une sorte d'alias de la commande git log selon la doc de git log
Vincent

2
git whatchangedest obsolète à partir de la dernière version actuelle 2.21.0. Tout ce qui est git whatchangedréalisé peut être réalisé git loget n'est conservé que pour des raisons historiques. Voir les détails git-scm.com/docs/git-whatchanged/2.21.0
Devy

60

Les suggestions précédentes présentent quelques inconvénients. En gros, je cherchais quelque chose d'équivalent cvs diff -D"1 day ago" -D"2010-02-29 11:11". En collectant de plus en plus d'informations, j'ai trouvé une solution.

Les choses que j'ai essayées:

  • git whatchanged --since="1 day ago" -pd' ici

    Mais cela donne une différence pour chaque commit, même s'il y a plusieurs commits dans un fichier. Je sais que "date" est un peu un concept vague dans git , je pensais qu'il devait y avoir un moyen de le faire.

  • git diff 'master@{1 day ago}..masterdonne un avertissement warning: Log for 'master' only goes back to Tue, 16 Mar 2010 14:17:32 +0100.et n'affiche pas tous les diffs.

  • git format-patch --since=yesterday --stdout ne donne rien pour moi.

  • revs=$(git log --pretty="format:%H" --since="1 day ago");git diff $(echo "$revs"|tail -n1) $(echo "$revs"|head -n1) fonctionne en quelque sorte, mais semble compliqué et ne se limite pas à la branche actuelle.

Finalement:

Curieusement, git-cvsserver ne prend pas en charge "cvs diff -D" (sans cela, il est documenté quelque part).


4
+1 pour git rev-list, ce qui a largement contribué à résoudre le problème très similaire que je voyais.
me_and

Cela ne devrait pas être la réponse acceptée, celle de seth est plus concise et correcte.
ctford

6
@ctford, à mon avis, ce n'est pas correct. Il peut signaler plusieurs diffs pour un fichier, pas une diff par fichier comme diff svn / cvs.
Weidenrinde

1
@Weidenrinde +1, c'est beaucoup plus intelligent
rostamn739

1
La git diff 'master@{1 day ago}..mastersyntaxe signifie "vérifier le reflog et déterminer où branchemaster utilisé pour pointer dans votre référentiel local 1 day ago ". Plus précisément, n'utilisera pas l'historique de validation réel de la branche actuelle master. C'est très rarement ce que vous voulez vraiment.
Mikko Rantalainen

22

"date" est un concept un peu vague dans git. Un commit aura une date d'auteur qui peut être bien dans le passé avant que quelqu'un ne tire / valide le commit dans son référentiel, aussi le commit peut être rebasé et mis à jour pour être au-dessus d'un commit apparemment plus récent.

Un commit a également une date de commit qui est mise à jour si un commit est rebasé ou modifié de quelque manière que ce soit. Ces commits sont plus susceptibles d'être dans une sorte d'ordre chronologique, mais vous êtes toujours à la merci du committer ayant l'heure correcte définie sur son ordinateur et même ainsi, un commit non modifié peut rester indéfiniment sur une branche de fonctionnalité d'un référentiel distant avant fusionné dans la branche maître d'un référentiel central.

Ce qui est probablement le plus utile à vos fins est la date de reflog sur le référentiel particulier en question. Si vous avez activé les reflogs par branche (voir git config core.logAllRefUpdates), vous pouvez utiliser leref@{date} syntaxe pour faire référence à l'emplacement d'une branche à un moment donné.

Par exemple

git log -p master@{2009-07-01}..master@{now}

Vous pouvez également utiliser des descriptions `` floues '' comme:

git log -p "master@{1 month ago}..master@{yesterday}"

Ces commandes afficheront tous les commits qui sont «apparus» dans la branche donnée du référentiel quel que soit leur «âge» en fonction de leur auteur et des dates de livraison.

Notez que le reflog par branche est spécifique à un référentiel, donc si vous exécutez la commande log sur un clone et que vous ne tirez pas pendant (disons) un mois, puis extrayez toutes les modifications du mois dernier en une seule fois, puis toutes les modifications du mois dernier apparaîtront dans une @{1 hour ago}..@{now}plage. Si vous êtes en mesure d'exécuter la commande log sur le répertoire «central» vers lequel les gens poussent, alors il peut faire ce que vous voulez.


Très bonne rédaction et bonne réponse à la question posée ... mais je pense que cela n'aiderait pas beaucoup à faire ce que brbob voulait.
Jakub Narębski le

Cela dépend, cela pourrait aider s'il veut réellement analyser ce qui a été poussé vers une certaine branche sur un certain référentiel central et que la commande log a été exécutée sur ce référentiel. Je pense qu'un montage est en ordre ...
CB Bailey

"date de validation qui est mise à jour si un commit est rebasé ou modifié de quelque manière que ce soit", en fait la date n'est jamais changée; le commit entier est remplacé par un autre commit (bien que l'arbre puisse être supposé être le même).
hasen

2
@hasen j: Techniquement, vous avez raison. Les validations sont immuables. Lorsque vous rebasez ou modifiez un commit et créez un nouveau commit, le message de commit existant, les détails de l'auteur et la date de l'auteur sont souvent copiés de l'ancien commit, c'est comme si vous mettiez à jour le commit avec un nouvel identifiant et une nouvelle date de commit.
CB Bailey

Notez que la @{time spec}syntaxe fait toujours référence à votre reflog local . Il ne fait pas référence à l'historique de validation réel (DAG). Si vous ne comprenez pas la différence, n'utilisez pas cette syntaxe!
Mikko Rantalainen

14
git diff --stat @{2013-11-01}..@{2013-11-30}

ou

git diff --stat @{2.weeks.ago}..@{last.week}

Cela dépend-il du reflog? Parce que si c'est le cas, vous ne pouvez pas réellement l'utiliser si le dépôt dans lequel vous exécutez cette commande est plus récent (c'est-à-dire fraîchement cloné) que l'historique de validation qu'il contient.

2
Oui, cela dépend totalement du reflog. Et oui, cela ne fonctionne que dans l'historique des copies locales, mais c'est un peu une commande pratique.
AA.

1
Oui, je suis tout à fait d'accord pour dire que c'est pratique, tant que vous avez des entrées de reflog suffisamment anciennes pour le prendre en charge.

Merci AA. En utilisant votre réponse, j'ai pu faire: git annotate --stat .. @ {2017-08-8} filename | less; git annotate --stat .. @ {5.days.ago} filename; afin que je puisse voir les changements dans le contexte.
Chris le

Notez que la @{time spec}syntaxe fait toujours référence à votre reflog local . Il ne fait pas référence à l'historique de validation réel (DAG). Si vous ne comprenez pas la différence, n'utilisez pas cette syntaxe!
Mikko Rantalainen

4

Peut-être

$ git format-patch --committer=<who> --since=yesterday --stdout

est ce que vous voulez (avec ou sans '--stdout')?


1
Question rapide, est-ce que - depuis utilise la date de validation?
CB Bailey

3

Je pense que la solution générale est d'utiliser:

git rev-list -n1 --first-parent --until=<a date string> <a ref>

Sans --first-parent, vous pourriez obtenir un commit d'une branche qui a ensuite été fusionnée a refmais qui n'a pas été fusionnée depuis a date string.

Voici une alternative utilisant --childrenet grepau lieu de -n1:

mlm_git_ref_as_of() {
    # # Examples #
    #
    # Show all commits between two dates:
    #
    #     git log $(mlm_git_ref_as_of '2012-05-21 09:00:00-0400')..$(mlm_git_ref_as_of '2012-05-21 17:00:00-0400')
    #
    # Show diffs of all commits between two dates:
    #
    #     git diff $(mlm_git_ref_as_of '2012-05-21 09:00:00-0400')..$(mlm_git_ref_as_of '2012-05-21 17:00:00-0400')
    local as_of="$1"
    local ref="${2:-HEAD}"
    # Get the most recent commit (--children, grep -v ' ') that was on
    # the given branch ($ref, --first-parent) as of a given date
    # ($as_of)
    git rev-list --children --first-parent --until="$as_of" "$ref" | grep -v ' '
}

Je n'étais pas familier avec git whatchangedavant de lire ce Q&R, mais il donne des résultats très différents pour moi, donc je ne suis pas sûr de ce que cela fait.


3

Un autre moyen simple d'obtenir une différence de tous les changements depuis une certaine date consiste simplement à trouver le premier commit Xqui s'est produit à cette date ou après, puis à utiliser

git diff X

Cela présente l'avantage de ne pas dépendre des entrées de reflog dans un nouveau clone, contrairement au

git diff <reference>@{n}..
git log <reference>@{n}..

solutions dans


3

Pour observer les changements de fichiers Git de date en date sur votre branche, utilisez la formule suivante:

  1. vérifiez votre succursale.
  2. extraire et mettre à jour les modifications à partir du référentiel distant
  3. regarder les fichiers diff d'une date à l'autre

Formule :

git checkout <branch>
git pull
git diff --stat @{fromDate}..@{toDate}

Faites attention à ce que les dates soient au format AAAA-MM-JJ :

git diff --stat @{2019-08-20}..@{2019-08-21}

Si vous souhaitez observer les changements sur un fichier spécifique dans une plage de temps spécifique (regardez les différences dans le code), naviguez simplement dans le fichier actuel:

Exemple :

git diff @{2019-01-01}..@{2019-01-02} ~/dev/myApp/package.json

2

C'est plus une réponse amusante, car il existe probablement une meilleure solution. Cela affichera tous les hachages de validation pour aujourd'hui.

git log --pretty="format:%H %ai" | grep `date +"%Y-%m-%d"` | awk {'print $1'}`

; ·)


2

Vous pouvez également utiliser git-format-patch pour préparer des correctifs (diffs) et les envoyer par e-mail.

Utilisez les options [depuis] ou [plage de révision] pour spécifier la plage de validation.


0

Je vais vous expliquer comment je le fais: git logcar une date vous donne des hachages de validation pour la branche actuelle. Ensuite, j'utilise simplement quelque chose comme git diff 8fgdfg8..565k4l5qui me donne une différence appropriée agrégée par fichiers. J'espère que cela aide, mais pas beaucoup testé

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.