Como posso usar o rebase git sem exigir um push forçado?

92

Em uma tentativa de alcançar o nirvana do git, estou passando o dia aprendendo como aproveitar o rebase para situações em que atualmente faço a fusão.

Ao percorrer o que considero ser um fluxo git 101 (que explico abaixo), preciso fazer isso push --forceao empurrar minhas alterações de volta à origem.

Eu não sou o único - eu sei que isso é um terreno coberto (ver 1 , 2 , 3 , 4 , 5 ), e entendo as razões técnicas pelas quais uma força é necessária. Meu problema é este --- há muitas (muitas) entradas de blog elogiando o rebase e como isso mudou suas vidas (ver 1 , 2 , 3 , 4 para listar alguns), mas nenhum deles menciona que push --forcefaz parte do seu fluxo. No entanto, quase todas as respostas às questões de stackoverflow existentes dizem coisas como "sim, se você vai rebase, você tem que usar push --force".

Dado o número e religiosidade dos defensores do rebase, tenho que acreditar que o uso de 'push --force' não é uma parte inerente de um fluxo de rebase e que, se alguém frequentemente tiver que forçar seus empurrões, eles estão fazendo algo errado .

push --forceé uma coisa ruim .

Então aqui está o meu fluxo. De que forma eu poderia alcançar os mesmos resultados sem uma força?

Exemplo Simples

Duas filiais:

  • v1.0 - um branch de lançamento, contém apenas patches
  • master - tudo para o próximo lançamento principal.

Eu tenho alguns commits de patch e alguns commits para o próximo lançamento.

pré-emergir

Eu gostaria de incorporar os patches ao meu mestre para que eles não se percam no próximo lançamento. Pré-iluminação, eu simplesmente:

git checkout master
git merge v1.0

Mas agora estou tentando

git checkout master
git rebase v1.0

Então agora estou aqui:

insira a descrição da imagem aqui

Hora de:

git push

Sem dados.

Roy Truelove
fonte

Respostas:

43

Rebasing é uma ótima ferramenta, mas funciona melhor quando você o usa para criar mesclagens de avanço rápido para ramificações de tópicos no master. Por exemplo, você pode realocar seu branch add-new-widget em relação ao master:

git checkout add-new-widget
git rebase -i master

antes de realizar uma fusão rápida do branch no master. Por exemplo:

git checkout master
git merge --ff-only add-new-widget

O benefício disso é que seu histórico não terá muitos commits de mesclagem complexos ou conflitos de mesclagem, porque todas as suas alterações serão realocadas na ponta do master antes da mesclagem. Um benefício secundário é que você fez o rebase, mas não precisa usar git push --forceporque não está destruindo o histórico no branch master.

Certamente, esse não é o único caso de uso para rebase, ou o único fluxo de trabalho, mas é um dos usos mais sensatos que já vi. YMMV.

Todd A. Jacobs
fonte
4
Obrigado CG, acho que "usá-lo para criar mesclagens de avanço rápido" é a chave. Não se aplica ao meu caso acima, onde tenho dois ramos ativos - um ramo de desenvolvimento e um ramo de lançamento, mas parece se aplicar muito bem para ramos de tópicos temporários que são necessários apenas por um período limitado de tempo, e então podem ser apagados assim que forem mesclados. Obrigado novamente.
Roy Truelove de
1
Eu entendo isso, mas a questão original permanece. Acho que a resposta real é a dada por @Fabien Quatravaux
IsmailS
4
Bem, você ainda teria que forçar o push do branch 1.0, não? Pelo menos, é assim que as coisas tendem a acontecer para mim o tempo todo. O método de Fabiens impediria que isso acontecesse.
joerx
23

@CodeGnome está certo. Você não deve realocar o master no branch v1.0, mas o branch v1.0 no master, isso fará toda a diferença.

git checkout -b integrate_patches v1.0
git rebase master
git checkout master
git merge integrate_patches

Crie um novo branch que aponte para v1.0, mova esse novo branch para cima do master e então integre a nova versão dos patches V1.0 ao branch master. Você vai acabar com algo como:

o [master] [integrate_patches] Another patch on v1.0
o A patch on v1.0
o Another change for the next major release
o Working on the next major release
|  o [v1.0] Another path on v1.0
|  o A patch on v1.0
| /
o Time for the release

Esta forma de usar o rebase é recomendada pela documentação oficial do git .

Acho que você está certo sobre git push --force: você só deve usá-lo se cometeu um erro e empurrou algo que não queria.

Fabien Quatravaux
fonte
Acho que essa é a melhor resposta para o problema específico do OP. Você cria uma ramificação de mesclagem temporária e rebase nela, então mescla para master e empurra para a origem. O branch temporário não precisa ser enviado para a origem. O único conselho adicional que eu daria é ter um branch de desenvolvimento ou qa em que o código mesclado / rebaseificado possa ser qualificado. Após a qualificação, esse código seria então mesclado apenas com ff no mestre. Isso permite o hotfix fácil se o processo de qualificação demorar muito. Este é basicamente o processo de "fluxo git".
Javid Jamae,
Obrigado Fabien, ótima resposta. Para aqueles de nós que querem apenas integrar as alterações mastere não se importam em mesclar o próprio branch de recursos, isso pode ser feito com:git checkout my-branch; git rebase master; git checkout master; git merge my-branch
Siavas
17

