Quando é que usa o git rebase em vez de git merge?

quando é recomendado o uso de git rebase vs. git merge?

Ainda preciso de me fundir depois de um ajuste bem sucedido?

Author: Nick Volynkin, 2009-04-30

14 answers

Versão Curta

  • a junção pega em todas as alterações num ramo e junta-as noutro ramo num commit.
  • Rebase diz que eu quero o ponto em que eu me ramifiquei para mudar para um novo ponto de partida
Então, quando é que usas qualquer um?

Juntar

    Digamos que criou um ramo com o propósito de desenvolver um único recurso. Quando você quer trazer essas mudanças de volta para o mestre, você provavelmente quer merge (Você não cuidado com a manutenção de todos os commits provisórios).

Rebase

    Um segundo cenário seria se você começasse a fazer algum desenvolvimento e então outro desenvolvedor fizesse uma mudança não relacionada. Você provavelmente quer puxar e então ajustar para basear as suas alterações da versão atual do repo.
 981
Author: Rob Di Marco, 2016-07-18 14:23:54

É simples, com rebase você diz para usar outro ramo como a nova base para o seu trabalho.

Se você tem, por exemplo, um branch master e você cria um branch para implementar um novo recurso, diga que o nomeia cool-feature, claro que o branch master é a base para o seu novo recurso.

Agora, num certo ponto, você quer adicionar a nova funcionalidade que implementou no ramo master. Podias mudar para master e juntar o ramo cool-feature:

$ git checkout master
$ git merge cool-feature
Mas por aqui ... adiciona-se um novo envio simulado, se quiser evitar o histórico do spaghetti, poderá ajustar a base:
$ git checkout cool-feature
$ git rebase master

E depois fundi-lo em master:

$ git checkout master
$ git merge cool-feature

Desta vez, uma vez que a ramificação temática tem os mesmos commits de master plus com a nova funcionalidade, a junção será apenas um avanço rápido.

 298
Author: Aldo 'xoen' Giambelluca, 2018-10-05 23:18:57

