Estou convertendo tudo para o Git para meu uso pessoal e encontrei algumas versões antigas de um arquivo já no repositório. Como comprometê-lo com o histórico na ordem correta, de acordo com a "data de modificação" do arquivo, para que eu tenha um histórico preciso do arquivo?
Foi-me dito que algo assim funcionaria:
git filter-branch --env-filter="GIT_AUTHOR_DATE=... --index-filter "git commit path/to/file --date " --tag-name-filter cat -- --all
git
version-control
repository
git-commit
desconhecido
fonte
fonte
git commit --date="xxx day ago" -m "yyy"
é suficiente para esse fim, se alguém estiver se perguntando.Respostas:
O conselho que você recebeu é falho. Configurar incondicionalmente GIT_AUTHOR_DATE em um
--env-filter
reescreveria a data de cada confirmação. Além disso, seria incomum usar o git commit dentro--index-filter
.Você está lidando com vários problemas independentes aqui.
Especificando datas diferentes de "agora"
Cada confirmação tem duas datas: a data do autor e a data do confirmador. Você pode substituir cada um deles fornecendo valores por meio das variáveis de ambiente GIT_AUTHOR_DATE e GIT_COMMITTER_DATE para qualquer comando que grava uma nova confirmação. Veja “Formatos de Data” no git-commit (1) ou abaixo:
O único comando que grava uma nova confirmação durante o uso normal é git commit . Ele também possui uma
--date
opção que permite especificar diretamente a data do autor. Seu uso antecipado incluigit filter-branch --env-filter
também as variáveis de ambiente mencionadas acima (elas fazem parte do "env" após o qual a opção é nomeada; consulte "Opções" em git-filter-branch (1) e o comando "encanamento" subjacente git-commit -árvore (1) .Inserindo um arquivo em um único histórico ref
Se o seu repositório é muito simples (ou seja, você possui apenas uma ramificação, sem tags), provavelmente poderá usar o git rebase para fazer o trabalho.
Nos comandos a seguir, use o nome do objeto (hash SHA-1) da confirmação em vez de "A". Não se esqueça de usar um dos métodos de "substituição de data" ao executar o git commit .
Se você deseja atualizar A para incluir o novo arquivo (em vez de criar um novo commit onde foi adicionado), use em
git commit --amend
vez degit commit
. O resultado ficaria assim:O procedimento acima funciona, desde que você possa nomear o commit que deve ser o pai do seu novo commit. Se você realmente deseja que seu novo arquivo seja adicionado por meio de um novo commit raiz (sem pais), precisará de algo um pouco diferente:
git checkout --orphan
é relativamente novo (Git 1.7.2), mas existem outras maneiras de fazer a mesma coisa que funcionam em versões mais antigas do Git.Inserir um arquivo em um histórico multi- referência
Se seu repositório é mais complexo (ou seja, possui mais de uma referência (ramificações, tags, etc.)), provavelmente você precisará usar o git filter-branch . Antes de usar o git filter-branch , você deve fazer uma cópia de backup de todo o seu repositório. Um arquivo tar simples de toda a sua árvore de trabalho (incluindo o diretório .git) é suficiente. O git filter-branch faz refs de backup, mas geralmente é mais fácil se recuperar de uma filtragem não muito correta apenas excluindo seu
.git
diretório e restaurando-o do seu backup.Nota: Os exemplos abaixo usam o comando de nível inferior em
git update-index --add
vez degit add
. Você poderia usar o git add , mas primeiro seria necessário copiar o arquivo de algum local externo para o caminho esperado (--index-filter
executa seu comando em um GIT_WORK_TREE temporário que está vazio).Se você deseja que seu novo arquivo seja adicionado a cada confirmação existente, você pode fazer o seguinte:
Não vejo realmente nenhuma razão para alterar as datas dos commits existentes
--env-filter 'GIT_AUTHOR_DATE=…'
. Se você o usasse, o tornaria condicional para que ele reescrevesse a data de cada confirmação.Se você deseja que seu novo arquivo apareça apenas nas confirmações após alguma confirmação existente ("A"), faça o seguinte:
Se você deseja que o arquivo seja adicionado por meio de uma nova confirmação que deve ser inserida no meio do seu histórico, será necessário gerar a nova confirmação antes de usar o git filter-branch e adicionar
--parent-filter
ao git filter-branch :Você também pode providenciar para que o arquivo seja adicionado pela primeira vez em uma nova confirmação de raiz: crie sua nova confirmação de raiz através do método “órfão” na seção git rebase (capture-a
new_commit
), use o incondicional--index-filter
e--parent-filter
similares"sed -e \"s/^$/-p $new_commit/\""
.fonte
--index-filter
aplicar às confirmações retornadas porgit rev-list
? No momento, estou vendo o filtro de índice aplicado a um subconjunto de rev-list. Aprecie qualquer insight.-- --all
para processar todos os commits acessíveis a partir de qualquer ref. O último exemplo mostra como alterar apenas determinadas confirmações (basta testar GIT_COMMIT para o que você quiser). Para alterar apenas uma lista específica de confirmações, você pode salvar a lista antes de filtrar (por exemplogit rev-list … >/tmp/commits_to_rewrite
) e testar a associação dentro do filtro (por exemploif grep -qF "$GIT_COMMIT" /tmp/commits_to_rewrite; then git update-index …
). O que exatamente você está tentando realizar? Você pode querer iniciar uma nova pergunta se for demais para explicar nos comentários.import-directories.perl
do Gitcontrib/
(ouimport-tars.perl
, ouimport-zips.py
…) para criar um novo repositório Git a partir dos seus instantâneos (mesmo com Timestamps "antigos"). Asrebase
/filter-branch
técnicas na minha resposta são necessárias apenas se você deseja inserir um arquivo que foi "deixado de fora" do histórico de um repositório existente.Você pode criar a confirmação como de costume, mas, ao confirmar, defina as variáveis de ambiente
GIT_AUTHOR_DATE
eGIT_COMMITTER_DATE
as datas apropriadas.Obviamente, isso fará o commit na ponta do seu ramo (ou seja, na frente do commit HEAD atual). Se você deseja empurrá-lo para mais longe no repositório, é preciso ter um pouco de fantasia. Digamos que você tenha esse histórico:
E você deseja que seu novo commit (marcado como "X") apareça em segundo :
A maneira mais fácil seria ramificar a partir do primeiro commit, adicionar seu novo commit e depois refazer todos os outros commit sobre o novo. Igual a:
fonte
GIT_AUTHOR_DATE='Fri Jul 26 19:32:10 2013 -0400' GIT_COMMITTER_DATE='Fri Jul 26 19:32:10 2013 -0400' git commit
2013-07-26T19:32:10
: kernel.org/pub/software/scm/git/docs/…THE_TIME='2019-03-30T8:20:00 -0500' GIT_AUTHOR_DATE=$THE_TIME GIT_COMMITTER_DATE=$THE_TIME git commit -m 'commit message here'
Eu sei que essa pergunta é bastante antiga, mas foi o que realmente funcionou para mim:
fonte
--date
também suporte o formato de data relativa legível por humanos.git --date
modificará apenas $ GIT_AUTHOR_DATE ... portanto, dependendo das circunstâncias, você verá a data atual anexada ao commit ($ GIT_COMMITTER_DATE)git show <commit-hash> --format=fuller
. Lá, você veráAuthorDate
a data especificada, mas aCommitDate
data real da confirmação.No meu caso, com o tempo, salvei várias versões do myfile como myfile_bak, myfile_old, myfile_2010, backups / myfile etc. Eu queria colocar o histórico do myfile no git usando suas datas de modificação. Então, mudar o nome do mais antigo para myfile,
git add myfile
e, em seguidagit commit --date=(modification date from ls -l) myfile
, mudar o nome mais antigo em seguida para myfile, outro git commit com --date, repita ...Para automatizar isso um pouco, você pode usar o shell-foo para obter o tempo de modificação do arquivo. Comecei com
ls -l
ecut
, mas o stat (1) é mais diretofonte
--date
"Substitua a data do autor usada no commit."git log
Data parece ser o AuthorDate,git log --pretty=fuller
mostra AuthorDate e CommitDate.git commit
opção--date
modificará apenas oGIT_AUTHOR_DATE
, nãoGIT_COMMITTER_DATE
. Como o Pro Git Book explica: "O autor é a pessoa que originalmente escreveu a obra, enquanto o autor é a pessoa que aplicou a obra pela última vez". No contexto de datas,GIT_AUTHOR_DATE
é a data em que o arquivo foi alterado, enquantoGIT_COMMITTER_DATE
a data em que foi confirmado. É importante observar aqui que, por padrão,git log
exibe as datas do autor como "Data", mas depois usa as datas de confirmação para filtragem quando uma--since
opção é fornecida .stat -c %y
no macOS (e outras variantes do BSD) éstat -f %m
.O seguinte é o que eu uso para confirmar as alterações no
foo
paraN=1
dias no passado:Se você quer se comprometer com uma data ainda mais antiga, digamos, 3 dias de volta, basta alterar o
date
argumento:date -v-3d
.Isso é realmente útil quando você esquece de cometer algo ontem, por exemplo.
UPDATE :
--date
também aceita expressões como--date "3 days ago"
ou mesmo--date "yesterday"
. Portanto, podemos reduzi-lo a um comando de linha:fonte
git --date
modificará apenas $ GIT_AUTHOR_DATE ... portanto, dependendo das circunstâncias, você verá a data atual anexada ao commit ($ GIT_COMMITTER_DATE)git commit --amend --date="$(stat -c %y fileToCopyMTimeFrom)"
git commit --amend --date="$(date -R -d '2020-06-15 16:31')"
No meu caso, ao usar a opção --date, meu processo git travou. Pode ser que eu fiz algo terrível. E, como resultado, algum arquivo index.lock apareceu. Então, eu apaguei manualmente os arquivos .lock da pasta .git e os executei, para que todos os arquivos modificados fossem confirmados em datas passadas e funcionou dessa vez. Obrigado por todas as respostas aqui.
fonte
git commit --date
. Além disso, o exemplo mensagem de confirmação deve ser alterado para desencorajar mensagens de linha de um pobres como estes @JstRoRRgit --date
modificará apenas $ GIT_AUTHOR_DATE ... portanto, dependendo das circunstâncias, você verá a data atual anexada ao commit ($ GIT_COMMITTER_DATE)Para fazer um commit que parece ter sido feito no passado, você deve definir ambos
GIT_AUTHOR_DATE
eGIT_COMMITTER_DATE
:onde
date -d'...'
pode ser a data exata2019-01-01 12:00:00
ou a relativa5 months ago 24 days ago
.Para ver as duas datas no log do git, use:
Isso também funciona para confirmações de mesclagem:
fonte
Você sempre pode alterar uma data no seu computador, fazer uma confirmação e alterar a data de volta e pressionar.
fonte
Ou apenas use um histórico falso-git para gerá-lo para um intervalo de dados específico.
fonte