Como obter apenas um arquivo de outra ramificação

1267

Estou usando o git e trabalhando no ramo mestre. Esta ramificação tem um arquivo chamado app.js.

Eu tenho um experimentramo no qual fiz várias alterações e toneladas de confirmações. Agora, quero trazer todas as alterações feitas apenas para app.jsde experimentpara masterramificação.

Como faço isso?

Mais uma vez, não quero mesclar. Eu só quero trazer todas as alterações app.jsde experimentfilial para masterfilial.

Nick Vanderbilt
fonte
1
Com exceção das respostas e outras respostas de hoje, como copiar o conteúdo do arquivo, era isso que eu queria quando encontrei essa. No entanto, se lido exatamente, Nick queria trazer alterações, não texto completo, e o arquivo masterpode divergir experiment, por exemplo, pode conter alterações mescladas de outros ramos que seriam perdidos no arquivo, apenas copiadas. PS, por outro lado, ele não deseja mesclar, mas, tanto quanto eu sei, o git mergetermo é apenas para ramificação, não para arquivo específico, portanto não há contradição aqui.
Alexei Martianov

Respostas:

1605
git checkout master               # first get back to master
git checkout experiment -- app.js # then copy the version of app.js 
                                  # from branch "experiment"

Veja também git como desfazer alterações de um arquivo?


Atualização em agosto de 2019, Git 2.23

Com o novo git switche os git restorecomandos, isso seria:

git switch master
git restore -s experiment -- app.js

Por padrão, apenas a árvore de trabalho é restaurada.
Se você deseja atualizar o índice também (ou seja, restaurar o conteúdo do arquivo e adicioná-lo ao índice em um comando):

git restore -s experiment --staged --worktree -- app.js
# shorter:
git restore -s experiment -WS -- app.js

Como Jakub Narębski menciona nos comentários:

git show experiment:path/to/app.js > path/to/app.js

também funciona, exceto que, conforme detalhado na pergunta do SO " Como recuperar um único arquivo de uma revisão específica no Git? ", você precisa usar o caminho completo no diretório raiz do repositório.
Daí o caminho / to / app.js usado por Jakub em seu exemplo.

Como Frosty menciona no comentário:

você obterá apenas o estado mais recente do app.js

Mas, para git checkoutou git show, você pode realmente fazer referência a qualquer revisão que desejar, conforme ilustrado na pergunta SO " revisão de git checkout de um arquivo no git gui ":

$ git show $REVISION:$FILENAME
$ git checkout $REVISION -- $FILENAME

seria o mesmo que $ FILENAME é o caminho completo de um arquivo com versão.

$REVISIONpode ser como mostrado em git rev-parse:

experiment@{yesterday}:app.js # app.js as it was yesterday 
experiment^:app.js            # app.js on the first commit parent
experiment@{2}:app.js         # app.js two commits ago

e assim por diante.

schmijos acrescenta nos comentários :

você também pode fazer isso a partir de um stash:

git checkout stash -- app.js

Isso é muito útil se você estiver trabalhando em dois ramos e não quiser confirmar.

VonC
fonte
13
Uma observação: você obterá apenas o estado mais recente do app.js, não receberá nenhum histórico da ramificação da experiência.
Gelado
2
@ThomasReggi, você poderá importar (fazer checkout) de um arquivo de qualquer ramo para qualquer ramo atual. Se você não puder, pode ser uma boa pergunta aqui, com detalhes específicos, como a mensagem de erro exata e a versão do Git e do OS usada.
VonC
2
Em um subdiretório, você também pode usar experiment:./app.js. (Você não precisa especificar o caminho completo.) Aprendi isso graças à mensagem de erro muito útil que o git me deu: "Você quis dizer 'mybranch: full / caminho / para / meu / arquivo.xsl', também conhecido como 'mybranch: ./file.xsl '? " Sim eu fiz! Acho que nunca fiquei tão encantado com uma mensagem de erro fatal.
Evan Lenz
1
@TomaszGandor Sim, eu mencionei isso em stackoverflow.com/a/21066489/6309 , em que o git show não modifica o índice, mas o git checkout modifica o índice.
VonC 5/08/16
1
@FriedBrice Veja minha resposta: atualmente, seriagit restore -s new-feature path/to/app.js
VonC 5/19/19
360

Tudo é muito mais simples, use o git checkout para isso.

Suponha you're on masterramificação, para obter app.js from new-featureramificação faça:

git checkout new-feature path/to/app.js

// note that there is no leading slash in the path!

Isso exibirá o conteúdo do arquivo desejado. Como sempre, você pode usar parte do sha1 em vez do nome do ramo do novo recurso para obter o arquivo como estava naquele commit específico.

Nota : new-featureprecisa ser uma filial local , não remota.