Para complementara minha própria resposta mencionada por TSamper,

  • Um rebase é muitas vezes uma boa idéia para fazer antes de uma fusão, porque a idéia é que você integre em seu branch Y o trabalho do branch B sobre o qual você vai se fundir.
    Mas novamente, antes de se fundir, você resolve qualquer conflito em seu ramo (ou seja: "rebase", como em " replay my work in my branch a partir de um ponto recente do ramo B)
    Se concluído correctamente,a junção subsequente do seu ramo para o ramo B pode ser rápida.

  • Uma série de impacto diretamente o destino do ramo B, o que significa que a mescla melhor ser trivial, caso contrário, esse ramo B pode ser muito tempo para voltar a um estado estável (tempo para você resolver todos os conflitos)


O ponto de fusão depois de um ajuste de contas?

No caso que eu descrevo, eu rebase B para o meu ramo, só para ter o oportunidade de repetir o meu trabalho a partir de um ponto mais recente de B, mas enquanto ficar no meu ramo.
Neste caso, ainda é necessária uma fusão para trazer o meu trabalho" replayed " para B.

O outro cenário (descrito no Git Ready , por exemplo), é trazer o seu trabalho directamente em B através de um rebase (que conserva todos os seus commits agradáveis, ou até lhe dá a oportunidade de reordená-los através de um rebase interactivo).
Nesse caso (quando você refaz enquanto estando no ramo B), tem razão: não é necessária mais nenhuma junção:

Uma árvore git por omissão quando não nos fundimos nem nos reformulamos

rebase1

Nós conseguimos reajustar:

rebase3

Esse segundo cenário é todo sobre: como é que eu faço com que o novo recurso volte para o mestre.

O meu ponto, ao descrever o primeiro cenário de rebase, é lembrar a todos que um rebase também pode ser usado como um passo preliminar para isso (que sendo "get" new-feature back into master").
Você pode usar o rebase para primeiro trazer o master " em " o ramo de nova funcionalidade: o rebase irá repetir os commits de nova funcionalidade a partir do HEAD master, mas ainda assim no ramo de nova funcionalidade, movendo efectivamente o seu ramo a partir de um antigo commit master para HEAD-master.
Isso permite-lhe resolver quaisquer conflitos em o seu ramo (ou seja, isoladamente, permitindo ao mestre continuar a evoluir em paralelo se a sua fase de resolução de conflitos levar demasiado longo).
Então você pode mudar para master e merge new-feature (ou rebase new-feature para master Se você quiser preservar commits feito no seu ramo new-feature).

Então:

  • "rebase vs. merge" pode ser visto como duas formas de importar um trabalho em, digamos, master.
  • mas "rebase then merge" pode ser um fluxo de trabalho válido para resolver primeiro o conflito em isolamento, em seguida, trazer de volta o seu trabalho.
 254
Author: VonC, 2017-05-23 12:34:51

Muitas respostas aqui dizem que a fusão transforma todos os seus commits em um, e, portanto, sugere usar rebase para preservar os seus commits. Isto está incorrecto. E uma má ideia se você já tiver pressionado seus commits .

A junção não apaga os seus commits. A junção preserva o histórico! o Rebase reescreve a história, o que é uma coisa má depois de a teres empurrado.

Usar o merge -- not rebase sempre que já o tenha feito empurrar.

Aqui está a resposta de Linus (autor do git). É uma boa leitura. Ou você pode ler minha própria versão da mesma idéia abaixo.

Rebocar um ramo no mestre:

  • dá uma ideia incorreta de como os commits foram criados
  • polui master com um monte de commits intermediários que podem não ter sido bem testados
  • [[22]] poderia realmente introduzir quebras de construção sobre estes commits intermediários por causa das mudanças que foram feitas para mestre entre quando o ramo tópico original foi criado e quando ele foi rebatizado. Torna difícil encontrar bons lugares no mestre para fazer o check-out.
  • faz com que as datas nos comprometam a não se alinharem com a sua ordem cronológica na árvore. Então você veria que o commit A precede o commit B em master, mas o commit B foi escrito primeiro. (O quê?!)
  • produz mais conflitos porque os commits individuais no ramo temático podem envolver conflitos de fusão que devem ser individualmente resolvido (mentir ainda mais na história sobre o que aconteceu em cada commit).
  • é uma reescrita da história. Se o ramo que está sendo refeito foi empurrado em qualquer lugar (compartilhado com qualquer um que não seja você mesmo), então você lixou toda a gente que tem esse ramo desde que você reescreveu a história.

Em contraste, fundindo uma ramificação temática em master:

  • preserva o histórico de onde os ramos temáticos foram criados, incluindo qualquer fusão do master para o tópico branch para ajudar mantém-no actualizado. Você realmente tem uma idéia precisa de que código o desenvolvedor estava trabalhando quando eles estavam construindo.
  • master é um ramo composto principalmente de merges, e cada um desses commits merge são tipicamente 'bons pontos' na história que são seguros de verificar porque é onde o ramo tópico estava pronto para ser integrado.
  • Todos os commits individuais do ramo tópico são preservados, incluindo o fato de que eles estavam em um ramo tópico, de modo que isolar essas mudanças é natural e você pode perfurar onde necessário.
  • os conflitos de junção só têm de ser resolvidos uma vez (no ponto da junção) para que as alterações intermédias de commit feitas no ramo tópico não tenham de ser resolvidas de forma independente.
  • pode ser feito várias vezes sem problemas. Se você integrar seu ramo tópico para dominar periodicamente, as pessoas podem continuar a construir sobre o ramo tópico e ele pode continuar a ser fundido independentemente.
 154
Author: Andrew Arnott, 2016-01-22 02:46:30

TL; DR

Se tiver alguma dúvida, use a junção.

Resposta Curta

As únicas diferenças entre um rebase e uma junção são:

  • a estrutura da árvore resultante do histórico (geralmente apenas notável quando se olha para um grafo de commit) é diferente (um terá ramos, o outro não).
  • a junção irá geralmente criar um commit extra (por exemplo, nó na árvore).
  • a junção e o ajuste irão lidar com os conflitos de forma diferente. Rebase will conflitos presentes um commit em um momento em que o merge irá apresentá-los todos de uma vez.

Então a resposta curta é para escolher o rebase ou fundir com base no que você quer que a sua história se pareça com .

Resposta Longa

Existem alguns factores que deve considerar ao escolher qual a operação a utilizar.

É o ramo que está a receber alterações de outros programadores partilhados fora da sua equipa (por exemplo, código aberto, público)?

Se sim, não refaça. Rebase destrói o ramo e esses desenvolvedores terão repositórios quebrados / inconsistentes, a menos que eles usem git pull --rebase. Esta é uma boa maneira de perturbar os outros desenvolvedores rapidamente.

Quão hábil é a tua equipa de desenvolvimento? Rebase é uma operação destrutiva. Isso significa que, se você não aplicar corretamente, você perde o trabalho comprometido e / ou quebra a consistência dos repositórios de outros desenvolvedores. Trabalhei em equipas onde os programadores vieram todos de um tempo. quando as empresas podiam pagar pessoal dedicado para lidar com ramificações e fusão. Esses desenvolvedores não sabem muito sobre Git e não querem saber muito. Nestas equipas, não me arriscaria a recomendar rebasing por nenhuma razão.

O próprio ramo representa informações úteis

Algumas equipas usam o modelo branch-per-feature onde cada ramo representa uma funcionalidade(ou bugfix, ou sub-funcionalidade, etc.) Neste modelo, o branch ajuda a identificar conjuntos de commits relacionados. Por exemplo, pode-se reverter rapidamente uma característica revertendo a junção desse ramo (para ser justo, esta é uma operação rara). Ou diff uma característica comparando dois ramos (mais comum). Rebase iria destruir o ramo e isso não seria direto.

Também trabalhei em equipas que usaram o modelo branch-per-developer (já todos estivemos lá). Neste caso, o próprio ramo não transmite nenhuma informação adicional (o commit já tem o autor). Não haveria mal em alteracao.

Pode querer reverter a junção por alguma razão?

Reverter (como em desfazer) um rebase é consideravelmente difícil e/ou impossível (se o rebase teve conflitos) em comparação com reverter uma fusão. Se você acha que há uma chance que você vai querer reverter, então use merge.

Trabalhas numa equipa? Em caso afirmativo, está disposto a adoptar uma abordagem de tudo ou nada neste ramo?

As operações de ajuste de Base têm de ser puxadas com um git pull --rebase correspondente. Se está trabalhando sozinho você pode ser capaz de lembrar qual você deve usar no momento apropriado. Se você está trabalhando em uma equipe isso será muito difícil de coordenar. É por isso que a maioria dos fluxos de trabalho de ajuste recomendam o uso de ajuste para todas as concentrações (e git pull --rebase para todas as puxações).

Mitos Comuns

A junção destrói o histórico (commits de esmagar)

Assumindo que tens a seguinte junção:

    B -- C
   /      \
  A--------D

Algumas pessoas irão afirmar que a fusão "destrói" o histórico de commits porque se você deveria olhar para o log de apenas o branch mestre (A -- D) você perderia as mensagens de commit importantes contidas em B E C.

Se isto fosse verdade, não teríamos perguntas como esta. Basicamente, você verá B E C a menos que você explicitamente peça para não vê-los (usando --first-parent). Isto é muito fácil de tentar por si mesmo.

Rebase permite uma fusão mais segura / mais simples

As duas abordagens fundem-se de forma diferente, mas não é claro que uma é sempre melhor. do que o outro e pode depender do fluxo de trabalho do desenvolvedor. Por exemplo, se um desenvolvedor tende a se comprometer regularmente (por exemplo, talvez eles se comprometam duas vezes por dia à medida que passam do trabalho para casa), então pode haver um monte de commits para um determinado ramo. Muitos desses commits podem não se parecer nada com o produto final (eu tendem a refaturar minha abordagem uma ou duas vezes por característica). Se alguém estivesse a trabalhar numa área relacionada com o código e tentassem refazer as minhas alterações, poderia ser um pouco aborrecido. operacao.

O Rebase é mais fixe / sexy / mais profissional

Se gosta de alias rm a {[[5]} para "poupar tempo", então talvez o rebase seja para si.

Os Meus Dois Cêntimos Acho sempre que um dia vou encontrar um cenário em que o git rebase é a ferramenta fantástica que resolve o problema. Muito como eu acho que vou encontrar um cenário onde git reflog é uma ferramenta incrível que resolve o meu problema. Trabalho com o git há mais de cinco anos. Não foi. acontecer. Histórias confusas nunca foram um problema para mim. Nunca leio a história dos meus compromissos como um romance excitante. A maioria do tempo eu preciso de uma história eu vou usar git blame ou git bisect de qualquer maneira. Nesse caso, ter o Merge commit é realmente útil para mim porque se o merge introduziu o problema que é informação significativa para mim.

Actualização (4/2017)

Sinto-me obrigado a mencionar que, pessoalmente, suavizei o uso do rebase. embora o meu conselho geral ainda esteja de pé. Estive recentemente a interagir muito com o projecto de Material Angular 2. Eles usaram rebase para manter um histórico de commit muito limpo. Isso permitiu-me ver muito facilmente o que comete corrigiu um determinado defeito e se esse commit foi ou não incluído em um lançamento. Ele serve como um grande exemplo de usar o rebase corretamente.
 124
Author: Pace, 2017-05-23 12:18:30

Junção significa: criar um único commit novo que funde as minhas alterações no destino.

Rebase significa: criar uma nova série de commits, usando o meu conjunto actual de commits como dicas. Em outras palavras, calcular o que as minhas mudanças teriam parecido se eu tivesse começado a fazê-las a partir do ponto em que estou a rebocar. Após o ajuste, portanto, você pode precisar voltar a testar suas alterações e durante o ajuste, você possivelmente teria alguns conflitos.

Dado isto, porque haveria de o fazer? você refaz? Só para manter a história do desenvolvimento clara. Digamos que estás a trabalhar no recurso X e quando terminares, FUNDES as tuas alterações. O destino agora terá um único commit que diria algo ao longo das linhas de "added feature X". Agora, em vez de se fundir, se você se refez e então se funde, o histórico de desenvolvimento do Destino conteria todos os commits individuais em uma única progressão lógica. Isso torna a revisão de mudanças mais tarde muito mais fácil. Imagina o quanto difícil encontrarias ele para rever o histórico de desenvolvimento se 50 desenvolvedores estavam fundindo várias características o tempo todo.

Dito isto, se você já empurrou o branch que você está trabalhando em upstream, você não deve refazer, mas fundir em vez disso. Para ramos que não foram empurrados para montante, ajuste, teste e mesclagem.

Outra vez que você pode querer refazer é quando você quer se livrar de commits de seu ramo antes de empurrar rio acima. Por exemplo: Commits que introduzem algum código de depuração no início e outros comprometem-se a limpar o código. A única maneira de fazer isso é realizando um ajuste interativo: git rebase -i <branch/commit/tag>

Actualização: também deseja usar o rebase quando estiver a usar o Git para interface com um sistema de controlo de versões que não suporte histórico não-linear (subversion, por exemplo). Ao usar a ponte git-svn, é muito importante que as alterações que você juntar de volta ao subversion sejam uma lista sequencial de alterações no topo das alterações mais recentes no trunk. Só há dois. maneiras de fazer isso: (1) recriar manualmente as alterações e (2) Usando o comando rebase, que é muito mais rápido.

UPDATE2: uma maneira adicional de pensar em um rebase é que ele permite uma espécie de mapeamento do seu estilo de desenvolvimento para o estilo aceito no repositório que você está se comprometendo. Digamos que gosta de se comprometer em pequenos pedaços. Você tem um commit para corrigir um erro de Digitação, um commit para se livrar do código não utilizado e assim por diante. Quando terminares o que precisas de fazer, terás um longo tempo. série de commits. Agora vamos dizer que o repositório que você está se comprometendo encoraja grandes commits, então para o trabalho que você está fazendo, um esperaria um ou talvez dois commits. Como você pega sua cadeia de commits e os comprime para o que é esperado? Você usaria um ajuste interativo e esmagaria seus pequenos commits em menos pedaços maiores. O mesmo é verdade se o reverso era necessário-se seu estilo era alguns commits grandes, mas o repo exigiu longas strings de commits pequenos. Você usaria um ajuste de base para fazer isso também. Se você tivesse se Unido em vez disso, você agora enxertou seu estilo de commit no repositório principal. Se houver um monte de desenvolvedores, você pode imaginar o quão difícil seria seguir um histórico com vários estilos de commit diferentes após algum tempo.

UPDATE3: Does one still need to merge after a successful rebase? sim, tens. A razão é que um rebase essencialmente envolve uma "mudança" de commits. Como já disse acima, estes commits são calculados, mas se você tivesse 14 commits do ponto de ramificação, então assumindo nada se correr mal com o seu rebase, você será 14 commits à frente (do ponto em que você está se ajustando) depois que o rebase é feito. Tinhas um ramo antes de um ajuste de contas. Você terá um ramo do mesmo comprimento depois. Ainda precisa de se fundir antes de publicar as suas alterações. Em outras palavras, rebase quantas vezes você quiser (mais uma vez, só se você não empurrou suas alterações para cima). Fundir apenas depois de ajustar a base.

 65
Author: Carl, 2013-08-11 20:38:23

Antes da junção / ajuste:

A <- B <- C    [master]
^
 \
  D <- E       [branch]

Depois git merge master:

A <- B <- C
^         ^
 \         \
  D <- E <- F

Depois git rebase master:

A <- B <- C <- D' <- E'

(A, B, C, D, E E F são commits)

Este exemplo e informações muito mais bem ilustradas sobre o git podem ser encontradas aqui: http://excess.org/article/2008/07/ogre-git-tutorial/

 55
Author: guybrush, 2012-06-07 06:19:16
Embora a fusão seja definitivamente a maneira mais fácil e mais comum de integrar as mudanças, não é a única: ajustar a base é um meio alternativo de integração.

Entender mescla um pouco melhor

Quando o Git realiza uma junção, procura três commits:

  • (1) commit ancestral comum se você seguir a história de dois ramos em um projeto, eles sempre têm pelo menos um commit em comum: neste momento, ambos os ramos tinha o mesmo conteúdo e depois evoluiu de forma diferente.
  • (2) + (3) Endpoints de cada ramo o objetivo de uma integração é combinar os estados atuais de dois ramos. Por conseguinte, as suas últimas revisões têm especial interesse. A combinação destes três commits resultará na integração que pretendemos.

Avançar ou juntar a persistência

Em casos muito simples, um dos dois ramos não tem novos commits desde que a ramificação aconteceu. - seu último commit ainda é o ancestral comum.

enter image description here

Neste caso, realizar a integração é muito simples: o Git pode simplesmente adicionar todos os commits do outro ramo no topo do commit do ancestral comum. No Git, esta forma mais simples de integração é chamada de fusão "fast-forward". Ambos os ramos, então, compartilham o mesmo histórico.

enter image description here

Em muitos casos, porém, ambos os ramos avançaram. individualmente. enter image description here

Para fazer uma integração, o Git terá de criar um novo commit que contenha as diferenças entre eles - o Merge commit.

enter image description here

Humanos Commits & Merge Commits

Normalmente, um compromisso é cuidadosamente criado por um ser humano. É uma unidade significativa que envolve apenas mudanças relacionadas e anota-as com um comentário.

Um commit merge é um pouco diferente: em vez de ser criado por um desenvolvedor, ele é criado automaticamente pelo Git. E em vez de envolver um conjunto de mudanças relacionadas, seu propósito é conectar dois ramos, assim como um nó. Se você quiser entender uma operação de junção mais tarde, você precisa dar uma olhada no histórico de ambos os ramos e o grafo de commit correspondente.

Integração com Rebase

Algumas pessoas preferem ir sem tais commits de junção automática. Em vez disso, querem que a história do projecto pareça ter evoluído. numa única linha recta.[[9]] não há indícios de que tenha sido dividido em vários ramos em algum momento.

enter image description here

Vamos passar por uma operação de ajuste passo a passo. O cenário é o mesmo que nos exemplos anteriores: queremos integrar as mudanças de branch-B em branch-A, Mas agora usando rebase.

enter image description here

Vamos fazer isto em três passos.
  1. git rebase branch-A // syncs the history with branch-A
  2. git checkout branch-A // change the current branch to branch-A
  3. git merge branch-B // merge/take the changes from branch-B to branch-A

Primeiro, O Git irá "desfazer" todos os commits no branch - a que aconteceu depois que as linhas começaram a ramificar-se (após o commit ancestral comum). No entanto, é claro, ele não vai descartá-los: em vez disso, você pode pensar naqueles commits como sendo "salvos temporariamente".

enter image description here

A seguir, aplica os commits do branch-B que queremos integrar. Neste momento, ambos os ramos parecem exactamente iguais.

enter image description here

Na etapa final, os novos commits no branch - A são agora reaplicados-mas em uma nova posição, em cima dos commits integrados do branch-B (eles são re-baseados). O resultado parece que o desenvolvimento aconteceu em linha recta. Em vez de um commit de junção que contém todas as alterações combinadas, a estrutura de commit original foi preservada.

enter image description here

Finalmente você tem um ramo limpo branch-a sem commits indesejados e gerados automaticamente.

Nota: Retirado do espantoso posto por git-tower. As desvantagens de também são uma boa leitura no mesmo post.

 27
Author: Abdullah Khan, 2017-10-12 12:08:52
Esta frase diz:
Em geral, a maneira de obter o melhor de ambos os mundos é ajustar a base local mudanças que fizeste mas que ainda não partilhaste antes de as empurrares para dentro ordem para limpar a tua história, mas nunca refazas nada que tenhas empurrado algures.

Fonte: http://www.git-scm.com/book/en/v2/Git-Branching-Rebasing#Rebase-vs.-Merge

 25
Author: Joaquin Sargiotto, 2015-01-05 13:50:13

O livro pro git como uma explicação muito boa na Página de ajuste .

Basicamente uma junção irá pegar em 2 commits e combiná-los.

Um rebase irá para o ancestral comum no 2 e incrementalmente aplicar as mudanças em cima um do outro. Isto torna a história mais "limpa" e mais linear.

Mas quando você reiniciar você abandona os commits anteriores e cria novos. Por isso, nunca deves refazer um acordo que seja público. As outras pessoas que trabalham no Acordo de recompra vai odiar-te. Só por essa razão me fundi quase exclusivamente. 99% das vezes os meus ramos não diferem muito, por isso, se houver conflitos, é só em um ou dois lugares.
 15
Author: xero, 2013-09-06 07:40:00

Esta resposta é amplamente orientada em torno de fluxo Git. As tabelas foram geradas com o gerador de mesa ASCII de nice , e as árvores da história com este comando maravilhoso ( aliased as git lg):

git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
As tabelas estão em ordem cronológica inversa para serem mais consistentes com as árvores históricas. Veja também a diferença entre git merge e git merge --no-ff em primeiro lugar (você normalmente quer usar git merge --no-ff Porque faz a sua história olhar mais perto do Realidade):

git merge

Comandos:

Time          Branch "develop"             Branch "features/foo"
------- ------------------------------ -------------------------------
15:04   git merge features/foo
15:03                                  git commit -m "Third commit"
15:02                                  git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"
Resultado:
* 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo)
|           Third commit - Christophe
* 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago)
|           Second commit - Christophe
* 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge --no-ff

Comandos:

Time           Branch "develop"              Branch "features/foo"
------- -------------------------------- -------------------------------
15:04   git merge --no-ff features/foo
15:03                                    git commit -m "Third commit"
15:02                                    git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"
Resultado:
*   1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/foo' - Christophe
| * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago)
|/            Second commit - Christophe
* c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge vs git rebase

