não pode empurrar para ramificar após rebase

131

Usamos o git e temos uma filial principal e uma filial do desenvolvedor. Preciso adicionar um novo recurso e depois refazer as confirmações para mestre, e depois enviar o mestre para o servidor de CI.

O problema é que, se eu tiver conflitos durante a reformulação, não poderei enviar para minha ramificação de desenvolvedor remoto (no Github) após a conclusão da rebase, até puxar minha ramificação remota. Isso causa confirmações duplicadas. Quando não há conflitos, funciona como esperado.

pergunta: após o rebase e a resolução de conflitos, como sincronizar minhas ramificações de desenvolvedor local e remota sem criar confirmações duplicadas

Configuração:

// master branch is the main branch
git checkout master
git checkout -b myNewFeature

// I will work on this at work and at home
git push origin myNewFeature

// work work work on myNewFeature
// master branch has been updated and will conflict with myNewFeature
git pull --rebase origin master

// we have conflicts
// solve conflict
git rebase --continue

//repeat until rebase is complete
git push origin myNewFeature

//ERROR
error: failed to push some refs to '[email protected]:ariklevy/dropLocker.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

// do what git says and pull
git pull origin myNewFeature

git push origin myNewFeature

// Now I have duplicate commits on the remote branch myNewFeature

EDITAR

Parece que isso interromperá o fluxo de trabalho:

developer1 trabalhando em myNewFeature developer2 trabalhando em hisNewFeature ambos usam master como ramificação principal

developer2 funde myNewFeature em hisNewFeature

developer1 rebase, resolve conflitos e força os push para ramificação remota para myNewFeature

alguns dias depois, o developer2 mescla myNewFeature no hisNewFeature novamente

Isso fará com que os outros desenvolvedores detestem o developer1?

Matt
fonte
Não é uma solução, mas apenas um pensamento. quem é we? você está em uma equipe de mais do que apenas você? theydiga (as pessoas que sabem mais do que eu) que, se você compartilhar seu código, não deverá usá-lo rebase. Por que você não está apenas fazendo git pulle git merge?
28813 AdamT
Desculpe, nós = equipe de desenvolvimento
Matt
1
então sim, provavelmente não deve ser reprovado quando você estiver compartilhando código. que podem levar você a ter de fazer coisas como o que está listado abaixo ( forceo push)
AdamT
oh desculpe, quando eles dizem rewriting history, isso é umrebase
AdamT 28/02
Como ele disse seu um ramo de desenvolvimento de seu próprio modo que não deve ser um problema a menos que alguém era esperado para mesclagem que no.
Learath2

Respostas:

93

Primeiro, você e aqueles com quem trabalha precisa concordar se um ramo de tópico / desenvolvimento é para desenvolvimento compartilhado ou apenas para você. Outros desenvolvedores sabem que não devem ser mesclados nos meus ramos de desenvolvimento, pois serão reformulados a qualquer momento. Normalmente, o fluxo de trabalho é o seguinte:

o-----o-----o-----o-----o-----o       master
 \
   o-----o-----o                      devel0
                \
                  o-----o-----o       devel1

Para manter-se atualizado com o controle remoto, faça o seguinte:

 git fetch origin
 git checkout master
 git merge --ff origin/master

Eu Faço Isso Por Duas Razões. Primeiro porque me permite ver se há alterações remotas sem precisar mudar do meu ramo de desenvolvimento. Segundo, é um mecanismo de segurança para garantir que eu não substitua nenhuma alteração não armazenada / confirmada. Além disso, se eu não conseguir avançar rapidamente com a ramificação mestre, isso significa que alguém rebasou o mestre remoto (para o qual eles precisam ser açoitados severamente) ou acidentalmente me comprometi a dominar e preciso limpar meu objetivo.

Então, quando o controle remoto tiver alterações e eu tiver encaminhado rapidamente para a versão mais recente, refiz o seguinte:

