É possível escolher um commit de outro repositório git?

726

Estou trabalhando com um repositório git que precisa de uma confirmação de outro repositório git que não sabe nada sobre o primeiro.

Normalmente, eu selecionaria cereja usando o HEAD@{x}no reflog, mas como isso .gitnão conhece nada dessa entrada de reflog (diretório físico diferente), como posso escolher isso de maneira cerejeira, ou posso?

Estou usando git-svn. Meu primeiro ramo está usando git-svno trunkrepositório Subversion e o próximo ramo está usando git-svnum ramo Subversion.

gitcoder182
fonte
2
Esta é a razão dada por Ben Lee para abrir uma recompensa sobre esta questão: "Vou conceder a recompensa à resposta certa, e não à resposta aceita. Só tenho que esperar 24 [horas] para fazê-lo". No entanto, não entendo qual delas deveria ser "a resposta certa" e por que a resposta aceita não é "certa".
1
Não está claro qual é a natureza do problema. Como esses diferentes repositórios estão relacionados, se é que existem? Um é um garfo do outro? Ou eles são realmente dois projetos completamente separados e não relacionados?
@ Cupcake, a resposta aceita é boa e claramente ajudou o OP, por isso deve ser aceito. Por "certo" eu realmente quis dizer "certo para mim" (e, a julgar pelos comentários, certo para várias outras pessoas também). Eu apenas pensei que aquele a quem eu dei a recompensa merecia tanto representante quanto a resposta aceita.
Ben Lee

Respostas:

557

Você precisará adicionar o outro repositório como um controle remoto e buscar suas alterações. A partir daí, você vê o commit e pode selecioná-lo.

Curtiu isso:

git remote add other https://example.link/repository.git
git fetch other

Agora você tem todas as informações para simplesmente fazer git cherry-pick.

Mais informações sobre como trabalhar com controles remotos aqui: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes

CharlesB
fonte
1
E se eu estiver usando o git-svn? minha primeira filial está usando git-svn do tronco ea próxima está usando o git-svn em uma filial (obrigado pela resposta rápida)
gitcoder182
1
quando você clonar o repositório Subversion pela primeira vez, certifique-se de clonar o repositório inteiro , não apenas o tronco. Também certifique-se de usar a --stdlayoutopção git-svn se estiver usando o layout padrão de trunk / branches / tags no Subversion. Então o ramo Subversion será um mero ramo remoto do git.
Wilelmtell
33
Se você estiver usando o Github, poderá extrair o patch anexando .patch ao URL de confirmação e aplicando-o com git am < d821j8djd2dj812.patch. Fora do GH, conceitos semelhantes poderiam ser feitos conforme referenciado na resposta alternativa abaixo.
Radicand
2
@radicand, que resposta abaixo é a "alternativa"? Por favor, link para ele.
7
Etapas detalhadas para escolher cereja de outro repo: coderwall.com/p/sgpksw/git-cherry-pick-from-another-repository
T. Kim Nguyen
854

A resposta, como dada, é usar o patch de formato, mas como a pergunta era como escolher uma cereja em outra pasta, aqui está um pedaço de código para fazer exatamente isso:

$ git --git-dir=../<some_other_repo>/.git \
format-patch -k -1 --stdout <commit SHA> | \
git am -3 -k

(explicação de @cong ma )

O git format-patchcomando cria um patch a partir some_other_repoda confirmação especificada pelo seu SHA (apenas -1para uma confirmação). Esse patch é canalizado git am, o que aplica o patch localmente ( -3significa tentar a combinação de três vias se o patch falhar na aplicação correta). Espero que isso explique.

