GIT copiar o ficheiro preservar o histórico

Tenho uma pergunta um pouco confusa em GIT. Digamos que tenho um ficheiro {[[0]} comprometido e o git preserva um histórico de commits {[[10]}

Agora preciso (por algumas razões) copiar o ficheiro para dir2/A.txt (não mover, mas copiar). Eu sei que existe um comando {[[2]} mas eu preciso dir2/A.txt para ter o mesmo Histórico de commits que dir1/A.txt, e {[[0]} para ainda permanecer lá.

não estou a planear actualizar {[[6]} Assim que a cópia for criada e todo o trabalho futuro for feito em dir2/A.txt

Eu sei. parece confuso, eu vou adicionar que esta situação é em java com o módulo (mavenized projeto) e precisamos criar uma nova versão do código para que os nossos clientes têm a capacidade de ter 2 versões diferentes em tempo de execução, a primeira versão será removido, eventualmente, quando o alinhamento será feito. Podemos usar Maven versioning, é claro, eu sou apenas novato em GIT e curioso sobre o que git pode fornecer aqui.

 122
Author: Avery, 2013-06-05

5 answers

Ao contrário do subversion, o git não tem um histórico por ficheiro. Se você olhar para a estrutura de dados de commit, ela só aponta para os commits anteriores e o novo objeto árvore para este commit. Nenhuma informação explícita é armazenada no objeto commit que arquivos são alterados pelo commit; nem a natureza dessas alterações.

As ferramentas para inspecionar mudanças podem detectar renomeações baseadas na heurística. Por exemplo," git diff " tem a opção-M que liga a detecção de renomeação. Por isso, em caso de mudança de nome, "git diff" poderá mostrar-lhe que um ficheiro foi apagado e outro criado, enquanto que o "git diff-M" irá realmente detectar o movimento e mostrar a alteração de acordo (veja "man git diff" para mais detalhes).

Então, no git isto não é uma questão de como você comete suas mudanças, mas como você olha para as mudanças comprometidas mais tarde.

 66
Author: CliffordVienna, 2016-12-07 20:56:35

Tudo o que você tem que fazer é movê-lo em paralelo para dois locais diferentes, fundir, e então mover uma cópia de volta para o local original, e você está feito.

Você pode então executar git blame em qualquer uma das cópias, sem opções especiais, e ver as melhores atribuições históricas para ambas. Você também pode executar git log no original e ver um histórico completo.

Em detalhe, suponha que deseja copiar o foo/ no seu repositório para o bar/. Faça isso (nota que estou usando-n para se comprometer para evitar qualquer reescrita, etc. por anzóis):

git mv foo bar
git commit -n
SAVED=`git rev-parse HEAD`
git reset --hard HEAD^
git mv foo foo-magic
git commit -n
git merge $SAVED # This will generate conflicts
git commit -a -n # Trivially resolved like this
git mv foo-magic foo
git commit -n

Nota: usei o git 2. 1. 4 no Linux

Porque é que isto funciona

Você vai acabar com um histórico de revisão como este:

  ORIG_HEAD
    /    \
SAVED  ALTERNATE
    \    /
    MERGED
      |
   RESTORED

Quando você perguntar ao git sobre o histórico de 'foo', ele irá (1) detectar a mudança de nome de 'foo-magic' entre fundido e restaurado, (2) detectar que 'foo-magic' veio do Pai alternativo de MERGED, e (3) detectar a mudança de nome de 'foo' entre ORIG_HEAD e ALTERNATE. A partir daí, irá investigar a história do "foo".

Quando você pergunta ao git sobre o histórico de 'bar', ele (1) notará nenhuma alteração entre a junção e a restauração, (2) detectará que 'bar' veio do Pai salvo da junção, e (3) detectará a mudança de nome de 'foo' entre ORIG_HEAD e SAVED. A partir daí, irá investigar a história do "foo".

É assim tão simples. Você só precisa forçar o git em uma situação de junção onde você pode aceitar duas cópias rastreáveis do(S) arquivo (s), e nós fazemos isso com um movimento paralelo do original (que em breve revertemos).
 70
Author: Peter Dillinger, 2018-06-17 08:27:16

Basta copiar o ficheiro, adicionar e enviar:

cp dir1/A.txt dir2/A.txt
git add dir2/A.txt
git commit -m "Duplicated file from dir1/ to dir2/"

Então os seguintes comandos irão mostrar o histórico completo de pré-cópia:

git log --follow dir2/A.txt

Para ver as anotações herdadas linha a linha do ficheiro original, use isto:

git blame -C -C -C dir2/A.txt

O Git não rastreia cópias à hora do commit, em vez disso detecta as cópias ao inspeccionar a história com, por exemplo, git blame e git log.

A maior parte desta informação vem das respostas aqui: gravar a operação de cópia de ficheiros com o Git

 16
Author: Jakob Buron, 2017-06-15 11:39:10

Para ser completo, eu acrescentaria que, se você quisesse copiar um diretório inteiro cheio de arquivos controlados e não controlados, você poderia usar o seguinte:

git mv old new
git checkout HEAD old

Os ficheiros não controlados serão copiados, por isso deve limpá-los:

git clean -fdx new
 10
Author: Hervé, 2014-01-29 11:29:14

No meu caso, eu fiz a alteração no meu disco rígido (cut/colado cerca de 200 pastas/ficheiros a partir de um caminho na minha cópia de trabalho para um outro caminho na minha cópia de trabalho), e utilizado SourceTree (2.0.20.1) a fase de ambas as alterações detectadas (um adicionar, remover um), e enquanto eu encenado tanto o adicionar e remover juntos, ele automaticamente combinadas em uma simples mudança de cor-de-rosa R ícone (mudar o nome, eu suponho).

Reparei que por ter tido um grande número de alterações ao mesmo tempo, o SourceTree era um pouco lento detectar todas as alterações, por isso, alguns dos meus arquivos de teste olhar como apenas adiciona (mais verde) ou apenas exclui (menos vermelho), mas eu continuei a atualizar o status do arquivo e mantido teste de novas alterações como eles, eventualmente, apareceu, e depois de alguns minutos, toda a lista foi perfeito e pronto para comprometer-se.

Verifiquei que o histórico está presente, desde que, quando procuro o histórico, verifique a opção "seguir ficheiros renomeados".

 2
Author: darbvin, 2017-05-16 18:47:39