Trabalhando em uma ramificação com dependência de outra ramificação que está sendo revisada

65

Como o git ajuda a lidar com o cenário abaixo:

Eu tenho uma tarefa dividida em 2 partes: tarefa de back-end e tarefa de front-end. Eu faço uma solicitação pull para mesclar as alterações de back-end e espero que sejam mescladas (e endereçar comentários). Enquanto aguardo, não posso trabalhar nas alterações de front-end, pois depende de alterações de back-end e elas ainda não estão disponíveis na ramificação principal.

Qual é a melhor maneira de obter alterações para ramificação de alterações de front-end do ramo de alterações de back-end enquanto ele ainda está sendo revisado?

sul4bh
fonte
14
Bem, geralmente, as interfaces do projeto de back-end devem ser claramente definidas. Portanto, ao iniciar sua implementação de front-end, isso não deve incomodá-lo, se a lógica do back-end ainda for revisada, pois você pode usar uma simulação.
Herr Derb
17
@HerrDerb Oh doce criança verão ...
gardenhead
4
Por que você não pode escrevê-lo no seu código de back-end ainda não revisado?
user253751
Sua equipe tem algum tipo de técnica acordada para lidar com essa situação? Caso contrário, talvez você deva concordar com algo assim, já que é uma situação bastante comum.
Radu Murzea
Não há nenhum. Essa é a razão pela qual eu fiz essa pergunta. Eu recebi sugestões muito boas. Vou experimentar as sugestões e ver como elas funcionam para mim.
sul4bh

Respostas:

42

Eu também tenho esse problema algumas vezes. Git é muito flexível. Aqui está uma maneira de fazer isso.

Sua primeira filial featureAestá em revisão.

Seu segundo ramo featureBestá em desenvolvimento e depende do código no featureAramo.

Mesclar a featureAramificação na featureBramificação.

Se você fizer alterações na featureAramificação, deverá mesclar featureAa featureBramificação novamente para incorporar as alterações.

Você também deve se fundir featureAao tronco principal primeiro, caso contrário, ao se fundir featureBno tronco principal, você inadvertidamente também será mesclado featureA. Depois de featureAmesclado no tronco principal, você pode se livrar do featureAramo, pois agora featureBsó depende do tronco principal.

Eu prefiro quando meus ramos de recursos não dependem um do outro, mas às vezes eles dependem e você precisa seguir com ele.

Matt
fonte
Isso faz sentido. Isso permite desfazer a fusão de featureApara, featureBse necessário?
sul4bh
8
Não há nenhuma operação de desfazer, mas como o @ 9000 menciona, você pode fazer uma nova ramificação e escolher os commits que deseja, featureAcaso precise começar de novo. É bom pensar nos galhos do Git como descartáveis. Eles são baratos e fáceis, você sempre pode fazer uma nova filial. Você pode até criar uma ramificação de teste fora de sua featureBramificação, se quiser brincar com algo que não tem certeza, e depois descartá-la se não der certo, ou mesclar de volta para sua featureBramificação, se isso acontecer.
Matt
9
A fusão criará uma confusão que será difícil (não impossível) de reverter. Gostaria de escolher cereja ou rebascar (ou seja: escolher cereja tudo no recurso A na base do recurso B). Veja a resposta do 9000.
Pierre.Sassoulas
11
Isso cria uma história complexa que vai ser um problema para muitos anos sempre que alguém quer entender o código foi alterado para featureA e featureB
Ian
2
se featureA é atualizado, featureB deve ser rebased não fundiu
Lyndon Branca
40

Espere, pule a fusão

Para esta abordagem, você não deseja mesclar sua feature_aem feature_brepetidamente.

O rebase foi mencionado em outras respostas, mas apenas para rebater as coisas master. O que você quer fazer no seu caso é:

  • Comece o seu feature_bde feature_a, ou seja:

    git checkout feature_a
    git checkout -b feature_b
    
  • Sempre que feature_amudar enquanto aguarda a fusão master, você a refaz feature_b :

    ... commit something onto feature_a ...
    git checkout feature_b
    git rebase feature_a
    
  • Por fim, assim que feature_afor mesclado master, você simplesmente obtém o novo mastere o refaz feature_auma última vez:

    git checkout master
    git pull origin master
    git checkout feature_b
    git rebase --onto master feature_a feature_b
    

    Essa nova versão final enxertará todos os commits que estão pendurados no feature_acommit (que agora é irrelevante como foi mesclado master) diretamente master. Seu feature_bagora é um ramo simples, padrão indo para a direita a partir master.

EDIT: inspirado nos comentários, um pouco de atenção: se você precisar fazer alguma alteração que afeta os dois recursos, certifique-se de inseri-lo feature_a(e depois refazê-lo conforme mostrado). Você não fazê-lo em dois commits diferentes em ambos os ramos, mesmo que possa ser tentador; como feature_afaz parte da história de feature_b, ter uma única alteração em dois commits diferentes estará semanticamente errada e possivelmente levará a conflitos ou "ressurreições" de código indesejado posteriormente.

