git cherry-pick diz “… 38c74d é uma fusão, mas nenhuma opção foi dada”

Eu fiz algumas mudanças no meu branch master e quero trazê-las para o upstream. quando eu escolho os seguintes commits no entanto eu fico preso em fd9f578 onde git diz:

$ git cherry-pick fd9f578 fatal: Commit fd9f57850f6b94b7906e5bbe51a0d75bf638c74d is a merge but no -m option was given. 

O que está tentando me dizer e escolher a coisa certa a ser usada aqui? A ramificação principal inclui mudanças nos arquivos que foram modificados na ramificação upstream, portanto, tenho certeza que haverá alguns conflitos de mesclagem, mas esses não são ruins para serem resolvidos. Eu sei quais mudanças são necessárias onde.

Estes são os commits que eu quero trazer para o upstream.

 e7d4cff added some comments... 23e6d2a moved static strings... 44cc65a incorporated test ... 40b83d5 whoops delete whitspace... 24f8a50 implemented global.c... 43651c3 cleaned up ... 068b2fe cleaned up version.c ... fd9f578 Merge branch 'master' of ssh://extgit/git/sessions_common 4172caa cleaned up comments in sessions.c ... 

A maneira como um cherry-pick funciona é tomando o diff que um changeset representa (a diferença entre a tree de trabalho naquele ponto e a tree de trabalho de seu pai), e aplicando-o ao seu branch atual.

Então, se um commit tiver dois ou mais pais, ele também representa dois ou mais diffs – qual deve ser aplicado?

Você está tentando escolher fd9f578 , que foi uma fusão com dois pais. Então você precisa dizer ao comando cherry-pick qual deve ser o valor do diff, usando a opção -m . Por exemplo, git cherry-pick -m 1 fd9f578 para usar o pai 1 como base.

Eu não posso dizer com certeza pela sua situação em particular, mas usar o git merge vez do git cherry-pick é geralmente aconselhável. Quando você escolhe uma consolidação de mesclagem, ela recolhe todas as alterações feitas no pai que você não especificou para -m nessa confirmação . Você perde toda a sua história e junta todos os seus diffs. Sua chamada.

@ A resposta da Borealid está correta, mas suponha que você não se preocupe em preservar o histórico exato de fusão de uma ramificação e apenas queira escolher uma versão linearizada dela. Aqui está uma maneira fácil e segura de fazer isso:

Estado inicial: você está na ramificação X e quer selecionar os commits Y..Z .

  1. git checkout -b tempZ Z
  2. git rebase Y
  3. git checkout -b newX X
  4. git cherry-pick Y..tempZ

O que isto faz é criar um branch tempZ baseado em Z , mas com o histórico de Y linearizado, e então selecionar isso em uma cópia de X chamada newX . (É mais seguro fazer isso em uma nova ramificação do que sofrer uma mutação em X ) É claro que pode haver conflitos na etapa 4, que você terá que resolver da maneira usual ( cherry-pick funciona muito como rebase esse respeito ).

Se a etapa 2 fornecer a mensagem “A ramificação atual tempZ está atualizada”, então Y..Z já foi linear, portanto, ignore essa mensagem e prossiga com as etapas 3 e 4.

Em seguida, analise o newX e veja se ele fez o que você queria.

(Nota: isto não é o mesmo que um git rebase X simples de git rebase X quando na ramificação Z , porque não depende de qualquer forma da relação entre X e Y ; pode haver commits entre o ancestral comum e Y que você não fez. t quer.)

Aqui está uma reescrita da resposta aceita que idealmente esclarece as vantagens / riscos de possíveis abordagens:

Você está tentando escolher fd9f578, que foi uma fusão com dois pais.

Em vez de selecionar uma mesclagem, a coisa mais simples é selecionar os commits que você quer de cada branch na junit.

Como você já se fundiu, é provável que todos os commits desejados estejam na sua lista. Escolha-os diretamente e você não precisa mexer com o commit da mesclagem.

explicação

A maneira como um cherry-pick funciona é tomando o diff que um changeset representa (a diferença entre a tree de trabalho naquele ponto e a tree de trabalho de seu pai), e aplicando o conjunto de mudanças em seu branch atual.

Se um commit tiver dois ou mais pais, como é o caso de uma mesclagem, esse commit também representa dois ou mais diffs. O erro ocorre devido à incerteza sobre qual diff deve ser aplicado.

alternativas

Se você determinar que precisa include o merge vs cherry-picking dos commits relacionados, você tem duas opções:

  1. (Mais complicado e obscuro; também descarta histórico) você pode indicar qual pai deve aplicar.

    • Use a opção -m para fazer isso. Por exemplo, git cherry-pick -m 1 fd9f578 usará o primeiro pai listado na mesclagem como base.

    • Considere também que, quando você escolhe uma consolidação de mesclagem, ela recolhe todas as alterações feitas no pai que você não especificou para -m nessa confirmação . Você perde toda a sua história e junta todos os seus diffs. Sua chamada.

  2. (Mais simples e familiar; preserva o histórico) você pode usar o git merge vez do git cherry-pick .

    • Como é normal com o git merge , ele tentará aplicar todos os commits que existem no branch que você está mesclando, e listá-los individualmente no seu log git.

Simplificação do método @Daira Hopwood é bom para escolher um único commit. Não precisa de ramos temporários.

No caso do autor:

  • Z é procurado commit (fd9f578)
  • Y está comprometido antes disso
  • X ramo de trabalho atual

então faça:

 git checkout Z # move HEAD to wanted commit git reset Y # have Z as changes in working tree git stash # save Z in stash git checkout X # return to working branch git stash pop # apply Z to current branch git commit -a # do commit