Você tem que forçar o push se você rebase, e você já publicou suas alterações, certo?

Eu uso um monte de rebase, mas publico em algo privado onde um push forçado não importa (por exemplo: meu próprio clone no GitHub, como parte de uma solicitação pull), ou eu faço o rebase antes de fazer push pela primeira vez.

Este é o coração do fluxo de trabalho em que você usa rebase, mas não force muito o push: não publique coisas até que estejam prontas, não faça o rebase depois de empurrar.

Daniel Pittman
fonte
Obrigado Dan. Você poderia me informar como o acima exposto deve ser alcançado então? Não é apenas um cenário em que o rebase se aplica?
Roy Truelove
2
Se você isolar todo o seu trabalho para ramificações de tópico, isso criará um bom cenário para rebase. Você rebasepuxou novas mudanças em seu branch de tópico, mas quando você completou as alterações daquele branch, você mergeo branch de volta ao branch de desenvolvimento principal.
redhotvengeance de
1
O problema é que você publicou o branch - então você precisa forçar o envio para o repositório. Você precisa desistir de um dos dois: publicar da maneira que você faz ou rebase. Desculpe.
Daniel Pittman
Parece que o rebasing não funciona neste cenário. v1.0 não é um branch de tópico, é um branch de lançamento, então nunca morrerá e terá que ser publicado.
Roy Truelove
5

Acho que há um bom caso de uso para esse padrão rebase-e-force-push que não é resultado de um push incorreto: trabalhar em um branch de recurso sozinho em vários locais (computadores). Eu faço isso com frequência, já que às vezes trabalho no escritório em meu desktop e às vezes em casa / local do cliente em meu laptop. Eu preciso fazer o rebase ocasionalmente para acompanhar o branch principal e / ou para tornar as fusões mais limpas, mas também preciso forçar o push quando deixo uma máquina para ir trabalhar em outra (onde eu apenas puxo). Funciona perfeitamente, contanto que eu seja o único trabalhando no galho.

8 quarenta
fonte
2
Eu tenho esse mesmo fluxo de trabalho (trabalhando em vários computadores / locais). Então, vamos assumir que você está trabalhando em um branch de tópico chamado 'mytopic'. Contanto que você sempre rebase uma ramificação local descartável (que é meramente uma ramificação do mytopic) em "master" e depois mescle isso de volta no mytopic, você nunca terá que forçar o push. O OP tem um cenário ligeiramente diferente, portanto, em um caso como esse, um empurrão de força pode ser necessário. No entanto, acho que o OP está rebatizando da maneira errada - se ele fizesse isso como eu descrevi, nenhum impulso de força seria necessário.
bwv549 de
3

Aqui está o que eu uso (assumindo que o nome do seu branch seja foobar ):

git checkout master              # switch to master
git rebase   foobar              # rebase with branch
git merge -s ours origin/master  # do a basic merge -- but this should be empty
git push origin master           # aaand this should work
cheiroso
fonte
2
Rebasing master parece estranho.
Emil Vikström de
2
gitnão é sem personalidade
cheirando a
1
git merge -s ours origin/<branch>foi o que corrigiu para nós
máx.
0

tl; dr mesclar com branches compartilhados, rebase com branches individuais. --force-with-leaseé uma alternativa mais segura à força e deve ajudá-lo a alcançar o dito nirvana git sem a natureza destrutiva da força.

Uma regra geral que vi funcionar para fluxos de trabalho de várias equipes é usar mergepara branches compartilhados (ou seja, master ou development) e usar rebaseao trabalhar em seu próprio branch de recurso. Aqui está um ciclo de vida típico de um ramo de recurso

git checkout master
git checkout -b new-feature
git commit -am "commit new work"
git push -u origin new-feature
# have code reviewed, run CI, etc.,
# meanwhile master has new commits
git checkout master
git pull
git rebase -i master # -i for interactive rebase allows you to squash intermediate commits
git push --force-with-lease
git merge master

Uma versão em inglês simples do que fizemos aqui:

  1. Criou um novo branch fora do master
  2. Trabalho concluído na filial e enviado para remoto
  3. rebaseado do mestre
  4. Empurre o trabalho para o remoto com force-with-lease
  5. mesclar no master com um log git muito limpo, reduzindo a confusão de mesclagens múltiplas de nosso branch compartilhado para que nosso branch "acompanhe" o master mais recente (branch compartilhado)

A 4ª etapa é MUITO importante e uma das principais razões pelas quais comecei a defender o uso de rebase. force-with-leaseverifica o remoto para ver se algum novo commit foi adicionado. Se o seu git pushfoi provado ser destrutivo, ele não vai empurrar!

Espero que isso dê a alguém mais confiança para usar o rebase.

lucasnad27
fonte