Primeiro ponto: sempre mesclar características em desenvolvimento, nunca refazer desenvolvimento a partir de características . Esta é uma consequência da regra de ouro de rebocar:

A regra de ouro de git rebaseé nunca usá-la em público ramo.

Por outras palavras::

Nunca refaça nada que tenha empurrado para algum lado.

Eu acrescentaria pessoalmente: a menos que seja um ramo de recurso e tu e a tua equipa estejam cientes das consequências.

Assim, a questão de git merge vs git rebase aplica-se quase apenas aos ramos das funcionalidades (nos exemplos seguintes, --no-ff Sempre foi usado quando se fundem). Note que como Não tenho a certeza se há uma solução melhor ([[93]} a o debate existe, só vou providenciar como se comportam ambos os comandos. No meu caso, prefiro usar git rebase pois produz uma árvore de história melhor:)

Entre os ramos das características

git merge

Comandos:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- --------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"
Resultado:
*   c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago)
| |\            Merge branch 'features/foo' into features/bar - Christophe
| * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | |           Fifth commit - Christophe
| * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | |           Fourth commit - Christophe
* | |   98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ \            Merge branch 'features/foo' - Christophe
| |/ /
|/| /
| |/
| * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

Comandos:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git rebase features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"
Resultado:
*   7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
| * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

