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?

Loren
fonte

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).

Alan Haggai Alavi
fonte
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
jakob-r
fonte
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
BLRBoy
fonte
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.

Stuart Cardall
fonte
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.

Nupur
fonte
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.

Alex
fonte
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.

lobsterhands
fonte
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)
terwxqian
fonte