Posso esmagar commits no Mercurial?


109

Eu tenho um par de commits que deveria ser apenas um. Se eu estivesse usando o git, usaria:

git rebase -i <some-commit-before>

e depois esmagá-los.

Posso fazer isso no mercurial? Se sim, como?

Respostas:


88

Sim, você pode fazer isso usando o mercurial sem quaisquer extensões por Concatenating Changesets .

Como alternativa, se quiser usar uma extensão, você pode usar:


Sim, pesquei essa resposta nas perguntas idiotas que gostei em meu comentário sobre a pergunta geral. Acho que é sua resposta sobre isso.
Ry4an Brase

4
Uma pequena nota lateral: a extensão Histedit é distribuída com o Mercurial 2.3 e posterior. Você apenas tem que habilitá-lo.
Paidhi de

1
No documento Concatenating Changesets usa conceitos abstratos de "repos", como posso fazer referência a eles? Por exemplo: hg -R oldrepo export ... produz "abort: repository oldrepo not found!
Aleksandr Levchuk

13
Apenas tentando esmagar 2 commits. Eu realmente preciso de uma página wiki com mais de 10 comandos ou extensões alternativas?
Aleksandr Levchuk

3
Veja os comentários. Histedit agora está integrado, você só precisa habilitá-lo (porque nenhum comando padrão modificará o histórico)
Ry4an Brase

43

Meu favorito é o hg strip --keepcomando. E então eu confirmo todas as mudanças em um commit.

É a forma mais rápida e confortável para mim, porque gosto de fazer muitos pequenos compromissos no meu trabalho diário;)


Nota 1: stripprecisa de uma extensão embutida mqpara ser habilitada.
Nota 2: Meu cliente Git / Mercurial favorito (SmartGit / Hg) anexa por --keepparâmetro padrão durante strip. E o que é ainda mais conveniente: oferece uma opção chamada join commits:]


4
O comando completo para hg strip é: hg strip --keep --rev [rev] Onde revestá o número de revisão do primeiro commit que você deseja esmagar com o último
Nicolas Forney

3
@NicolasForney Não exatamente, --revé opcional, o comando completo éhg strip --keep [rev]
G. Demecki

A revisão é obrigatória para mim em 3.3.3: hg help stripfornece hg strip [-k] [-f] [-n] [-B bookmark] [-r] REV..., e omitindo a revisão, fornece abort: empty revision set.
Roman Starkov de

3
Usar hg stripnão é a melhor ideia. Não é exatamente seguro. Experimente hg histedit, talvez até tente usar a extensão evoluir.
Martin Thomson de

Parece a maneira mais natural para git people;)
foo

32

A extensão Rebase funcionou perfeitamente. Para esmagar 2 commits:

$ hg rebase --dest .~2 --base . --collapse

Dot é um atalho para a revisão atual.

É ainda mais fácil quando você tem alguns commits em um branch e deseja agrupá-los todos em um:

$ hg rebase --dest {destination branch (e.g. master)} --base . --collapse

Como funciona:

insira a descrição da imagem aqui