git checkout devel0
git rebase master
git push -f origin devel0

Outros desenvolvedores sabem que precisam refazer suas ramificações de desenvolvimento das minhas últimas:

git fetch <remote>
git checkout devel1
git rebase <remote>/devel0

O que resulta em um histórico muito mais limpo:

o-----o                                 master
       \
         o-----o-----o                  devel0
                      \
                        o-----o-----o   devel1

Não mescle commits de um lado para o outro ao seu capricho. Ele não apenas cria confirmações duplicadas e impossibilita o acompanhamento do histórico, é quase impossível encontrar regressões de uma alteração específica (é por isso que você está usando o controle de versão em primeiro lugar, certo?). O problema que você está tendo é o resultado de fazer exatamente isso.

Também parece que outros desenvolvedores podem estar comprometendo seus ramos de desenvolvimento. Você pode confirmar isso?

O único momento para mesclar é quando o ramo do tópico está pronto para ser aceito master.

Em uma nota lateral. Se vários desenvolvedores estão se comprometendo com o mesmo repositório, todos devem considerar nomear branches para distinguir entre desenvolvedores que desenvolvem branches. Por exemplo:

git branch 'my-name/devel-branch'

Portanto, todos os ramos de tópicos dos desenvolvedores residem em seu próprio conjunto aninhado.

Trevor Norris
fonte
1
"Também parece que outros desenvolvedores podem estar se comprometendo com seus ramos de desenvolvimento. Você pode confirmar isso?" SIM, eles são ...
Matt
Você também chamou minha atenção para outra questão. Trabalhando entre o escritório e a casa. Faço mesclagens em ambos os lugares e, no final do dia, empurro para que possa retomar de onde parei. Então, quando é hora de se recuperar, todos esses commits criam confusão. Preciso tratar meus galhos como um galho e refazer o processo
Matt
@ Matt Sim, esses dois problemas vão realmente estragar o seu fluxo de trabalho. Para o primeiro, eu comunicaria aos outros desenvolvedores que apenas o proprietário pode se comprometer com uma ramificação nomeada (por exemplo, 'matt / devel'). IMHO, não há dois desenvolvedores devem se comprometer com o mesmo ramo de qualquer maneira. Apenas cria confusão. Para o posterior, o rebaseamento e a força forçada devem manter os dois locais atualizados.
Trevor Norris
Ótima resposta. Eu tenho uma pergunta paralela, por que você está usando a --forcebandeira quando usa git push -f origin devel0?
Nobita
2
@Nobita Quando git pushnão é possível avançar rapidamente (ou seja, o histórico sha não corresponde), você deve forçar push para substituir o histórico anterior pelo novo histórico gerado a partir do git rebase.
Trevor Norris
50

Você precisa forçar o push à medida que moveu as confirmações mais abaixo na linha que o git espera que você adicione confirmações na ponta do ramo. git push -f origin myNewFeaturevai resolver o seu problema.

Dica: Acima está um uso legítimo de força forçada. Nunca reescreva a história em um repositório acessível ao público ou muitas pessoas o odiarão.

Learath2
fonte
1
Acho essa a maneira mais ideal de manter o fluxo de trabalho.
Syed Priom
1
Obrigado companheiro. Eu usei esse comando para forçar minha ramificação local rebased para a mesma ramificação remota.
wei
11
usar git push --force-with-leaseé muito mais seguro do que usar #git push --force
git push --force-with-lease origin HEAD- assumindo que o seu ramo de destino já está checkouted
Lucaci Sergiu
31

A principal coisa a ter em mente aqui é o que puxar e rebater estão fazendo nos bastidores.

Um puxão basicamente faz duas coisas: buscar e mesclar. Quando você incluir --rebase, ele fará uma nova recuperação em vez da mesclagem.

Uma rebase é praticamente como esconder todas as suas alterações locais desde que você ramificou, encaminhando rapidamente sua ramificação para a confirmação mais recente no destino e removendo as alterações na ordem em cima.