Dmitry Avtonomov
fonte
77
Acho útil especificar sempre a origem, git checkout origin/source_branch path/to/fileporque se você não tiver atualizado a ramificação de origem do seu repositório local, poderá obter uma versão antiga do arquivo ... Pergunte-me como eu sei. ;)
talyric 15/05
3
@Mymozaaa a questão não mencionou controles remotos, assim, a suposição de que é um repo puramente local
Dmitry Avtonomov
1
Esse comando trará o histórico do arquivo ou apenas a última versão do arquivo?
User1366265
1
@ user1366265 este comando colocará o arquivo como estava na confirmação específica que você especificou ou no cabeçalho da ramificação que você especificou. Não existe o "histórico de um arquivo", todas as informações do histórico são armazenadas apenas em ramificações.
Dmitry Avtonomov
3
Isso parece preparar automaticamente o arquivo com check-out. É possível fazer o mesmo sem teste?
bluenote10
44
git checkout branch_name file_name

Exemplo:

git checkout master App.java

Isso não funcionará se o nome do seu ramo tiver um período.

git checkout "fix.june" alive.html
error: pathspec 'fix.june' did not match any file(s) known to git.
Sarath
fonte
@PhilipRego Esta resposta está correta. Suponho que exista uma maiúscula ou pontuação diferente em sua filial, ou você só tem uma filial remota e não local. Veja o documento do git checkout: git-scm.com/docs/git-checkout#Documentation/…
Bret
@Bret eu achei que não funciona quando o nome do ramo tem um período. Eu sugeri uma edição
Philip Rego
Esta é a melhor resposta. Desejo que esta resposta tenha a classificação mais alta. O atual mais alto é muito confuso e não é direto #
Russell Lego
41

Complementar às respostas de VonC e chhh.

git show experiment:path/to/relative/app.js > app.js
# If your current working directory is relative than just use
git show experiment:app.js > app.js

ou

git checkout experiment -- app.js
AlexLordThorsen
fonte
2
Legal! Eu odeio especificar caminhos longos. O traço duplo ( --) entre o nome da ramificação e os caminhos é opcional? É apenas para impedir que caminhos, que começariam com um traço, sejam tratados como opções / opções?
Tomasz Gandor
Honestamente, eu não sei. Eu nem percebi que tinha esquecido o traço duplo até que você apontou isso.
AlexLordThorsen
6
@TomaszGandor O --é opcional, mas é mais útil evitar conflitos com nomes de filiais. Por exemplo, git checkout -- foosignifica "retirar o arquivo foo do HEAD" (ou seja, substituir as alterações locais no foo , isto é, um subconjunto de git reset --hard), mas git checkout foopode significar isso ou "vamos para o ramo foo ".
Alois Mahdal 23/02
8

Ou se você quiser todos os arquivos de outro ramo:

git checkout <branch name> -- .
Jester
fonte
24
A missão inicial contém "apenas um arquivo".
22617 greatvovan
1
este substitui os arquivos existentes em vez de fusão
Amare
3
Isso .faz uma enorme diferença: em vez de mudar para outro ramo, ele copia todos os arquivos de lá, deixando-o no atual. Você obtém conteúdo de outro ramo sem entrar nele.
Xeverous 20/09/18
4

Revise o arquivo no github e puxe-o de lá

Essa é uma abordagem pragmática que não responde diretamente ao OP, mas alguns acharam úteis:

Se a ramificação em questão estiver no GitHub, você poderá navegar até a ramificação e o arquivo desejados usando qualquer uma das muitas ferramentas oferecidas pelo GitHub, clique em 'Raw' para visualizar o texto sem formatação e (opcionalmente) copiar e colar o texto como desejado.

Eu gosto dessa abordagem porque permite que você olhe o arquivo remoto na íntegra antes de puxá-lo para a máquina local.

fearless_fool
fonte
2
No entanto, copiar e colar o arquivo bruto provavelmente causará alterações indesejadas de caracteres no diff do git. É mais seguro salvar o arquivo diretamente no seu projeto para garantir que não haja alterações.
Philip Rego
0

Se você desejar o arquivo de uma confirmação específica (qualquer ramificação), diga 06f8251f

git checkout 06f8251f path_to_file

por exemplo, no windows:

git checkout 06f8251f C: \ A \ B \ C \ D \ file.h

arupjbasu
fonte
1
Obrigado por reservar um tempo para responder! Mas isso não responde à pergunta, e uma boa resposta muito detalhada já foi publicada há 9 anos. Não há necessidade de esbarrar na questão.
Nathan
Este é um cenário prático válido. A resposta lida corretamente com a ramificação, mas que tal observar um commit específico da ramificação?
Arupjbasu 25/07/19
0

Outra maneira é criar um patch com as diferenças e aplicá-lo no ramo mestre. Por exemplo. Digamos que o último commit antes de você começar a trabalhar no app.js seja 00000aaaaa e o commit contendo a versão desejada seja 00000bbbbb

Você executa isso no ramo da experiência:

git diff 00000aaaaa 00000bbbbb app.js > ~/app_changes.git

Isso criará um arquivo com todas as diferenças entre essas duas confirmações para app.js que você pode aplicar onde quiser. Você pode manter esse arquivo em qualquer lugar fora do projeto

Então, no master, você apenas executa:

git apply ~/app_changes.git

agora você verá as alterações nos projetos como se as tivesse feito manualmente.

Santi
fonte
-3
git checkout master               -go to the master branch first
git checkout <your-branch> -- <your-file> --copy your file data from your branch.

git show <your-branch>:path/to/<your-file> 

Espero que isso ajude você. Entre em contato se você tiver alguma dúvida.

Rohit Saini
fonte