git rebase sans changer les horodatages de commit

157

Serait-il judicieux d'exécuter git rebasetout en préservant les horodatages de validation?

Je crois qu'une conséquence serait que la nouvelle succursale n'aura pas nécessairement de dates d'engagement chronologiquement. Est-ce théoriquement possible du tout? (par exemple en utilisant des commandes de plomberie; juste curieux ici)

Si c'est théoriquement possible, alors est-il possible en pratique avec rebase, de ne pas changer les horodatages?

Par exemple, supposons que j'ai l'arbre suivant:

master <jun 2010>
  |
  :
  :
  :     oldbranch <feb 1984>
  :     /
oldcommit <jan 1984>

Maintenant, si je rebase oldbranchsur master, la date du commit change de février 1984 à juin 2010. Est-il possible de changer ce comportement afin que l'horodatage de commit ne soit pas changé? Au final j'obtiendrais ainsi:

      oldbranch <feb 1984>
      /
 master <jun 2010>
    |
    :

Cela aurait-il du sens? Est-il même permis dans git d'avoir un historique où un ancien commit a un commit plus récent en tant que parent?

Olivier Verdier
la source
3
C'est génial que la réponse à la question soit en effet "vous n'avez rien à faire - c'est comme ça que ça marche par défaut". Mais maintenant, supposons que vous souhaitiez que la validation soit triée dans le bon ordre des dates lors du rebase (ce qui est un scénario assez naturel si vous y réfléchissez). Maintenant, je n'ai pas pu trouver comment y parvenir, et j'ai posté mon q sous le nom stackoverflow.com/questions/12270357/really-flatten-a-git-merge
pfalcon
1
David mentionne une autre option pour réinitialiser la date committers: git rebase --committer-date-is-author-date SHA. Voir ma réponse modifiée ci
VonC
Je viens d'écrire une réponse détaillée sur une question similaire dont l'auteur a essayé les réponses expliquées ici et n'a pas pu les appliquer de manière satisfaisante.
axiac

Réponses:

149

Mise à jour juin 2014: David Fraser mentionne dans les commentaires une solution également détaillée dans " Changer les horodatages lors du rebasage de la branche git ", en utilisant l'option --committer-date-is-author-date(introduite initialement en janvier 2009 dans le commit 3f01ad6

Notez que l' --committer-date-is-author-dateoption semble laisser l'horodatage de l'auteur et définir l'horodatage du committer sur le même que l'horodatage de l'auteur original, ce que voulait l' OP Olivier Verdier .

J'ai trouvé le dernier commit avec la date correcte et j'ai fait:

git rebase --committer-date-is-author-date SHA

Voir git am:

--committer-date-is-author-date

Par défaut, la commande enregistre la date du message électronique comme date de l'auteur de la validation et utilise l'heure de création de la validation comme date de validation.
Cela permet à l'utilisateur de mentir sur la date de validation en utilisant la même valeur que la date de l'auteur .


(Réponse originale, juin 2012)

Vous pouvez essayer, pour un rebase non interactif

git rebase --ignore-date

(à partir de cette réponse SO )

Ceci est transmis à git am, qui mentionne:

 --ignore-date

Par défaut, la commande enregistre la date du message électronique comme date de l'auteur de la validation et utilise l'heure de création de la validation comme date de validation.
Cela permet à l'utilisateur de mentir sur la date de l'auteur en utilisant la même valeur que la date de validation.

Pour git rebase, cette option est «Incompatible avec l'option --interactive».

Puisque vous pouvez modifier à volonté l'horodatage de l'ancienne date de validation (avec git filter-branch), je suppose que vous pouvez organiser votre historique Git avec l'ordre de date de validation que vous voulez / dont vous avez besoin, même le définir dans le futur! .


Comme le mentionne Olivier dans sa question, la date de l' auteur n'est jamais modifiée par un rebase;
À partir du livre Pro Git :

  • L'auteur est la personne qui a écrit l'œuvre à l'origine,
  • alors que le committer est la personne qui a appliqué le travail en dernier.

Donc, si vous envoyez un correctif à un projet et que l'un des membres principaux applique le correctif, vous en avez tous les deux un crédit.

Pour être plus clair, dans ce cas, comme le commente Olivier:

le --ignore-datefait le contraire de ce que j'essayais de réaliser !
À savoir, il efface l'horodatage de l'auteur et les remplace par les horodatages de commits!
Donc, la bonne réponse à ma question est:
ne rien faire, car git rebase cela ne change pas les horodatages des auteurs par défaut.


VonC
la source
1
Intéressant sur les dates arbitraires pour s'engager. Cependant, git rebase --ignore-datene fonctionne pas. Il change les dates des commits rebasés.
Olivier Verdier
@Olivier: étrange: avez-vous fait un rebase non interactif? Et entre la date de l'auteur et la date de validation, sommes-nous sûrs de surveiller la «bonne» date?
VonC le
1
Merci VonC, la différence entre l'horodatage de l'auteur et celui du committer, c'est ce qui rend tout soudainement clair. J'ai écrit la réponse à ma question dans mon message, mais n'hésitez pas à adapter votre réponse pour refléter cela.
Olivier Verdier
4
pour être plus précis: cela --ignore-datefait le contraire de ce que j'essayais de réaliser! À savoir, il efface l'horodatage de l'auteur et les remplace par les horodatages de commits! Donc, la bonne réponse à ma question est: ne rien faire, car git rebasecela ne change pas les horodatages des auteurs par défaut.
Olivier Verdier
5
Notez que l' --committer-date-is-author-dateoption semble laisser l'horodatage de l'auteur et définir l'horodatage du committer pour qu'il soit le même que l'horodatage de l'auteur d'origine, ce que voulait Olivier ...
David Fraser
118