(Isso explica por que você pode receber vários prompts de resolução de conflitos ao fazer uma nova atualização versus a única solução de conflito que você pode obter com uma mesclagem. Você tem a oportunidade de resolver um conflito no EACH commit que está sendo reformulado para preservar seus commits. )

Você nunca deseja enviar alterações reformuladas para ramificações remotas, pois isso está reescrevendo o histórico. Ofcoarse, nunca é um pouco forte, pois quase sempre há exceções. O caso em que você precisa manter uma versão remota do seu repositório local para trabalhar em um ambiente específico, por exemplo.

Isso exigirá que você faça alterações rebaseadas às vezes usando força:

git push -f origin newfeature

Em alguns casos, seu administrador pode ter removido a capacidade de forçar, então você deve excluir e recriar:

git push origin :newfeature
git push origin newfeature

Em ambos os casos, você deve ter certeza absoluta de que sabe o que está fazendo se outra pessoa estiver colaborando com você em sua filial remota. Isso pode significar que você trabalha em conjunto inicialmente com mesclagens e as redimensiona para um formato de confirmação mais gerenciável antes de dominar e remover sua ramificação de trabalho.

Lembre-se de que você quase sempre pode usar o GC do git aproveitando:

git reflog

Este é um enorme salva-vidas, pois você pode voltar a um estado mais estável se se perder em todo o gerenciamento de rebase / conflito.

Matthew Sanders
fonte
A opção excluir e recriar acima funcionou bem para mim. Não é permitido forçar no meu repositório!
Simon Holmes
2

Você precisa executar um empurrão forçado, ou seja, git push -f origin myNewFeature

Ah, e é melhor você ter certeza de que as pessoas não baseiam nada no seu ramo de desenvolvimento - normalmente você não deve publicar ramos nos quais você está reescrevendo o histórico (ou melhor, não reescreva o histórico uma vez publicado). Uma maneira seria usar um nome de filial como wip/myNewFeaturee, em seguida, mencionar que as wipramificações serão reformuladas para dominar de tempos em tempos.

ThiefMaster
fonte
usando git push --force-with-leaseé muito mais seguro do que usargit push --force
@MrCholo As pessoas não vão começar a usar isso até que o git adicione uma pequena opção para ele, como -fpara um empurrão forçado normal :)
ThiefMaster 9/18
ha sim, eu usei-o em um script automatizado tho
2

A resposta geral que já foi dada - a ser usada git push -f origin myNewFeatureao pressionar alterações reformuladas - é um bom ponto de partida. Estou escrevendo esta resposta para abordar a edição sobre se isso interromperá seu fluxo de trabalho.

Se assumirmos que você está indo usar git pull --rebase ...(ou alguma variação sobre isso) seguido por uma força-push para o ramo remoto, então a única coisa que quebra o fluxo de trabalho no seu exemplo é developer2 está se fundindo myNewFeatureemhisNewFeature . Faz sentido poder refazer sua própria ramificação de recurso, desde que ninguém mais esteja trabalhando nessa ramificação, portanto, você precisa de regras para demarcar o território da ramificação.

Você pode contornar isso: a) estabelecendo uma regra da qual você apenas se une master; ou b) criando um developramo coletivo , no qual você baseia o seu próprio myNewFeatureramo, e estabelece uma regra da qual você apenas se une develop. masterserá reservado apenas para marcos ou liberações (ou de qualquer outra forma que você desejar configurar) e developserá onde você empurrará cada recurso quando estiver pronto para ser integrado a outras ramificações de recursos.

Acredito que isso possa ser considerado uma versão simplificada do fluxo de trabalho do Gitflow.

cosmicFluke
fonte
1

Concordo com MrCholo , e talvez Trevor Norris possa considerar atualizar sua boa resposta para substituir

git push -f origin devel0

com

git push --force-with-lease origin devel0
Sylvain Lesage
fonte