Como squash compromete no git depois que eles foram enviados?


550

Isso fornece uma boa explicação para esmagar várias confirmações:

http://git-scm.com/book/en/Git-Branching-Rebasing

mas não funciona para confirmações que já foram enviadas. Como faço para esmagar os poucos commit mais recentes nos meus repositórios locais e remotos?

EDIT: Quando eu faço git rebase -i origin/master~4 master, manter o primeiro como pick, definir os outros três como squashe, em seguida, sair (via cx cc no emacs), recebo:

$ git rebase -i origin/master~4 master
# Not currently on any branch.
nothing to commit (working directory clean)

Could not apply 2f40e2c... Revert "issue 4427: bpf device permission change option added"
$ git rebase -i origin/master~4 master
Interactive rebase already started

onde 2f40 é o pickcommit. E agora nenhum dos 4 commits aparece git log. Eu esperava que meu editor fosse reiniciado para que eu pudesse inserir uma mensagem de confirmação. O que estou fazendo errado?

Respostas:


780

Squash confirma localmente com

git rebase -i origin/master~4 master

e depois forçar empurrar com

git push origin +master

Diferença entre --forcee+

A partir da documentação de git push:

Observe que isso --forcese aplica a todas as refs que são enviadas por push , portanto, usá-lo com push.defaultdefinido como matchingou com vários destinos de envio configurados com remote.*.pushpode substituir refs que não sejam a ramificação atual (incluindo refs locais que estão estritamente por trás de sua contraparte remota). Para forçar um empurrão em apenas um ramo, use um + na frente do refspec para empurrar (por exemplo, git push origin +masterpara forçar um empurrão no masterramo).


30
você também podegit push --force origin master
Daenyth 14/04

7
Daenyth : Sim, mas eu sempre prefiro essa sintaxe, pois ela é mais curta.
Alan Haggai Alavi

86
E, é claro, perceba que, se alguém tiver retirado do repositório remoto, você provavelmente não deseja fazer isso - a resposta nesse caso é "você não".
Cascabel

10
Além disso, acho que o OP está copiando exatamente o comando git rebase -i origin/mastere, na verdade, quer saber como refazer os commits mais antigos do que isso, por exemplo git rebase -i origin/master~20 master.
Cascabel

6
gstackoverflow :+força apenas o refspec que é prefixado por ele. --forceforçará todos os refspecs sendo empurrados. Por favor, veja a resposta atualizada.
Alan Haggai Alavi

120

Em uma ramificação, eu pude fazer isso da seguinte maneira (nos últimos 4 commits)

git checkout my_branch
git reset --soft HEAD~4
git commit
git push --force origin my_branch

1
Fazer isso com o comando suave em um galho já enviado acabou empurrando uma tonelada de outras pessoas comprometidas por mim.
Cchamberlain

3
Uma tonelada? Como pode ser mais do que 4? Você pode elaborar?
precisa

Não tenho certeza, mas isso tem algo a ver com tentar esmagar um commit já enviado. Looks como outros experimentaram semelhante aqui - stackoverflow.com/questions/5189560/...
cchamberlain

4
Eu teria aceito isso como resposta esperada. Mais limpo que resposta aceita.
vikramvi

4
Esta é a resposta mais clara e aceita em apenas 4 etapas
Ameya Salagre 10/10

45

Diferença menor na resposta aceita, mas eu estava tendo muita dificuldade para esmagar e finalmente consegui.

$ git rebase -i HEAD~4
  • Na tela interativa que se abre, substitua pick por squash na parte superior de todos os commits que você deseja squash.
  • Salve e feche o editor através de esc --> :wq

Empurre para o controle remoto usando:

$ git push origin branch-name --force

2
breve e eficaz, elaborado:
terwxqian 7/01/19

22

Muitos problemas podem ser evitados criando apenas um branchpara trabalhar e não trabalhando master:

git checkout -b mybranch

Os trabalhos a seguir para remoteconfirmações já enviadas e uma mistura de remoteconfirmações enviadas / localconfirma apenas:

# example merging 4 commits

git checkout mybranch
git rebase -i mybranch~4 mybranch

# at the interactive screen
# choose fixup for commit: 2 / 3 / 4

git push -u origin +mybranch

Também tenho algumas notas de solicitação de recebimento que podem ser úteis.


17

git rebase -i master

você vai abrir o editor vm e msgs algo como isto

Pick 2994283490 commit msg1
f 7994283490 commit msg2
f 4654283490 commit msg3
f 5694283490 commit msg4
#Some message 
#
#some more

Aqui eu mudei o pick para todos os outros commits para "f" (significa correção).

git push -f origin feature/feature-branch-name-xyz

isso consertará todas as confirmações em uma confirmação e removerá todas as outras confirmações. Eu fiz isso e isso me ajudou.


3

Ao trabalhar com um Gitlab ou Github, você pode ter problemas dessa maneira. Você esmaga seus commits com um dos métodos acima. Minha preferida é:

git rebase -i HEAD~4
or
git rebase -i origin/master

selecione squash ou correção para o seu commit. Nesse ponto, você deve verificar o status do git. E a mensagem pode ser:

    On branch ABC-1916-remote
    Your branch and 'origin/ABC-1916' have diverged,
    and have 1 and 7 different commits each, respectively.
      (use "git pull" to merge the remote branch into yours)

E você pode ficar tentado a puxá-lo. NÃO FAÇA ISSO ou você estará na mesma situação de antes.

Em vez disso, avance para sua origem com:

git push origin +ABC-1916-remote:ABC-1916

O + permite forçar o envio apenas para um ramo.


não há nada errado em puxar, especialmente se você tiver conflitos, eles podem ser resolvidos com mais facilidade do que se você forçar push
Ray_Poly

2

Para esmagar dois commits, um dos quais já foi enviado, em um único ramo, o seguinte funcionou:

git rebase -i HEAD~2
    [ pick     older-commit  ]
    [ squash   newest-commit ]
git push --force

Por padrão, isso incluirá a mensagem de confirmação da confirmação mais recente como um comentário na confirmação mais antiga.


2

1) git rebase -i HEAD~4

Elaborar: Funciona no ramo atual; o HEAD ~ 4 significa esmagar os quatro últimos commits; modo interativo (-i)

2) Nesse ponto, o editor abriu, com a lista de confirmações, para alterar a segunda confirmação e as confirmações seguintes, substituindo pick por squash e salve-a.

saída: refs / heads / branch-name refazidos e atualizados com sucesso.

3) git push origin refs/heads/branch-name --force

resultado:

remote:
remote: To create a merge request for branch-name, visit:
remote: http://xxx/sc/server/merge_requests/new?merge_request%5Bsource_branch%5D=sss
remote:To ip:sc/server.git
 + 84b4b60...5045693 branch-name -> branch-name (forced update)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.