Desde o tempo git cherry-pick
aprendeu a ser capaz de aplicar vários commits, a distinção de fato se tornou um tanto discutível, mas isso é algo a ser chamado de evolução convergente ;-)
A verdadeira distinção reside na intenção original de criar as duas ferramentas:
git rebase
A tarefa de é encaminhar uma série de mudanças que um desenvolvedor possui em seu repositório privado, criado contra a versão X de algum branch upstream, para a versão Y desse mesmo branch (Y> X). Isso efetivamente muda a base daquela série de commits, daí o "rebasing".
(Também permite que o desenvolvedor transplante uma série de commits para qualquer commit arbitrário, mas isso é de uso menos óbvio.)
git cherry-pick
é para trazer um commit interessante de uma linha de desenvolvimento para outra. Um exemplo clássico é o backport de uma correção de segurança feita em um branch de desenvolvimento instável para um branch estável (manutenção), onde um merge
não faz sentido, pois traria uma série de alterações indesejadas.
Desde sua primeira aparição, git cherry-pick
tem sido capaz de escolher vários commits de uma vez, um por um.
Portanto, possivelmente a diferença mais marcante entre esses dois comandos é como eles tratam o branch em que trabalham: git cherry-pick
normalmente traz um commit de algum outro lugar e o aplica no topo do seu branch atual, gravando um novo commit, enquanto git rebase
pega seu branch atual e reescreve uma série de sua própria dica compromete de uma forma ou de outra. Sim, esta é uma descrição bastante simplificada do que git rebase
podemos fazer, mas é intencional, para tentar fazer com que a ideia geral seja absorvida.
Atualize para explicar melhor um exemplo de uso que git rebase
está sendo discutido.
Dada esta situação,
o livro afirma:
No entanto, há outra maneira: você pode pegar o patch da mudança que foi introduzida em C3 e reaplicá-lo em cima de C4. No Git, isso é chamado de rebase. Com o comando rebase, você pode pegar todas as alterações que foram confirmadas em um branch e aplicá-las em outro.
Neste exemplo, você executaria o seguinte:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
"O problema" aqui é que, neste exemplo, o branch "experimento" (o assunto para rebase) foi originalmente bifurcado do branch "mestre" e, portanto, compartilha commits de C0 a C2 com ele - efetivamente, "experimento" é " master "até, e incluindo, C2 mais commit C3 em cima dele. (Este é o caso mais simples possível; claro, "experimento" pode conter várias dezenas de commits em cima de sua base original.)
Agora git rebase
é instruído a realocar "experimento" na ponta atual do "mestre" e funciona git rebase
assim:
- Executa
git merge-base
para ver qual é o último commit compartilhado por "experimento" e "mestre" (qual é o ponto de desvio, em outras palavras). Este é C2.
- Salva todos os commits feitos desde o ponto de desvio; em nosso exemplo de brinquedo, é apenas C3.
- Rebobina o HEAD (que aponta para a confirmação da ponta do "experimento" antes que a operação comece a ser executada) para apontar para a ponta do "mestre" - estamos fazendo o rebaseamento nele.
- Tenta aplicar cada um dos commits salvos (como se com
git apply
) em ordem. Em nosso exemplo de brinquedo, é apenas um commit, C3. Digamos que seu aplicativo produza um commit C3 '.
- Se tudo correr bem, a referência "experimento" é atualizada para apontar para o commit resultante da aplicação do último commit salvo (C3 'em nosso caso).
Agora, de volta à sua pergunta. Como você pode ver, aqui, tecnicamente, de git rebase
fato, transplanta uma série de commits de "experimento" para a ponta de "mestre", então você pode dizer com razão que de fato há "outro ramo" no processo. Mas a essência é que o commit de ponta de "experimento" acabou sendo o novo commit de ponta em "experimento", apenas mudou sua base:
Novamente, tecnicamente você pode dizer que git rebase
aqui estão incorporados certos commits do "master", e isso é absolutamente correto.
Com a escolha certa, os commits / branch originais permanecem e novos commits são criados. Com o rebase, todo o branch é movido com o branch apontando para os commits reproduzidos.
Digamos que você começou com:
Rebase:
Você obtém:
Colher cerejas:
Você obtém:
para mais informações sobre git, este livro tem a maior parte (http://git-scm.com/book)
fonte
topic
rebaseado no topomaster
, ele não contém os commits deixados de fora, então de qual branch eles farão parte?git checkout topic
egit reset --hard C'
depois da colheita seletiva, você terá o mesmo resultado que após a rebase. Eu me salvei de muitos conflitos de mesclagem usando a escolha seletiva ao invés de rebase, porque o ancestral comum estava há muito tempo.git
-guru mas estarebase
/cherry-pick
é em todos os detalhes comgit
que eu tinha uma compreensão problema.git checkout -b
, que não tem nada a ver comgit cherry-pick
. Uma maneira melhor de explicar o que você está tentando dizer seria “você corregit rebase
notopic
galho e passamaster
; você executagit cherry-pick
nomaster
branch e passa (commits de)topic
. ”A seleção seletiva funciona para commits individuais .
Quando você faz rebase, ele aplica todos os commits do histórico ao HEAD do branch que está faltando lá.
fonte
git cherry-pick foo~3..foo
obter os commits do topo da árvore de "foo" escolhidos um por um.git am
nele. Considerando que uma escolha certa aplica commit por commit (possivelmente criando uma caixa de correio de mensagem única para cada patch). Meu rebase estava falhando porque o arquivo de caixa de correio que estava criando ficou sem espaço na unidade, mas a escolha seletiva com o mesmo intervalo de revisão funcionou (e parece funcionar mais rápido).Uma resposta curta:
As respostas dadas acima são boas, eu só queria dar um exemplo na tentativa de demonstrar sua inter-relação.
Não é recomendado substituir "git rebase" por esta sequência de ações, é apenas uma "prova de conceito" que, espero, ajuda a entender como as coisas funcionam.
Dado o seguinte repositório de brinquedos:
Digamos que temos algumas mudanças muito importantes (commits # 2 a # 5) no master que queremos incluir em nosso test_branch_1. Normalmente, apenas mudamos para um branch e fazemos "git rebase master". Mas como estamos fingindo que estamos equipados apenas com o "git cherry-pick", fazemos:
Depois de todas essas operações, nosso gráfico de confirmação ficará assim:
Como podemos ver, os commits # 6 e # 7 foram aplicados contra 7254931 (um commit de ponta do master). HEAD foi movido e aponta um commit que é, essencialmente, uma ponta de um branch rebased. Agora, tudo o que precisamos fazer é excluir um ponteiro de branch antigo e criar um novo:
test_branch_1 agora está enraizado na última posição mestre. Feito!
fonte
cherry-pick
é capaz de aplicar uma série de commits, acho que sim. Embora esta seja uma maneira um pouco estranha de fazer as coisas, nada impede que você selecione todos os commits em seu branch de recursos emaster
, em seguida, exclua o branch de recursos e recrie-o de forma que aponte para a ponta demaster
. Você pode pensargit rebase
a partir de uma sequência degit cherry-pick feature_branch
,git branch -d feature_branch
egit branch feature_branch master
.Ambos são comandos para reescrever os commits de um branch em cima do outro: a diferença está em qual branch - "seu" (o atualmente em check-out
HEAD
) ou "deles" (o branch passado como um argumento para o comando) - é a base para esta reescrita.git rebase
pega um commit inicial e repete seus commits como se fossem os deles (o commit inicial).git cherry-pick
pega um conjunto de commits e reproduz os commits deles como vindo depois do seu (seuHEAD
).Em outras palavras, os dois comandos são, em seu comportamento central (ignorando suas características de desempenho divergentes, convenções de chamada e opções de aprimoramento), simétricos : fazer check-out do branch
bar
e executargit rebase foo
define obar
branch com o mesmo histórico que o check-out do branchfoo
e a execuçãogit cherry-pick ..bar
definiriafoo
para (as mudanças defoo
, seguidas pelas mudanças debar
).Em termos de nomenclatura, a diferença entre os dois comandos pode ser lembrada em que cada um descreve o que faz ao branch atual :
rebase
torna o outro chefe a nova base para suas alterações, enquantocherry-pick
escolhe as alterações do outro branch e as coloca no topo seuHEAD
(como cerejas em cima de um sundae).fonte
Ambos fazem coisas muito semelhantes; a principal diferença conceitual é (em termos simplificados) que:
rebase move os commits do branch atual para outro branch .
as cópias selecionadas para commits de outro branch para o branch atual .
Usando diagramas semelhantes à resposta de @Kenny Ho :
Dado este estado inicial:
... e assumindo que você deseja que os commits do
topic
branch sejam reproduzidos no topo domaster
branch atual , você tem duas opções:Usando rebase: primeiro, você iria para
topic
fazendogit checkout topic
e, em seguida, moveria o branch executandogit rebase master
, produzindo:Resultado: seu branch atual
topic
foi realocado (movido) paramaster
.A
topic
filial foi atualizada, enquanto amaster
filial permaneceu no local.Usando a escolha seletiva : primeiro você iria para
master
fazendogit checkout master
e, em seguida, copiasse o branch executandogit cherry-pick topic~3..topic
(ou, equivalentemente,git cherry-pick B..G
), produzindo:Resultado: os commits de
topic
foram copiados paramaster
.A
master
filial foi atualizada, enquanto atopic
filial permaneceu no local.Claro, aqui você teve que dizer explicitamente a pick-pick para escolher uma sequência de commits , usando a notação de intervalo
foo..bar
. Se você simplesmente tivesse passado o nome do branch, como emgit cherry-pick topic
, ele teria obtido apenas o commit na ponta do branch, resultando em:fonte