Como posso obter a diferença entre todos os commits que ocorreram entre duas datas com Git?

116

Ou apenas todos os commits que ocorreram entre duas datas? No SVN, você poderia fazer algo como

svn diff -r{date}:{date}

para fazer isso! Não consigo encontrar um Git equivalente a isso.

Especificamente, estou tentando escrever um script para enviar e-mails diários com todo o código confirmado naquele dia e por quem.

Chris
fonte

Respostas:

159

Você poderia usar git whatchanged --since="1 day ago" -p

Também requer um --untilargumento.

Docs

seth
fonte
obrigado! Estava certo o que eu queria, até leva o parâmetro --committer, embora isso não esteja listado em sua documentação! também, 'git whatchanged' não apareceu em 'git help'! Não tenho ideia do porquê ... obrigado novamente.
Chris
5
Você deve fazer desta a sua resposta escolhida para que seth receba algum carma.
Scott
18
@brbob Eu sei que isso foi respondido há muito tempo, mas apenas para alguém que se depara com isso (como eu) Git help diz: 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. Então, a documentação incentiva o uso em git logvez de git whatchanged; este último comando também usa a opção --no-merge do git log, então eles exibem os mesmos resultados.
Ramses
2
git whatchanged é uma espécie de alias do comando git log de acordo com o documento do git log
Vincent
2
git whatchangedestá obsoleto a partir da versão atual mais recente 2.21.0. Tudo git whatchangedalcançado pode ser alcançado git loge é preservado apenas por razões históricas. Veja detalhes em git-scm.com/docs/git-whatchanged/2.21.0
Devy
60

As sugestões anteriores têm algumas desvantagens. Basicamente, eu estava procurando algo equivalente a cvs diff -D"1 day ago" -D"2010-02-29 11:11". Enquanto colhia mais e mais informações, encontrei uma solução.

Coisas que eu tentei:

  • git whatchanged --since="1 day ago" -pa partir daqui

    Mas isso dá uma diferença para cada commit, mesmo se houver vários commits em um arquivo. Eu sei que "encontro" é um conceito um pouco vago no git , pensei que deve haver alguma maneira de fazer isso.

  • git diff 'master@{1 day ago}..masterdá alguns avisos warning: Log for 'master' only goes back to Tue, 16 Mar 2010 14:17:32 +0100.e não mostra todos os diffs.

  • git format-patch --since=yesterday --stdout não dá nada para mim.

  • revs=$(git log --pretty="format:%H" --since="1 day ago");git diff $(echo "$revs"|tail -n1) $(echo "$revs"|head -n1) funciona de alguma forma, mas parece complicado e não se restringe ao ramo atual.

Finalmente:

Curiosamente, git-cvsserver não suporta "cvs diff -D" (sem isso está documentado em algum lugar).

Weidenrinde
fonte
4
+1 para git rev-list, que ajudou muito a resolver o problema muito semelhante que eu estava vendo.
me_e
Essa não deveria ser a resposta aceita, a de seth é mais concisa e correta.
ctford
6
@ctford, a meu ver, não é correto. Ele pode relatar várias diferenças para um arquivo, não uma diferença por arquivo como svn / cvs diff.
Weidenrinde de
1
@ Weidenrinde +1, isso é muito mais inteligente
rostamn739
1
A git diff 'master@{1 day ago}..mastersintaxe significa "verifique o reflog e descubra para onde o branch mastercostumava apontar em seu repositório local 1 day ago ". Especificamente, não usará o histórico de commits real do branch atual master. Isso raramente é o que você realmente deseja.
Mikko Rantalainen
22

"data" é um conceito um pouco solto no git. Um commit terá uma data de autor que pode ser algum tempo no passado antes de alguém realmente puxar / submeter o commit em seu repositório, também o commit pode ser rebaseado e atualizado para estar no topo de um commit aparentemente mais recente.

Um commit também tem uma data de commit que é atualizada se um commit for rebatizado ou alterado de alguma forma. É mais provável que esses commits estejam em algum tipo de ordem cronológica, mas você ainda está à mercê do committer com a hora correta definida em seu computador e, mesmo assim, um commit não modificado pode ficar em um branch de recurso em um repositório remoto indefinidamente antes sendo mesclado no branch master de um repositório central.

O que provavelmente é mais útil para seus propósitos é a data de reflog no repositório particular em questão. Se você tiver reflogs por branch habilitado (consulte Recursos git config core.logAllRefUpdates), então você pode usar a ref@{date}sintaxe para se referir a onde um branch estava em um determinado momento.

Por exemplo

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

Você também pode usar descrições 'difusas' como:

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

Esses comandos mostrarão todos os commits que 'apareceram' em um determinado ramo do repositório, independentemente de quão 'antigos' eles realmente são de acordo com seu autor e datas de commit.