(de http://mercurial-scm.org/wiki/RebaseExtension#Collapsing )


1
Onde você encontrou o "~ 2" para dois commits?
Mi-La de

1
É explicado no tópico revsets, consulte hg help revsets.
marco e

13

Se você está lendo esta resposta, pode esquecer todas as outras opções mencionadas nesta resposta e usar o foldcomando da extensão evolve .

evolveé uma extensão do mercurial que nos ajuda a ter uma história mutável segura, embora ainda seja experimental. Você pode usá-lo clonando-o de sua repo e adicioná-lo em sua .hgrc assim.

[extensions]
evolve = ~/evolve/hgext/evolve.py

Supondo que você clonou o repo evoluir em seu diretório inicial. Agora você está pronto para ir. Você também pode procurar ajuda em hg help fold.

Comando de Dobra

Você diz foldpara esmagar / dobrar uma cadeia linear de commits que não está quebrada. O que o fold faz é criar um novo changeset que contém as mudanças de todos os changesets e marcar todos os commits como obsoletos. Você pode ter uma visão mais aprofundada sobre isso em docs .

Agora, suponha que você tenha o seguinte histórico.

a -> b -> c -> d -> e -> f -> g

Você quer esmagar e, fe g. Você pode fazer

hg up g
hg fold -r e

O resultado será

a -> b -> c -> d -> h

onde hestá o changeset que contém as mudanças de todos os três commits e, fe g.

Você também pode dobrar changesets do meio do histórico, ou seja, não necessariamente você precisa escolher uma corrente que inclua a ponta. Suponha que você queira desistir b, ce d. Você pode fazer

hg up d
hg fold -r b
hg evolve --all

Isso resultará em

a -> i -> j

onde ié dobrado a revisão de b, c, de jé o mesmo conjunto de alterações como h. Evolve guia do usuário é uma leitura obrigatória.


Parece que o rebase cobre a maioria (talvez todos?) Os casos de uso dessa extensão e, certamente, aquele que está sendo perguntado nesta pergunta. O recurso matador dessa extensão é ocultar (em vez de excluir) as revisões que você substitui, mas a --keepopção de rebase cobre isso (seguido por marcar as revisões como secretas ou usar tira nelas depois de verificar o resultado). Até mesmo mover revisões entre outras revisões é possível com uma sequência de dois comandos de rebase.
Arthur Tacca

... além disso, se você estiver fazendo algo realmente complicado, você pode apenas clonar o repositório local primeiro para usar como backup. Considerando o quão raro (espero!) Isso é, é menos trabalhoso do que aprender a usar uma extensão totalmente nova.
Arthur Tacca

"NameError: o nome 'execfile' não está definido" - o que significa que evoluir está escrito em Python 2, que é basicamente a idade da pedra.
Neil G

1
@NeilG mercurial não é compatível com Python 3 ainda.
Pulkit Goyal

2
@NeilG sim, a comunidade mercurial está trabalhando duro para obter suporte py3 o mais rápido possível.
Pulkit Goyal

1

Com o Mercurial 4.8 (novembro de 2018, 9 anos depois), você pode considerar o novo comando hg absorb(antes era um recurso experimental ).

Consulte " Absorvendo Mudanças Comprometidas no Mercurial 4.8 "

A extensão absorb pegará cada mudança em seu diretório de trabalho, descobrirá quais commits em sua série modificaram aquela linha, e automaticamente corrigirá a mudança para aquele commit.
Se houver alguma ambigüidade (ou seja, vários commits modificados na mesma linha), então absorb irá simplesmente ignorar essa mudança e deixá-la em seu diretório de trabalho para ser resolvida manualmente.

Em um nível técnico, hg absorbencontra todas as alterações não confirmadas e tenta mapear cada linha alterada para um commit anterior não ambíguo.
Para cada mudança que pode ser mapeada de forma limpa, as mudanças não confirmadas são absorvidas no commit anterior apropriado. As confirmações impactadas pela operação são realocadas automaticamente.
Se uma mudança não pode ser mapeada para um commit anterior inequívoco, ela é deixada sem commit e os usuários podem recorrer a um fluxo de trabalho existente (por exemplo, usando hg histedit).

A lógica de reescrita automática de hg absorbé implementada seguindo o histórico de linhas: Isso é fundamentalmente diferente da abordagem adotada por hg histeditou git rebase, que tende a depender de estratégias de mesclagem com base na mesclagem de três vias para derivar uma nova versão de um arquivo com entrada múltipla versões.

Essa abordagem combinada com o fato de que o hg absorb ignora as alterações com um commit ambíguo do aplicativo significa que o hg absorb nunca encontrará conflitos de mesclagem!

Agora, você pode estar pensando que, se ignorar as linhas com destinos de aplicativo ambíguos, o patch sempre será aplicado de forma limpa usando uma combinação clássica de 3 vias. Esta afirmação parece logicamente correta. Mas não é: hg absorbpode evitar conflitos de mesclagem quando a mesclagem executada por hg histeditou git rebase -ifalhar.


0

Eu acho que chistedit(construído desde o Mercurial 2.3) é o mais próximo rebase -ique é puro Mercurial ( chistedité a versão interativa do histedit). Uma vez no histedit, o foldcomando mapeia para rebase squashe rollmapeia de comando para rebase fixup. Veja histedit docs para mais informações.

Aqui está um exemplo simples. Suponha que você tenha o seguinte e deseja mover todas as alterações de 1e21c4b1 para a revisão anterior e apenas manter a mensagem da revisão anterior.

@  1e21c4b1 drees tip
|  A commit you want to squash
o  b4a738a4 drees
|  A commit
o  788aa028 drees
|  Older stuff

Você pode executar hg chistedit -r b4a738a4para editar o histórico de volta para b4a738a4. Em chistedit, você então move o cursor para baixo para 1e21c4b1 e pressiona rpara indicar que deseja rolar essa revisão. Observe que a ordem em histedit (do mais antigo para o mais recente) é revertida de hg log(do mais recente para o mais antigo).

#0  pick   160:b4a738a49916   A commit
#1  ^roll  161:1e21c4b1500c

Depois de escolher suas alterações, você escolhe c confirmá-las. O resultado é o seguinte:

@ bfa4a3be drees tip | Um compromisso de 788aa028 drees | Coisas mais antigas

Se você for relativamente novo para eles, então histeditpode ser uma escolha melhor do que chisteditporque fornece as descrições dos comandos no arquivo histedit para referência. Só é preciso um pouco mais de edição para definir os comandos usando a edição de texto normal (como o rebase normal).

Observe, para usar histeditouchistedit você precisa adicionar histeditàs suas extensões em ~ / .hgrc:

[extensions]
histedit =

Eu sugeri chistedituma vez que é o mais próximo derebase -i e funciona em qualquer lugar da história. Se você realmente quiser apenas incluir / ajustar a revisão atual na anterior, então @G. A stripsugestão de Demecki pode ser boa, pois o que está acontecendo é claro. Está integrado desde o Mercuria 2.8. Para obter os resultados equivalentes aos acima, você pode fazer o seguinte:

hg strip .
hg add
hg commit --amend

Observe strip, como o histedit, precisa ser habilitado em seu ~ / .hgrc:

[extensions]
strip =

0

Vamos supor que você queira esmagar (unir) 2 commits mais recentes.

  1. Encontre um número de revisão

    hg log -G -l 3
    

    saída possível:

    @  changeset:   156:a922d923cf6f
    |  branch:      default
    |  tag:         tip
    |  user:        naXa!
    |  date:        Thu Dec 13 15:45:58 2018 +0300
    |  summary:     commit message 3
    |
    o  changeset:   155:5feb73422486
    |  branch:      default
    |  user:        naXa!
    |  date:        Thu Dec 13 15:22:15 2018 +0300
    |  summary:     commit message 2
    |
    o  changeset:   154:2e490482bd75
    |  branch:      default
    ~  user:        naXa!
       date:        Thu Dec 13 03:28:27 2018 +0300
       summary:     commit message 1
    
  2. Ramificação de soft reset

    hg strip --keep -r 155
    
  3. Confirme as alterações novamente

    hg commit -m "new commit message"
    

Notas

striprequer que uma extensão embutida seja habilitada. Crie / edite o ~/.hgrcarquivo de configuração com o seguinte conteúdo:

[extensions]
strip = 

-1

Eu uso:

hg phase --draft --force -r 267
...
hg rebase --dest 282 --source 267 --collapse
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.