De develop para uma característica branch

git merge

Comandos:

Time           Branch “develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m “Sixth commit"
15:08                                                                    git merge --no-ff development
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m “Fifth commit"
15:05                                                                    git commit -m “Fourth commit"
15:04                                    git commit -m “Third commit"
15:03                                    git commit -m “Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m “First commit"
Resultado:
*   9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago)
| |\            Merge branch 'develop' into features/bar - Christophe
| |/
|/|
* |   5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | |           Third commit - Christophe
| * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ /            Second commit - Christophe
| * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
* 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

Comandos:

Time           Branch “develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m “Sixth commit"
15:08                                                                    git rebase development
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m “Fifth commit"
15:05                                                                    git commit -m “Fourth commit"
15:04                                    git commit -m “Third commit"
15:03                                    git commit -m “Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m “First commit"
Resultado:
*   b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
*   856433e - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\            Merge branch 'features/foo' - Christophe
| * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

Notas de lado

git cherry-pick

Quando você só precisa de um commit específico, git cherry-pick é uma boa solução (a opção -x adiciona uma linha que diz " (cherry picked from commit...) " para o corpo original da mensagem de commit, por isso é geralmente uma boa ideia usá-lo - git log <commit_sha1> para ver it):

Comandos:

Time           Branch “develop"              Branch "features/foo"                Branch "features/bar"           
------- -------------------------------- ------------------------------- -----------------------------------------
15:10   git merge --no-ff features/bar                                                                            
15:09   git merge --no-ff features/foo                                                                            
15:08                                                                    git commit -m “Sixth commit"             
15:07                                                                    git cherry-pick -x <second_commit_sha1>  
15:06                                                                    git commit -m “Fifth commit"             
15:05                                                                    git commit -m “Fourth commit"            
15:04                                    git commit -m “Third commit"                                             
15:03                                    git commit -m “Second commit"                                            
15:02   git checkout -b features/bar                                                                              
15:01   git checkout -b features/foo                                                                              
15:00   git commit -m “First commit"                                                                              
Resultado:
*   50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago)
| |           Second commit - Christophe
| * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
|/|
| * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git pull --rebase

