2010-06-04 17 views
103

Avrebbe senso per eseguire git rebase preservando il timestamp commesso?git rebase senza cambiare commettere timestamp

Credo che una conseguenza sarebbe che il nuovo ramo non avrà necessariamente date di commit in ordine cronologico. È che teoricamente possibile a tutti? (ad esempio usando i comandi idraulici, solo curioso qui)

Se è teoricamente possibile, allora è possibile in pratica con rebase, non modificare i timestamp?

Si supponga ad esempio ho il seguente albero:

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

Ora, se io REBASE oldbranch sul master, la data dei commit modifiche da febbraio 1984 al giugno 2010. E 'possibile modificare l'azione in modo che il timestamp commettere non è cambiato? Alla fine ottengo così:

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

Tutto ciò avrebbe senso? E 'anche consentito in git di avere una storia in cui un vecchio commit ha un più recente impegnarsi come un genitore?

+2

È strano che la risposta alla domanda sia davvero "non è necessario fare nulla - funziona come impostazione predefinita". Ma ora supponiamo di volere che il commit venga ordinato in ordine di data corretto mentre si fa rebase (che è uno scenario piuttosto naturale se ci si pensa). Ora, non sono riuscito a trovare il modo per ottenerlo e ho postato il mio q come http://stackoverflow.com/questions/12270357/really-flatten-a-git-merge – pfalcon

+1

David menziona un'altra opzione per ripristinare la data del commit: 'git rebase --committer-date-is-author-date SHA'. Vedi [la mia risposta modificata sotto] (http://stackoverflow.com/a/2976598/6309) – VonC

+0

