Eu tenho o seguinte layout de repositório:
O que eu quero alcançar é escolher uma série de compromissos do ramo de trabalho e fundi-lo no ramo de integração. Eu sou muito novo no git e não consigo'não sei exatamente como fazer isso (o cherry picking dos intervalos de commit em uma operação, não na fusão) sem bagunçar o repositório. Alguma dica ou pensamento sobre isso? Obrigado!
Quando se trata de uma série de compromissos, escolher a cereja is não foi prático.
Como mencionado abaixo por Keith Kim, Git 1.7.2+ introduziu a capacidade de escolher uma gama de compromissos (mas você ainda precisa estar ciente da conseqüência da escolha da cereja para futuras fusões)
git cherry-pick" aprendeu a escolher uma gama de compromissos (por exemplo, "
cherry-pick A..B
" e "cherry-pick --stdin
"), assim como "git revert
" estes não suportam o melhor controle de seqüenciamento "rebase [-i]
" tem, no entanto.
Damian comentários e avisa-nos:
no "
cherry-pick A..B
" form,A
deve ser mais antigo queB
.
Se eles'são a ordem errada o comando irá falhar silenciosamente.
Se você quiser escolher o intervalo Baté
D` (inclusive) isso seria **B^...D
***.
Veja "Git cria ramo a partir de uma série de commits anteriores?" como uma ilustração.
Como Jubobs menciona nos comentários:
Isto assume que
B
não é um commit da raiz; você'irá obter um "revisão desconhecida
" erro de outra forma.
Nota: a partir de Git 2.9.x/2.10 (3º trimestre de 2016), você pode escolher um intervalo de compromisso diretamente em um ramo órfão (cabeça vazia): veja "Como tornar um ramo existente órfão em git".
Resposta original (Janeiro de 2010)
Um rebase --onto
seria melhor, onde você reproduz a gama dada de compromisso no topo do seu ramo de integração, como Charles Bailey descreveu aqui.
(também, procure por "Aqui está como você transplantaria um ramo tópico baseado em um ramo para outro" na página git rebase man page, para ver um exemplo prático de git rebase --onto
)
Se o seu ramo atual é a integração:
# Checkout a new temporary branch at the current location
git checkout -b tmp
# Move the integration branch to the head of the new patchset
git branch -f integration last_SHA-1_of_working_branch_range
# Rebase the patchset onto tmp, the old location of integration
git rebase --onto tmp first_SHA-1_of_working_branch_range~1 integration
Isso vai repetir tudo entre eles:
first_SHA-1_of_branch_range_working_branch_range
(daí o ~1
): o primeiro compromisso que você quer repetirintegração
" (que aponta para o último compromisso que você quer repetir, a partir do ramo trabalho
)para "tmp
" (que aponta para onde a integração
estava apontando antes)
Se houver algum conflito quando um desses compromissos for repetido:
git rebase --continue
".git rebase --skip
"git rebase --abort
" (e coloque de volta o ramo integration
no ramo tmp
)Depois disso rebase --onto
, integração
estará de volta no último commit do ramo de integração (isto é "tmp
" ramo + todos os commits reproduzidos)
Com o cherry-picking ou rebase --onto
, não se esqueça que ele tem conseqüências em fusões posteriores, como descrito aqui.
Um puro "cherry-pick
" a solução é discutida aqui, e envolveria algo como:
Se você quiser usar uma abordagem de patch, então "git format-patch|git am" e "git cherry" são suas opções.
Atualmente,git cherry-pick
aceita apenas um único commit, mas se você quiser escolher a faixaB
atéD
que seriaB^..D
no git lingo, então
git rev-list --reverse --topo-order B^..D | while read rev
do
git cherry-pick $rev || break
done
Mas de qualquer forma, quando você precisa de "replay" uma gama de commits, a palavra "replay" deve pressioná-lo a usar o "rebase
" recurso do Git.
Tem a certeza que não'não quer mesmo fundir os ramos? Se o ramo funcional tem alguns commits recentes que você não't quer, você pode apenas criar um novo ramo com uma HEAD no ponto que você quer.
Agora, se você realmente quer escolher uma gama de compromissos, por qualquer razão, uma maneira elegante de fazer isso é apenas puxar de um patchset e aplicá-lo ao seu novo ramo de integração:
git format-patch A..B
git checkout integration
git am *.patch
Isto é essencialmente o que o git-rebase está fazendo de qualquer maneira, mas sem a necessidade de jogar jogos. Você pode adicionar --3way' ao
git-am' se você precisar fundir. Certifique-se de que não há outros arquivos *.patch já no diretório onde você faz isso, se você seguir as instruções verbatim...
Eu envolvi código VonC's em um pequeno bash script, git-multi-cherry-pick
, para facilitar a execução:
#!/bin/bash
if [ -z $1 ]; then
echo "Equivalent to running git-cherry-pick on each of the commits in the range specified.";
echo "";
echo "Usage: $0 start^..end";
echo "";
exit 1;
fi
git rev-list --reverse --topo-order $1 | while read rev
do
git cherry-pick $rev || break
done
I'estou atualmente usando isso ao reconstruir a história de um projeto que tinha código de terceiros e customizações misturadas no mesmo tronco svn. I'm agora dividindo o código central de terceiros, módulos de terceiros e customizações em seus próprios ramos de git para melhor entendimento das customizações que vão adiante. A `git-cherry-pick' é útil nesta situação já que eu tenho duas árvores no mesmo repositório, mas sem um ancestral compartilhado.