Como 'sobrescrever', em vez de 'mesclar', uma ramificação em outra ramificação no Git?

257

Eu tenho dois galhos emailestaging . stagingé a mais recente e não preciso mais das alterações antigas no emailramo, mas não quero excluí-las.

Então, eu só quero despejar todo o conteúdo stagingem emailmodo que ambos apontam para o mesmo cometeu. Isso é possível?

Rafid
fonte
4
Possível duplicado da Mudança o ramo atual para mestrado em git
Tomas Kubes

Respostas:

196

Você pode usar a estratégia de mesclagem 'nossa':

$ git checkout staging
$ git merge -s ours email # Merge branches, but use our branch head
knittl
fonte
26
Eu tentei isso, e isso me parece inverso? Isso não despeja o conteúdo do email na preparação e não o contrário?
Max
27
@ Max tive a mesma confusão e isso me causou muitos problemas. Você precisa executar este comando a partir da ramificação mais recente (preparo) e, em seguida, fazer uma mesclagem / PR normal com a ramificação antiga (email).
precisa saber é o seguinte
7
Por que ;no final de cada comando? Eu fiz sem o ;e parece estar funcionando. Além disso, esta resposta está incompleta, o terceiro passo é fazer o checkout do ramo antigo (email) e depois mesclar com o teste novamente.
Rosdi Kasim
4
git rebase -s theirs <oldbranc> <newbranch> também funciona (não importa qual ramo você seja). Observe que em rebase 'deles' é realmente o newbranch porque 'nosso' é a cabeça na qual estamos aplicando os commits.
Rolf
4
@Rolf: mas o rebase se livrará das informações de mesclagem e achatará a história. Não necessariamente o que você procura. Também não é uma boa ideia, se você estiver trabalhando com o histórico já publicado.
knittl
99

Se você deseja que os dois ramos 'email' e 'teste' sejam iguais, é possível marcar o ramo 'email' e redefinir o ramo 'email' para o 'teste':

$ git checkout email
$ git tag old-email-branch
$ git reset --hard staging

Você também pode refazer a ramificação 'teste' na ramificação 'email'. Mas o resultado conterá a modificação dos dois ramos.

Sylvain Defresne
fonte
1
você provavelmente média git checkout, git checknão existe a meu conhecimento
knittl
4
Você está certo, estou tão acostumado a tabular a conclusão do comando git que sempre escrevo "git check <TAB>" para escrever "git checkout"! Corrigido.
Sylvain Defresne
17
breaks git reset o reporte de outras pessoas que clonaram seu repo
Geoffrey De Smet
Eu acredito que esta é a resposta certa. emailA cabeça do ramo deve apontar apenas para a mesma cabeça staginge ambos terão os mesmos commits, a mesma história.
Cicerocamargo
76

Eu já vi várias respostas e esse é o único procedimento que me permite corrigir isso sem nenhum conflito.

Se você deseja todas as alterações de branch_new em branch_old, então:

git checkout branch_new
git merge -s ours branch_old
git checkout branch_old
git merge branch_new

Uma vez aplicados esses quatro comandos, você pode enviar o branch_old sem nenhum problema

Brugolo
fonte
5
Sua resposta realmente se encaixou melhor no meu problema, pois eu não queria redefinir o HEAD, apenas indique uma preferência pelos arquivos mais recentes no ramo mais novo ao mesclar as coisas com o mais antigo e funcionou sem problemas! +1
fogões
Enviei meu branch_new para remote após a "nossa mesclagem", e esse método funcionou para mim. Era necessário empurrar? Ou teria funcionado sem? (Não tinha certeza se usaria a filial local ou remota). Obrigado!
aspergillusOryzae
Por que você não pode simplesmente fazer o abaixo? git checkout branch_old git merge -s deles branch_new Pista retirada de stackoverflow.com/questions/14275856/…
Ripu Daman
Ele diz que não foi possível encontrar a estratégia de mesclagem 'deles'.
arango_86
Funciona perfeitamente para mim, tem a vantagem de não zerando tudo
Romain
68

As outras respostas me deram as pistas certas, mas não ajudaram completamente.

Aqui está o que funcionou para mim:

$ git checkout email
$ git tag old-email-branch # This is optional
$ git reset --hard staging
$
$ # Using a custom commit message for the merge below
$ git merge -m 'Merge -s our where _ours_ is the branch staging' -s ours origin/email
$ git push origin email

Sem a quarta etapa da fusão com a nossa estratégia, o push é considerado uma atualização sem avanço rápido e será rejeitado (pelo GitHub).

Shyam Habarakada
fonte
Isso faz com que a mensagem de confirmação de mesclagem esteja errada, mas sim, funciona muito bem.
precisa saber é o seguinte
cdunn2001, estou curioso. Qual era a mensagem de confirmação de mesclagem que você esperava e como isso foi atrapalhado?
Shyam Habarakada
Ele diz "Mesclar 'origem / email' da filial de rastreamento remoto no email". Não menciona estadiamento. Não é grande coisa embora. Basta alterar o commit ou usar merge -m 'This is not my beautiful house.' -s ours origin/email.
precisa saber é o seguinte
@ShyamHabarakada, eu faço o que você diz, e eu recebo o problema com a atualização de avanço rápido. porque nada acontece quando eu faço o quarto passo.
precisa saber é o seguinte
O quarto passo exige que você use a origem / email, ele não funciona apenas com o email local.
Travis Reeder
45