Robert Wahler
fonte
18
Isso está certo, mas seria ótimo se alguém pudesse expandir isso - uma análise exata do que está acontecendo (especialmente com essas bandeiras) seria incrivelmente útil.
Nick F
46
@NickF, o git format-patchcomando cria um patch a partir some_other_repoda confirmação especificada pelo seu SHA ( -1para uma única confirmação). Esse patch é canalizado git am, o que aplica o patch localmente ( -3significa tentar a combinação de três vias se o patch falhar na aplicação correta). Espero que isso explique.
Cong Ma
3
erro: falha no patch: somefile.cs: 85 erro: somefile.cs: o patch não se aplica Você editou seu patch manualmente? Não se aplica a blobs registrados em seu índice. Não é possível voltar à mesclagem de três vias. O patch falhou em 0001 Adicionadas peças da GUI. A cópia do patch que falhou encontra-se em: <some_other_repo> /.git/rebase-apply/patch Quando você resolver esse problema, execute "git am --continue". Se você preferir pular esse patch, execute "git am --skip". Para restaurar a ramificação original e parar o patch, execute "git am --abort".
Tom
8
@ Tente usar --ignore-whitespace. Comando completo: git --git-dir=../<some_other_repo>/.git format-patch -k -1 --stdout <commit SHA> | git am -3 -k --ignore-whitespace
Jake Graham Arnold
7
@BoomShadow Porque é bem mais simples. Adicionar o controle remoto e buscar traz todas as alterações dos outros repositórios. Essa linha de comando é uma ação única.
Jonathon Reinhart
152

Aqui está um exemplo da fusão remota de busca.

cd /home/you/projectA
git remote add projectB /home/you/projectB
git fetch projectB

Então você pode:

git cherry-pick <first_commit>..<last_commit>

ou você pode até mesclar todo o ramo

git merge projectB/master
Brian
fonte
54
git merge projectB/master é muito, muito errado , porque você não está aplicando as alterações de uma única confirmação (como uma cereja-pick faria), você está realmente fundir em todas as alterações emprojectB/masterque não estão contidas em seu própriomasterramo.
4
Supus que essa era a intenção do pôster original. Caso contrário, sim, essa não é a opção certa para eles.
18713 Brian
5
Isso funciona de maneira brilhante quando os dois repositórios estão relacionados.
Ronny Ager-Wick
1
Eu criei uma cópia de um repositório git (apenas para "brincar" sem interromper o repositório original) e para mantê-lo atualizado com sua fonte, a resposta de Brian é exatamente o que eu precisava, então, Cupcake, eu tenho que dizer, não é "errado", mas outro caso de uso. Mas é bom de sua parte apontar o possível desastre: D
ferrari2k
6
Na IMO, essa precisa ser a solução aceita. Além disso, se você deseja excluir o controle remoto depois de fazer uma seleção, use git remote rm projectB. Use também git tag -d tag-namepara remover as tags buscadas no repositório remoto. As confirmações remotas não serão mais exibidas no seu histórico e a remoção as removerá do armazenamento eventualmente.
ADTC
130

Você pode fazer isso, mas requer duas etapas. Aqui está como:

git fetch <remote-git-url> <branch> && git cherry-pick FETCH_HEAD

Substitua <remote-git-url>pelo URL ou caminho para o repositório que você deseja escolher.

Substitua <branch>pelo nome da ramificação ou tag que você deseja selecionar no repositório remoto.

Você pode substituir FETCH_HEADpor um git SHA da ramificação.

Atualizado: modificado com base no feedback de @ pkalinow.

docwhat
fonte
8
Funciona com um nome de filial, mas não com SHA. Se você quiser cherry-pick um commit indicado por seu hash, use esta em vez disso: git fetch <repo-url> <branch> && git cherry-pick <sha>.
pkalinow
Obrigado. Era exatamente isso que eu precisava para inserir uma série de confirmações de um repositório para outro, que eu criei para esse propósito.
Wojciii
Era exatamente isso que eu precisava com muitas implementações personalizadas de nosso código para diferentes clientes (cada um com seus próprios repositórios / garfos). Precisávamos de uma maneira de obter confirmações específicas em nossa base / tronco. OBRIGADO!
RedSands
Essa deve ser a resposta aceita para uma escolha única entre repos. Eu o uso o tempo todo ao escolher entre repositórios que já são locais, a URL remota é apenas um caminho do sistema de arquivos local.
Amedee Van Gasse
61