AnoE
fonte
2
Com o rebaseamento feature_avárias vezes, é possível que ocorram problemas mais tarde, quando o feature_amesmo foi rebatizado nesse meio tempo. Como resultado da execução, git checkout feature_b; git rebase feature_avocê pode ter conflitos ou algumas confirmações engraçadas contendo confirmações, revertendo novas alterações de feature_a. Isso geralmente é solucionável usando --interactivee ignorando confirmações retiradas da versão antiga do outro ramo (eu tive que fazer isso várias vezes recentemente).
Maaartinus
@maaartinus, obrigado pelo aviso, eu mesmo não tive esses problemas. Assim rebasecomo muitas etapas individuais, mais do que uma simples merge, há certamente uma chance muito maior de criar conflitos; por outro lado, mergeseria semântica o bastante errado nesse caso.
AnoE
Eu acho mergeque teria problemas semelhantes ou piores (um conflito não é tão ruim quanto entrar em uma mudança indesejada). Eu vejo um ramo como uma sequência de alterações desejadas precedidas por muitas alterações não relacionadas (pertencendo logicamente a um ramo diferente). Ao refazer repetidamente o mesmo ramo, sempre removo as alterações não relacionadas, pois sei que elas ocorrerão de qualquer maneira (possivelmente em uma forma atualizada) e elas funcionam bem.
Maaartinus
11
@maaartinus, adicionei um pequeno adendo sobre isso (para fazer alterações consistentemente que precisam entrar nos dois ramos apenas no ramo base, não em dois commits diferentes).
AnoE
Boa técnica. É como sempre faço também. git rebase --ontoFTW: D
Radu Murzea
29

Você já possui uma ramificação da qual cada ramificação de recursos depende e que continua mudando. É chamado master.

A maneira típica de uma ramificação de recurso permanecer sincronizada masteré ficar em cima dela. Quando mastermuda, você normalmente está git fetch origin master:master && git rebase masterno diretório de trabalho de sua filial.

Você pode fazer o mesmo com outra ramificação de recursos: continue a buscá-la e a refazê-la em cima dela.

Se, por algum motivo, você precisar mover suas alterações para uma ramificação diferente, poderá escolher suas confirmações, que nunca serão misturadas com as confirmações de outras ramificações.

9000
fonte
Mas acho que o cenário é que o recurso-b precisa do código que está no recurso-a, a ramificação do master não será muito útil. Por onde devo começar? Devo ramificar do recurso-a e mantê-los sincronizados até que o recurso-a seja reintegrado ao mestre e, em seguida, refizemos o processo de mestre para o recurso-b?
Sinaesthetic
@ Sinestésico: é claro que você pode basear feature-b-se feature-ae fazer uma reformulação repetidas vezes, conforme a feature-amudança. Essa é uma maneira típica de tornar uma grande alteração observável: divida-a em part-A(com base em master), part-B(com base em part-A) e muito mais, se necessário. Em seguida, faça uma solicitação de recebimento para cada peça, e os revisores terão mais facilidade em analisar peças menores e agrupadas logicamente.
9000
importará se eu refazer a parte-b com a parte-a vs. parte-b com o mestre em termos de relações públicas? Eu só quero ter certeza de que minhas alterações não estão mostrando alterações da parte A como alterações na parte b. Além disso, se eu mesclar x rebase, como isso afetará o PR da parte b? Toda vez que acho que entendo os efeitos, recebo resultados diferentes
Sinaesthetic
5

Nesse caso, em que a tarefa de front-end tem uma dependência crítica do código de back-end e você deseja iniciar o trabalho no front-end antes que o back-end seja finalizado e aceito no master, eu simplesmente iniciaria a tarefa de front-end como uma ramificação de recurso proveniente do ramificação de back-end, em vez de ramificar a interface no mestre.

Um ramo de recurso que dura o tempo suficiente precisa mesclar alterações do mestre ocasionalmente (para garantir que você reconcilie qualquer conflito de mesclagem ou semântica como parte do trabalho de desenvolvimento no ramo de recurso, em vez de como parte da "revisão, qa, mesclagem dominar "). Portanto, você faz isso no seu ramo de front-end e, quando o trabalho de back-end for aceito como mestre, você receberá pequenas alterações feitas no back-end como parte de sua revisão / aceitação automaticamente, pela mesma rota que você obtenha outras alterações de código no master.

Se o ramo de back-end precisar de muito mais trabalho e continuar a mudar por um período de tempo antes de ser mesclado para mestre (por exemplo, se forem encontrados grandes problemas durante a revisão), você provavelmente desejará fazer mesclagens periódicas diretamente do ramo de back-end para o ramo de front-end (para que você não continue baseando todo o seu trabalho de front-end em código de back-end obsoleto). Isso é fácil se você é o único desenvolvedor que executa os dois recursos (já que você sabe se faz grandes alterações), mas mesmo que os dois acabem sendo trabalhados em paralelo por desenvolvedores diferentes, tudo bem; você só precisa manter a comunicação (o que você precisaria de qualquer maneira, se estiver trabalhando em tarefas paralelas em que uma tenha uma dependência crítica da outra).

