git rebase sem alterar os timestamps de confirmação

157

Faria sentido executar git rebaseenquanto preservava os carimbos de data / hora de confirmação?

Acredito que uma conseqüência seria que o novo ramo não terá necessariamente datas de confirmação cronologicamente. Isso é teoricamente possível? (por exemplo, usando comandos de encanamento; apenas curioso aqui)

Se for teoricamente possível, na prática com rebase, é possível não alterar os carimbos de data / hora?

Por exemplo, suponha que eu tenha a seguinte árvore:

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

Agora, se eu rebase oldbranchem master, a data de confirmar as alterações de fevereiro 1984 a junho de 2010. É possível alterar esse comportamento para que a cometer timestamp não é alterado? No final, eu obteria assim:

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

Isso faria algum sentido? É permitido ao git ter um histórico em que um commit antigo tenha um commit mais recente como pai?

Olivier Verdier
fonte
3
É estranho que a resposta para a pergunta seja realmente "você não precisa fazer nada - é assim que funciona, por padrão". Mas agora suponha que você queira que o commit seja classificado em ordem de data adequada ao fazer o rebase (o que é um cenário bastante natural, se você pensar bem). Agora, eu não era capaz de encontrar a forma de alcançar isso, e postei meu q como stackoverflow.com/questions/12270357/really-flatten-a-git-merge
pfalcon
1
David menciona uma outra opção para redefinir data committer: git rebase --committer-date-is-author-date SHA. Veja minha resposta editada abaixo
VonC
Acabei de escrever uma resposta extensa sobre uma pergunta semelhante, cujo autor tentou as respostas explicadas aqui e não conseguiu aplicá-las de maneira satisfatória.
axiac

Respostas:

149