Aqui estão as etapas para adicionar um controle remoto, buscar ramificações e escolher uma confirmação

# Cloning our fork
$ git clone [email protected]:ifad/rest-client.git

# Adding (as "endel") the repo from we want to cherry-pick
$ git remote add endel git://github.com/endel/rest-client.git

# Fetch their branches
$ git fetch endel

# List their commits
$ git log endel/master

# Cherry-pick the commit we need
$ git cherry-pick 97fedac

Fonte: https://coderwall.com/p/sgpksw

jaredwilli
fonte
17

Veja Como criar e aplicar um patch com Git . (Pela redação da sua pergunta, presumi que este outro repositório é para uma base de código totalmente diferente. Se for um repositório para a mesma base de código, você deve adicioná-lo como um controle remoto, conforme sugerido por @CharlesB. Mesmo que seja para outro base de código, acho que você ainda pode adicioná-lo como um controle remoto, mas talvez não queira colocar todo o ramo em seu repositório ...)

Aasmund Eldhuset
fonte
11

Você pode fazer isso em uma linha da seguinte maneira. Espero que você esteja no repositório git que precisa da alteração escolhida pela cereja e tenha feito check-out para corrigir o branch.

git fetch ssh://[email protected]:7999/repo_to_get_it_from.git branchToPickFrom && git cherry-pick 02a197e9533
# 

git fetch [URL da ramificação] [Ramifique para escolher a partir de] && git cherry-pick [ID de confirmação]

Don
fonte
1
Saúde, não precisava da ssh://parte, apenas parahttps://
Leo
5

Sim. Busque o repositório e escolha a partir da ramificação remota.

wilhelmtell
fonte
1

Supondo que Aé o repositório do qual você deseja escolher a cereja e Bo que você deseja escolher, você pode fazer isso adicionando </path/to/repo/A/>/.git/objectsa </path/to/repo/B>/.git/objects/info/alternates. Crie esses alternatesarquivos se eles não existirem.

Isso fará com que o repositório B acesse todos os objetos git do repositório A e fará com que a escolha de cereja funcione para você.

pranavk
fonte
0

Minha situação era que eu tinha um repositório vazio para o qual a equipe empurra e um clone daquele sentado ao lado dele. Esse conjunto de linhas em um Makefile funciona corretamente para mim:

git reset --hard
git remote update --prune
git pull --rebase --all
git cherry-pick -n remotes/origin/$(BRANCH)

Mantendo o mestre do repo bare atualizado, podemos escolher uma alteração proposta publicada no repo bare. Também temos uma maneira (mais complicada) de escolher vários braches para revisão e teste consolidados.

Se "não sabe nada" significa "não pode ser usado como um controle remoto", isso não ajuda, mas essa pergunta do SO surgiu quando eu estava pesquisando no Google para criar esse fluxo de trabalho, então pensei em contribuir de volta.

Paul Hulett
fonte
-n significa não-confirmação de acordo com git docs e eu coisa muito importante para ver as alterações antes de fazer um commit
canbax
0

Se você desejar selecionar várias confirmações para um determinado arquivo até chegar a uma confirmação, use o seguinte.

# Directory from which to cherry-pick
GIT_DIR=...
# Pick changes only for this file
FILE_PATH=...
# Apply changes from this commit
FIST_COMMIT=master
# Apply changes until you reach this commit
LAST_COMMIT=...

for sha in $(git --git-dir=$GIT_DIR log --reverse --topo-order --format=%H $LAST_COMMIT_SHA..master -- $FILE_PATH ) ; do 
  git --git-dir=$GIT_DIR  format-patch -k -1 --stdout $sha -- $FILE_PATH | 
    git am -3 -k
done
Diomidis Spinellis
fonte