Não sei se consigo explicar melhor do que o Derek Gourlay... Basicamente, use git pull --rebase em vez de git pull:) o que está faltando no artigo é que você pode ativá-lo por padrão:
git config --global pull.rebase true

git rerere

Mais uma vez, bem explicado. Mas simplificando, se você ativá-lo, você não terá que resolver o mesmo conflito várias vezes mais.
 14
Author: sp00m, 2017-02-22 14:03:52

O git rebase é usado para tornar lineares os caminhos de ramificação na estrutura do histórico mais limpa e do repositório.

Ele também é usado para manter os ramos criados por você privados, como depois de ajustar e empurrar as alterações para o servidor, Se você excluir seu branch, não haverá nenhuma evidência de branch em que você trabalhou. Então a sua filial é agora a sua preocupação local.

Depois de fazer o rebase também nos livramos de um commit extra que costumávamos ver se fazíamos a fusão normal.

E sim um ainda precisa fazer o merge após um rebase bem sucedido como comando rebase apenas coloca o seu trabalho em cima do branch que você mencionou durante o rebase dizer Mestre e faz o primeiro commit de seu branch como um descendente direto do branch master. Isso significa que agora podemos fazer uma junção rápida para a frente para trazer mudanças deste branch para o branch mestre.

 4
Author: cvibha, 2013-09-24 06:11:26
Alguns exemplos práticos, um pouco ligados ao desenvolvimento em grande escala, onde o gerrit é utilizado para a revisão e integração da entrega. Fundi-me quando elevei o meu ramo para um novo comando remoto. Isso dá um trabalho de elevação mínimo e é fácil acompanhar a história do desenvolvimento de recursos em, por exemplo, gitk.
git fetch
git checkout origin/my_feature
git merge origin/master
git commit
git push origin HEAD:refs/for/my_feature
Fundi-me quando preparo um compromisso de entrega.
git fetch
git checkout origin/master
git merge --squash origin/my_feature
git commit
git push origin HEAD:refs/for/master
Rebase quando o meu compromisso de entrega falha a integração por qualquer razão e preciso de actualiza-o para um novo comando remoto.
git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase origin/master
git push origin HEAD:refs/for/master
 2
Author: Martin G, 2016-02-29 09:51:26

Quando é que eu uso git rebase? Quase nunca, porque reescreve a história. git merge é quase sempre a escolha preferível, porque respeita o que realmente aconteceu no seu projecto.

 -7
Author: Marnen Laibow-Koser, 2018-01-19 21:01:38