Si vous avez déjà foiré les dates de validation (peut-être avec un rebase) et que vous souhaitez les réinitialiser à leurs dates d'auteur correspondantes, vous pouvez exécuter:

git filter-branch --env-filter 'GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE; export GIT_COMMITTER_DATE'

Andy
la source
1
J'ai juste essayé ceci, mais aucun effet. Je suis la sortie folowing: WARNING: Ref 'refs/heads/master' is unchanged. J'utilise la version 1.7.9.5 de git sur Linux (64 bits)
Markus N.9
20
Je voudrais ajouter une autre approche si vous avez déjà foiré mais que vous ne voulez pas parcourir tout l'historique: De git rebase --committer-date-is-author-date <base_branch> cette façon, git réinitialisera la date de validation uniquement pour les commits appliqués sur <base_branch> (qui est probablement le même nom de branche que vous avez utilisé lorsque vous vous êtes trompé).
speakman
La réponse acceptée n'a pas fonctionné en 2016, mais la réponse de @ speakman a fonctionné!
Theodore R. Smith
2
La réponse de @ speakman n'a pas fonctionné en octobre 2016, mais Andy l'a fait!
Amedee Van Gasse
2
Cela ne fonctionne pas sous Windows. J'ai pu le faire fonctionner en utilisant Windows Bash.
vaindil
33

Une question cruciale de Von C m'a aidé à comprendre ce qui se passe: lorsque votre rebase, l' horodatage du committer change, mais pas l' horodatage de l' auteur , qui soudainement prend tout son sens. Ma question n'était donc pas assez précise.

La réponse est que le rebase ne change en fait pas les horodatages de l'auteur (vous n'avez rien à faire pour cela), ce qui me convient parfaitement.

Olivier Verdier
la source
3
+1 - J'ai un alias git en place ( coderwall.com/p/euwpig/a-better-git-log ) qui utilise apparemment l'horodatage du committer, ce qui me déroutait . Gitk et git log affichent tous deux l'horodatage de l'auteur.
1615903
15

Par défaut, git rebase définira l'horodatage du committer sur l'heure à laquelle le nouveau commit est créé, mais gardera l'horodatage de l'auteur intact. La plupart du temps, c'est le comportement souhaité, mais dans certains scénarios, nous ne souhaitons pas non plus modifier l'horodatage du validateur. Comment pouvons-nous y parvenir? Eh bien, voici le truc que je fais habituellement.

Tout d'abord, assurez-vous que chacun des commits que vous êtes sur le point de rebaser a un message de commit unique et un horodatage de l'auteur (c'est là que l'astuce doit être améliorée, actuellement elle répond à mes besoins).

Avant le rebase, enregistrez l'horodatage du committer, l'horodatage de l'auteur et le message de commit de tous les commits qui seront rebasés dans un fichier.

#NOTE: BASE is the commit where your rebase begins
git log --pretty='%ct %at %s' BASE..HEAD > hashlog

Ensuite, laissez le rebase réel avoir lieu.

Enfin, nous remplaçons l'horodatage du committer actuel par celui enregistré dans le fichier si le message de commit est le même en utilisant git filter-branch.

 git filter-branch --env-filter '__date=$(__log=$(git log -1 --pretty="%at %s" $GIT_COMMIT); grep -m 1 "$__log" ../../hashlog | cut -d" " -f1); test -n "$__date" && export GIT_COMMITTER_DATE=$__date || cat'

Si quelque chose ne va pas, vérifiez simplement git reflogou toutes les refs/original/références.

De plus, vous pouvez faire la même chose pour l'horodatage de l'auteur.

Par exemple, si l'horodatage de l'auteur de certains commits est dans le désordre, et sans réorganiser ces commits, nous voulons juste que l'horodatage de l'auteur s'affiche dans l'ordre, alors les commandes suivantes vous aideront.

git log --pretty='%at %s' COMMIT1..COMMIT2 > hashlog
join -1 1 -2 1 <(cat hashlog | cut -f 1 | sort -nr | awk '{ print NR" "$1 }') <(cat hashlog | awk '{ print NR" "$0 }') | cut -d" " -f2,4- > hashlog_
mv hashlog_ hashlog
git filter-branch --env-filter '__date=$(__log=$(git log -1 --pretty="%s" $GIT_COMMIT); grep -m 1 "$__log" ../../hashlog | cut -d" " -f1); test -n "$__date" && export GIT_AUTHOR_DATE=$__date || cat'
Weynhamz
la source
C'est une super astuce! Cela m'a permis de ne réécrire que 75 commits au lieu de 1100+ en utilisant les autres réponses.
audun
C'est fantastique! Existe-t-il un moyen de modifier le script pour conserver également le committer d'origine?
David DeMar
@DavidDeMar devrait être le même, il suffit de changer le git log --pretty pour enregistrer l'e-mail d'origine et de modifier le script en conséquence.
weynhamz