Atualização em junho de 2014: David Fraser menciona nos comentários uma solução também detalhada em " Alterar carimbos de data e hora ao refazer a ramificação do git ", usando a opção --committer-date-is-author-date(introduzida inicialmente em janeiro de 2009 no commit 3f01ad6

Observe que a --committer-date-is-author-dateopção parece deixar o carimbo de data / hora do autor e defina o carimbo de data / hora do committer para o mesmo que o carimbo de data / hora do autor original, que é o que o OP Olivier Verdier queria.

Encontrei o último commit com a data correta e fiz:

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

Veja git am:

--committer-date-is-author-date

Por padrão, o comando registra a data da mensagem de email como a data do autor de confirmação e usa a hora da criação da confirmação como a data do commit.
Isso permite ao usuário mentir sobre a data do commit usando o mesmo valor da data do autor .


(Resposta original, junho de 2012)

Você poderia tentar, para um não-interativo rebase

git rebase --ignore-date

(desta resposta SO )

Isso é passado para git am, que menciona:

 --ignore-date

Por padrão, o comando registra a data da mensagem de email como a data do autor de confirmação e usa a hora da criação da confirmação como a data do commit.
Isso permite ao usuário mentir sobre a data do autor usando o mesmo valor da data do autor.

Para git rebase, esta opção é "Incompatível com a opção --interactive".

Como você pode alterar o carimbo de data e hora da data de confirmação antiga (com git filter-branch), suponho que você possa organizar seu histórico do Git com a ordem da data de confirmação que desejar / precisar, até mesmo configurá-la para o futuro! .


Como Olivier menciona em sua pergunta, a data do autor nunca é alterada por uma nova reformulação;
Do livro Pro Git :

  • O autor é a pessoa que originalmente escreveu o trabalho,
  • enquanto que o responsável é a pessoa que aplicou o trabalho pela última vez.

Portanto, se você enviar um patch para um projeto e um dos membros principais aplicar o patch, os dois receberão crédito.

Para ser mais claro, neste caso, como comenta Olivier:

o --ignore-datefaz o oposto do que eu estava tentando alcançar !
Ou seja, apaga o registro de data e hora do autor e o substitui pelo registro de data e hora de confirmação!
Portanto, a resposta certa para minha pergunta é:
não faça nada, pois git rebase na verdade não altera os carimbos de data / hora dos autores por padrão.


VonC
fonte
1
Interessante sobre as datas arbitrárias para cometer. No entanto, git rebase --ignore-datenão funciona. Ele altera as datas dos confirmados reformulados.
Olivier Verdier
@ Olivier: estranho: você fez uma rebase não interativa? E entre a Data do autor e a Data do emissor, temos a certeza de monitorar a data "correta"?
VonC
1
Obrigado VonC, a diferença entre o carimbo de data e hora do autor e do committer, é isso que torna tudo de repente claro. Escrevi a resposta para minha pergunta no meu post, mas sinta-se à vontade para adaptar sua resposta para refletir isso.
precisa
4
para ser mais preciso: o --ignore-datefaz o oposto do que eu estava tentando conseguir! Ou seja, apaga o registro de data e hora do autor e o substitui pelo registro de data e hora de confirmação! Portanto, a resposta certa para minha pergunta é: não faça nada, pois git rebasena verdade não altera os carimbos de data / hora dos autores por padrão.
Olivier Verdier
5
Note que a --committer-date-is-author-dateopção parece deixar o timestamp autor, e definir o timestamp committer ser o mesmo que o timestamp autor original, que é o que Olivier queria ...
David Fraser
118

Se você já estragou as datas de confirmação (talvez com uma nova reformulação) e deseja redefini-las para as datas de autor correspondentes, é possível executar:

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

Andy
fonte
1
Eu apenas tentei isso, mas sem efeito. Eu tenho a saída folowing: WARNING: Ref 'refs/heads/master' is unchanged. Eu estou usando git versão 1.7.9.5 no Linux (64 bits)
Markus N.
20
Gostaria de adicionar outra abordagem, se você já errou, mas não deseja percorrer toda a história: git rebase --committer-date-is-author-date <base_branch> Dessa forma, o git redefinirá a data de confirmação apenas para as confirmações aplicadas em <base_branch> (que provavelmente é o mesmo nome do ramo que você usou quando estragou tudo).
speakman 17/06/2014
A resposta aceita não funcionou em 2016, mas a resposta do @ speakman funcionou!
Theodore R. Smith
2
A resposta de @ speakman não funcionou em outubro de 2016, mas Andy funcionou!
Amedee Van Gasse
2
Isso não funciona no Windows. Consegui fazê-lo funcionar usando o Windows Bash.
vaindil
33

Uma pergunta crucial de Von C me ajudou a entender o que está acontecendo: quando a sua recuperação, o carimbo de data / hora do emissor muda, mas não o carimbo de data / hora do autor , que de repente tudo faz sentido. Então, minha pergunta não foi realmente precisa o suficiente.

A resposta é que o rebase na verdade não altera os carimbos de data / hora do autor (você não precisa fazer nada por isso), o que me convém perfeitamente.

Olivier Verdier
fonte
3
+1 - Eu tenho um alias do git em vigor ( coderwall.com/p/euwpig/a-better-git-log ) que aparentemente usa o carimbo de data / hora do committer, o que estava me confundindo. Gitk e git log mostram o carimbo de data / hora do autor.
1615903
15

Por padrão, o git rebase definirá o registro de data e hora do commit para o horário em que o novo commit é criado, mas mantém o registro de data e hora do autor intacto. Na maioria das vezes, esse é o comportamento desejado, mas em alguns cenários, também não queremos alterar o carimbo de data / hora do commiter. Como podemos conseguir isso? Bem, aqui está o truque que costumo fazer.

Primeiro, verifique se cada um dos commits que você está prestes a reformular possui uma mensagem de commit e um carimbo de data / hora exclusivos do autor (é aqui que o truque precisa de melhorias, mas atualmente atende às minhas necessidades).

Antes da rebase, registre o carimbo de data / hora do autor, o carimbo de data do autor e confirme a mensagem de todas as confirmações que serão rebaseadas em um arquivo.

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

Então, deixe a rebase real ocorrer.

Por fim, substituímos o registro de data e hora do consolidador atual pelo registrado no arquivo se a mensagem de confirmação for a mesma usando 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 algo der errado, faça o checkout git reflogou todos os refs/original/árbitros.

Além disso, você pode fazer o mesmo com o registro de data e hora do autor.

Por exemplo, se o carimbo de data / hora do autor de algumas confirmações estiver fora de ordem e sem reorganizá-las, queremos que o carimbo de data / hora do autor seja exibido em ordem, os seguintes comandos ajudarão.

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
fonte
Este é um ótimo truque! Ele me permitiu reescrever 75 confirmações, em vez de 1100+, de usar as outras respostas.
Audun
Isto é fantástico! Existe uma maneira de modificar o script para também preservar o committer original também?
David DeMar 31/01
O @DavidDeMar deve ser o mesmo, basta alterar o git log --pretty para registrar o email original e modificar o script de acordo.
27418 weynhamz