Ho appena scritto una [risposta esauriente] (http://stackoverflow.com/a/30819930/4265352) su un [simile domanda] (http://stackoverflow.com/q/30790645/4265352) il cui autore ha provato le risposte spiegate qui e non ha potuto applicarle in modo soddisfacente. – axiac

risposta

27

Una questione cruciale di Von C ha aiutato a capire cosa sta succedendo: quando il rebase, modifiche timestamp del del committer, ma non l'autore timestamp , che improvvisamente tutto ha un senso. Quindi la mia domanda non era in realtà abbastanza precisa.

La risposta è che rebase in realtà non modifica i timestamp dell'autore (non è necessario fare nulla per questo), che mi si addice perfettamente.

+1

+1 - Ho un alias git in atto (https://coderwall.com/p/euwpig/a-better-git-log) che apparentemente utilizza il timestamp del committer, il che era confuso me. Gitk e git log mostrano entrambi il timestamp dell'autore. – 1615903

102

Aggiornamento giugno 2014: David Fraser menziona in the comments una soluzione dettagliata anche in "Change timestamps while rebasing git branch", utilizzando l'opzione --committer-date-is-author-date (introdotto inizialmente nel gennaio 2009 a commit 3f01ad6

Si noti che l'opzione --committer-date-is-author-date sembra lasciare il timestamp autore ., e impostare il timestamp committer di essere lo stesso del timestamp autore originale, che è ciò che il OP Olivier Verdier volevano

ho trovato l'ultimo commit con la data corretta e fatto:

01.235.164,106174 millions
git rebase --committer-date-is-author-date SHA 

Vedi git am:

--committer-date-is-author-date 

Per impostazione predefinita il comando registra la data del messaggio di posta elettronica, come la data di impegnarsi autore, e usa il tempo di impegnarsi creazione come la data di committer .
Questo consente all'utente di trovano sulla data committer utilizzando lo stesso valore come data autore.


(risposta originale, giugno 2012)

Si potrebbe provare, per un non interattivo rebase

git rebase --ignore-date 

(da questo SO answer)

Questo è passato a git am, che menziona:

--ignore-date 

Per impostazione predefinita il comando registra la data del messaggio di posta elettronica, come la data di impegnarsi autore, e usa il tempo di impegnarsi creazione come la data di committer.
Questo consente all'utente di trovano sulla data autore utilizzando lo stesso valore come data committer.

Per git rebase, questa opzione è "Incompatibile con l'opzione --interattiva".

Dal you can change at will the timestamp of old commit date (con git filter-branch), suppongo è possibile organizzare la vostra storia Git con qualunque commettere ordine di data che si desidera/bisogno, anche set it to the future!.


Come Olivier menzioni nella sua interrogazione, la data autore è mai cambiato da un rebase;
Dal Pro Git Book:

  • L'autore è la persona che originariamente scrisse l'opera,
  • mentre il committer è la persona che lo scorso applicato il lavoro.

Quindi, se si invia una patch a un progetto e uno dei membri principali applica la patch, entrambi ricevono credito.

Per essere extra chiaro, in questo caso, come commenti Olivier:

il --ignore-date fa il contrario di quello che stavo cercando di realizzare!
Vale a dire, cancella timestamp dell'autore e sostituirli con i timestamp impegna!
Quindi la risposta giusta alla mia domanda è:
Non fare nulla, dal momento che git rebase realtà non non cambia timestamp autori per impostazione predefinita.


+0

Interessante sulle date arbitrarie da impegnare. Tuttavia, 'git rebase --ignore-date' non funziona. Cambia le date dei commit successivi. –

+0

@Olivier: strano: hai fatto un rebase interattivo * non *? E tra la data dell'autore e la data del commit, siamo sicuri di monitorare la data "giusta"? – VonC

+1

Grazie VonC, la differenza tra timestamp dell'autore e del committer, questo è ciò che rende tutto improvvisamente chiaro. Ho scritto la risposta alla mia domanda nel mio post, ma sentitevi liberi di adattare la vostra risposta per riflettere questo. –

104

Se hai già incasinato la date (magari con un rebase) impegnarsi e vogliono loro resettare ai loro corrispondenti date autore, è possibile eseguire:

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

+1

Ho appena provato questo, ma nessun effetto. Ho ottenuto l'output seguente: 'WARNING: Ref 'refs/heads/master' è invariato'. Sto usando git versione 1.7.9.5 su Linux (64 bit) –

+13

Mi piacerebbe aggiungere un altro approccio se hai già rovinato ma non voglio ripetere l'intera cronologia: 'git rebase --committer- data-è-autore-data ' In questo modo, git reimposterà la data di commit solo per i commit applicati su (che è probabilmente lo stesso nome di ramo che hai usato quando hai fallito). – speakman

+0

La risposta accettata non ha funzionato nel 2016, ma la risposta di @ speakman ha fatto! –

10

Per impostazione predefinita, git rebase sarà imposta il timestamp del committer al momento in cui viene creato il nuovo commit , ma mantiene intatto il timestamp dell'autore. La maggior parte del tempo, questo è il comportamento desiderato, ma in alcuni scenari, non vogliamo modificare timestamp del committente. Come possiamo riuscirci? Bene, ecco il trucco che faccio di solito.

In primo luogo, assicurarsi che ciascuno dei commit che state per rebase ha un unico messaggio di commit e autore timestamp (Questo è dove si ha bisogno di trucco miglioramenti, attualmente si adatta alle mie esigenze però).

Prima del rebase, registra il timestamp del committer, il timestamp dell'autore e il messaggio di commit di tutti i commit che verranno ridefiniti in un file.

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

Quindi, lasciare che il valore effettivo abbia luogo.

Infine, sostituiamo il timestamp del commit corrente con quello registrato nel file se il messaggio di commit è lo stesso utilizzando 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' 

Se qualcosa va storto, basta checkout git reflog o tutti i refs/original/ arbitri.

Furthormore, puoi fare la stessa cosa con il timestamp dell'autore.

Per esempio, se timestamp dell'autore di alcuni commit sono fuori uso, e senza riorganizzare queste commit, vogliamo solo timestamp dell'autore di mostrare in ordine, poi i seguenti comandi aiuteranno.

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' 
+0

Questo è un grande trucco! Mi ha permesso di riscrivere solo 75 commit anziché 1100+ utilizzando le altre risposte. – audun

+0

Questo è fantastico! C'è un modo per modificare lo script per preservare anche il committer originale? –

+0

@DavidDeMar dovrebbe essere lo stesso, basta cambiare il registro git --pretty per registrare l'e-mail originale e modificare lo script di conseguenza. – weynhamz