Se acontecer que todo o ramo de back-end precisa ser abandonado e nunca será mesclado (parece que isso seria um negócio muito importante que raramente aconteceria), então você escolhe seus compromissos para um novo ramo saindo do master sem o trabalho de back-end ou você aplica confirmações reversas que removem todo o código de back-end para a ramificação de front-end. Mas, como posso ver, seria mais provável pausar o trabalho de front-end até você descobrir o que iria substituir o back-end que está jogando fora e depois decidir o que fazer.

Ben
fonte
2

Não vejo o problema aqui.

Você já tem isso o tempo todo com sua masterfilial, que continua mudando enquanto os recursos são desenvolvidos e depois mesclados.

Portanto, em seu exemplo concreto, você primeiro cria a feature_xxx_backendramificação e desenvolve as alterações de back-end. Quando isso for feito, a filial poderá revisar e será mesclada masterassim que a revisão for concluída.

Então, simplesmente inicie outro ramo feature_yyy_frontend,. Você provavelmente desejará ramificar diretamente de feature_xxx_backend, para que você já tenha essas alterações em seu branc. então simplesmente desenvolva o recurso de front-end como o ramo era master.

Quando a feature_xxx_backendramificação muda, por exemplo, porque existem coisas que surgem durante a revisão que precisam ser corrigidas, basta fazer essas alterações e fundi-las na feature_yyy_frontendramificação. Continue na ramificação da interface.

Depois que a revisão da ramificação de back-end é concluída, ela é mesclada master. Nesse ponto, seria aconselhável refazer a feature_yyy_frontendramificação para masterque os revisores precisem revisar apenas as novas alterações para as quais essa ramificação contribui mastere não precisem revisar novamente as alterações feitas no back-end (que já foram aprovadas )

Isso também pode ser feito quando você tem dois, três ou mais ramos dependentes. Se você possui dois ramos de recurso dos quais você depende, basta criar um ramo derivado com ambos os recursos mesclados. Ramificar a partir daí, desenvolver o terceiro recurso, mesclar os dois ramos de recurso ao longo do caminho quando cada um deles mudar. Quando os dois recursos estiverem concluídos e forem mesclados na ramificação derivada, refazem-se a isso ou, se eles forem mesclados no mestre, faça uma nova recuperação no mestre.

O rebaseamento (como sugerido acima) é realmente poderoso e ajuda a manter um registro limpo das alterações, facilitando muito as revisões.

Polygnome
fonte
2

Como o Polygnome mencionou, você pode realmente mesclar seu ramo de front-end com o ramo de back-end em vez dos mestres. Mesmo com a configuração de ramificação atual que você tem agora, você pode simplesmente:

git checkout frontend
git merge backend

ou simplesmente

git merge backend frontend

Lembre-se de que, se as alterações no back-end não forem aceitas e mais trabalho for necessário, você precisará mesclar as atualizações do back-end no front-end para evitar conflitos. Depois que as alterações forem aceitas no mestre, você poderá refazer o frontend no master para se livrar das confirmações de mesclagem do backend.

Tecnicamente, você também pode fazer tudo com o rebase, mas isso atrapalha o histórico de consolidação do seu ramo de front-end. De onde eu venho, isso é considerado uma prática ruim. YMMV

Joris Meys
fonte
"Estranho que ninguém mencionou que você pode realmente fundir o seu ramo frontend com o seu ramo de backend em vez dos mestres:" Este tem já foi mencionado, por exemplo, em minha própria resposta.
precisa
O front end do @ Polygnome não precisa ser ramificado diretamente do back-end. Ambos podem ser ramificados do mestre também, mas você ainda pode mesclá-los. Portanto, sua resposta não menciona isso na verdade.
precisa
Na verdade, minha resposta não sugere que você se ramifique diretamente do back-end, apenas indica que esse é provavelmente o caminho a seguir (já que você mescla essas alterações no ramo do front-end).
precisa
@ Polygnome então eu entendi sua resposta. Atualizado especialmente para você :-)
Joris Meys
Não sei quem votou mal, mas por favor me diga onde estou errado, para que eu também possa aprender algo.
precisa
1

A maioria das respostas aqui descreve corretamente o processo de mesclar as alterações da segunda ramificação para a primeira, mas elas não abordam como minimizar a quantidade de conflitos que talvez você precise resolver.

Sempre que você tiver dois conjuntos de grandes alterações que deseja revisar individualmente (como featureAe featureB), crie um PR que NÃO deve ser mesclado, mas para obter feedback antecipado sobre um PoC de featureA.

As pessoas poderão revisá-lo rapidamente (é apenas um PoC), e o objetivo é validar o design ou a abordagem geral.

Em seguida, você pode continuar trabalhando no recurso A, criar uma solicitação de recebimento e ramificar e trabalhar no recurso B.

A grande diferença é que agora você pode esperar featureAnão mudar radicalmente: o design e a abordagem já foram validados. A revisão do código e as alterações necessárias podem ser sutis e locais, em vez de "woops, você precisa de uma abordagem diferente". Isso irá minimizar a quantidade de trabalho que você precisa fazer para mesclar mais tarde featureBem featureA'código s, independentemente do método que você escolheu.

Alfa
fonte