Se você é como eu e não deseja lidar com a mesclagem, pode executar as etapas acima, exceto usar força em vez de mesclar, porque isso criará uma trilha de papel de registro que distrai:

git checkout email
git reset --hard staging
git push origin email --force

Nota: Isso é apenas se você REALMENTE nunca quiser ver o material novamente por e-mail.

jsarma
fonte
1
email de origem do git push --force não funcionou para mim, pois a Etapa 2 deixou os ramos divergentes. Então, depois Passo 2, é isso que eu fiz: git reset origem / e-mail e empurrar então git
user3505394
2
Isso é exatamente o que foi perguntado em questão - "como substituir em vez de mesclar". Deve ser aceita resposta.
jozols
17

Eu queria mesclar duas ramificações para que todo o conteúdo old_branchfosse atualizado com o conteúdo denew_branch

Para mim, isso funcionou como um encanto:

$ git checkout new_branch
$ git merge -m 'merge message' -s ours origin/old_branch
$ git checkout old_branch
$ git merge new_branch
$ git push origin old_branch
Madhu
fonte
10

E se:

git branch -D email
git checkout staging
git checkout -b email
git push origin email --force-with-lease
Arek S
fonte
@emptywalls porque faz um push forçado sem avisar o usuário de que pode ser rejeitado pelo servidor, nem explica por que é necessário. Dito isto, é uma opção viável para um projeto de um desenvolvedor
David Costa
@DavidCosta, por que isso seria rejeitado pelo servidor? este é um ramo de email de exclusão simples e cópia de teste para email '... Então, eu só quero despejar todo o conteúdo de' teste 'em' email 'para que ambos aponte para o mesmo commit' - é exatamente o que está acontecendo aqui.
Arek S
@ArekS, ele pode ser recusado por um gancho do lado do servidor se a ramificação estiver definida como "protegida", por exemplo, no GitLab. O problema é que, se alguém derivado seu ramo de e-mail antes desta operação e, em seguida, tenta empurrar, as referências não correspondem mais (porque alguns commits simplesmente desapareceu)
David Costa
1
Editei o original de --force para --force-with-lease, que faz o truque de maneira não destrutiva.
Frandroid
1
Essa é a melhor maneira, se você quiser apenas remover um ramo e iniciá-lo a partir do ramo de origem.
Shane
6

Outras respostas pareciam incompletas.
Eu tentei abaixo na íntegra, e funcionou bem.

NOTA:
1. Faça uma cópia do seu repositório antes de tentar abaixo, por segurança.

Detalhes:
1. Todo o desenvolvimento acontece no ramo de desenvolvimento
2. qa ramo é apenas a mesma cópia do desenvolvimento
3. De tempos em tempos, o código de desenvolvimento precisa ser movido / sobrescrito no ramo qa

então precisamos sobrescrever qa branch, do dev branch

Parte 1:
Com os comandos abaixo, o antigo qa foi atualizado para o desenvolvedor mais recente:

git checkout dev
git merge -s ours qa
git checkout qa
git merge dev
git push

O comentário automático para o último push é apresentado abaixo:

// Output:
//  *<MYNAME> Merge branch 'qa' into dev,*  

Este comentário parece reverso, porque a sequência acima também parece reversa

Parte 2:

Abaixo estão inesperados, novos commits locais no dev, os desnecessários,
então precisamos jogar fora e tornar o dev intocado.

git checkout dev

// Output:
//  Switched to branch 'dev'  
//  Your branch is ahead of 'origin/dev' by 15 commits.  
//  (use "git push" to publish your local commits)


git reset --hard origin/dev  

//  Now we threw away the unexpected commits

Parte 3:
Verifique se tudo está como o esperado:

git status  

// Output:
//  *On branch dev  
//  Your branch is up-to-date with 'origin/dev'.  
//  nothing to commit, working tree clean*  

Isso é tudo.
1. qa antigo agora é sobrescrito pelo novo código de ramificação do desenvolvedor
2. o local está limpo (origem remota / dev é intocado)

Manohar Reddy Poreddy
fonte
6

A maneira mais fácil de fazer isso:

//the branch you want to overwrite
git checkout email 

//reset to the new branch
git reset --hard origin/staging

// push to remote
git push -f

Agora, o ramo de email e a preparação são os mesmos.

B.Neo
fonte
2
Aviso: Isso exclui todas as confirmações na emailramificação. É como excluir o emailramo e criá-lo novamente no início do stagingramo.
Cameron Hudson
2
git checkout email
git merge -m "Making email same as staging disregarding any conflicts from email in the process" -s recursive -X theirs staging
Willa
fonte
1
Essa resposta teria sido mais clara para mim se o comentário fosse separado do comentário mesclado no comando. Explique brevemente o que -X faz e como isso afeta essa mesclagem. Obrigado embora. Me fez procurar :)
noelicus 14/02/19
@noelicus obrigado pelo comentário e você está certo. Eu posso editar a resposta no futuro.
Willa
0

Este não altera a ramificação mais recente original e oferece a oportunidade de fazer outras modificações antes da confirmação final.

git checkout new -b tmp
git merge -s ours old -m 'irrelevant'
git checkout old
git merge --squash tmp
git branch -D tmp
#do any other stuff you want
git add -A; git commit -m 'foo' #commit (or however you like)
Jan Kyu Peblik
fonte