Observe que o reflog por ramo é específico para um repositório, portanto, se você estiver executando o comando log em um clone e não puxar por (digamos) um mês, extraia todas as alterações do último mês de uma vez, então, todas as alterações do último mês aparecerão em um @{1 hour ago}..@{now}intervalo. Se você for capaz de executar o comando log no repositório 'central' para o qual as pessoas enviam, então ele pode fazer o que você quiser.

CB Bailey
fonte
Muito boa redação e boa resposta à pergunta declarada ... mas acho que não ajudaria muito em fazer o que o brbob pretendia.
Jakub Narębski
Depende, pode ajudar se ele realmente deseja analisar o que foi enviado para um determinado ramo em um determinado repositório central e o comando de log foi executado nesse repositório. Acho que uma edição está em ordem ...
CB Bailey
"data de confirmação que é atualizada se uma confirmação for realocada ou alterada de qualquer forma", na verdade a data nunca é alterada; todo o commit é substituído por outro commit (embora a árvore possa supostamente ser a mesma).
hasen
2
@hasen j: Tecnicamente, você está correto. Os commits são imutáveis. Quando você rebase ou altera um commit e cria um novo commit, a mensagem de commit existente, os detalhes do autor e a data do autor são freqüentemente copiados do commit antigo, então é como se você estivesse atualizando o commit com um novo id de commit e data de commit.
CB Bailey,
Note que a @{time spec}sintaxe refere-se sempre o seu local de reflog . Não se refere ao histórico de confirmação real (DAG). Se você não entende a diferença, não use esta sintaxe!
Mikko Rantalainen
14
git diff --stat @{2013-11-01}..@{2013-11-30}

ou

git diff --stat @{2.weeks.ago}..@{last.week}
AA.
fonte
Isso depende do reflog? Porque se isso acontecer, então você não pode realmente usar isso se o repo no qual você está executando este comando for mais recente (ou seja, recém-clonado) do que o histórico de commit que ele contém.
2
Sim, isso depende totalmente do reflog. E sim, isso só funciona no histórico de cópia local, mas é um comando um pouco conveniente.
AA.
1
Sim, definitivamente concordo que é conveniente, contanto que você tenha entradas de reflog antigas o suficiente para suportá-lo.
Obrigado AA. Usando sua resposta, consegui fazer: git annotate --stat .. @ {2017-08-8} nome do arquivo | less; git annotate --stat .. @ {5.days.ago} nome do arquivo; para que eu possa ver as mudanças no contexto.
Chris
Note que a @{time spec}sintaxe refere-se sempre o seu local de reflog . Não se refere ao histórico de confirmação real (DAG). Se você não entende a diferença, não use esta sintaxe!
Mikko Rantalainen
4

Possivelmente

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

é o que você quer (com ou sem '--stdout')?

Jakub Narębski
fonte
1
Pergunta rápida, já que usa a data de confirmação?
CB Bailey
3

Acredito que a solução geral seja usar:

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

Sem --first-parent, você pode obter um commit de um branch que mais tarde foi mesclado, a refmas não havia sido mesclado até então a date string.

Aqui está uma alternativa usando --childrene em grepvez 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 ' '
}

Eu não estava familiarizado com isso git whatchangedantes de ler este P&R, mas dá resultados muito diferentes para mim, então não tenho certeza do que está fazendo.

Matt McClure
fonte
3

Outra maneira simples de obter uma comparação de todas as alterações desde uma determinada data é simplesmente encontrar o primeiro commit Xque ocorreu nessa data ou após, então usar

git diff X

Isso tem a vantagem de não depender de entradas de reflog em um clone novo, ao contrário do

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

soluções em

Comunidade
fonte
2

Esta é uma resposta mais engraçada, porque provavelmente existe uma maneira melhor. Isso mostrará todos os hashes de commit de hoje.

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

; ·)

gahooa
fonte
2

Você também pode usar git-format-patch para preparar patches (diffs) e enviá-los por e-mail.

Use as opções [desde] ou [intervalo de revisão] para especificar o intervalo de commits.

Nick Dandoulakis
fonte
2

Para observar as mudanças dos arquivos Git de uma data para outra em seu branch, use a seguinte fórmula:

  1. verifique sua filial.
  2. puxar e atualizar as mudanças do repositório remoto
  3. assistir a arquivos diff de data a intervalo de datas

Fórmula :

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

Observe que as datas estão no formato AAAA-MM-DD :

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

Se você gostaria de observar as mudanças em um arquivo específico em um intervalo de tempo específico (observe a diferença no código), basta navegar no arquivo atual:

Exemplo :

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

Vou colocar a maneira que faço: git logpor uma data dá a você commit hashes para o branch atual. Então eu apenas uso algo como o git diff 8fgdfg8..565k4l5que me dá a diferença adequada agregada por arquivos. Espero que isso ajude, mas não testei muito

rostamn739
fonte