Com o Mercurial, como posso “compactar” uma série de changesets em um antes de enviar?

96

Digamos que eu tenha um repositório Mercurial local e um remoto. Agora, começo a trabalhar em um recurso. Eu trabalho nisso e, quando penso que está pronto, eu envio o changeset. Testando-o um pouco mais, descobri que poderia melhorar ainda mais esse recurso ajustando algo no código. Eu faço a mudança e me comprometo. 20 minutos depois, descobri que há um bug neste novo recurso, então eu o corrijo e o cometo também.

Agora tenho 3 changesets que realmente gostaria de enviar para o repositório remoto como um changeset com a mensagem "Implementando recurso X", por exemplo.

Como posso fazer isso sem muito trabalho? Acredito que poderia fazer isso com patches, mas parece que dá muito trabalho.

Lucas
fonte
40
Claramente, não é minha função dissuadi-lo de tentar compactar seus changesets, mas você pode querer considerar que metade do valor do controle de versão é responder "por que" e não apenas "o quê" meses e anos depois. Uma representação precisa de como um recurso surgiu e em quais estágios pode ter valor futuro. Descartando parece tão ... sem controle de versão.
Ry4an Brase
Isso leva a outra pergunta ... Qual é a diferença entre 'histedit' e 'colapso'
sylvanaar
1
colapso fornece um subconjunto de recursos de histedit, e histedit tem uma UX muito mais intuitiva.
Stefan Rusek
1
Ele também fornece um mecanismo para editar a mensagem do changeset mesclado.
Stefan Rusek
1
@ Ry4an: Na verdade, comprimir / reduzir adiciona relevância ao controle de versão em alguns casos. Sem esmagar, eu teria dois commits todos os dias que nada têm a ver com recursos ou correções de bugs, mas são para mover o código do laptop para o desktop e vice-versa. Eles apenas adicionam ruído ao histórico de versões.
John Reynolds

Respostas:

39

Que tal a extensão Collapse ?

Steve Losh
fonte
20
Saudações do futuro! Eu pesquisei a mesma funcionalidade e, aparentemente, hoje em dia hg oferece suporte para isso fora da caixa com hg rebase --collapse. Verifique o hg wiki sobre o comando rebase. Uma vez que esta pergunta é o terceiro resultado geral da pesquisa e a primeira no stackoverflow, pensei que a informação poderia ser útil.
a.peganz,
1
Saudações de um futuro ainda mais distante !! A extensão rebase parece ser exclusivamente voltada para mover changesets de um branch para outro. Sim, há uma opção --collapse, mas ainda parece ser aplicável apenas ao mover um conjunto de changesets entre ramos. Veja < mercurial-scm.org/wiki/… >
Brad Oestreicher
3
Você pode usar hg rebasecom --collapsedentro de uma única ramificação.
UuDdLrLrSs
52

A extensão histedit é exatamente o que você está procurando.

hg histedit -o

ou

hg histedit --outgoing

exibirá uma lista dos conjuntos de alterações de saída. Da lista você pode

  • Dobre 2 ou mais changesets criando um único changeset
  • Remova os changesets removendo-os do histórico
  • Reordene os changesets como quiser.

histedit irá pedir-lhe a nova mensagem de commit dos changesets dobrados, cujo padrão é as duas mensagens com "\ n *** \ n" separando-as.

Você também pode obter resultados semelhantes usando a extensão mq, mas é muito mais difícil.

Você também pode usar a extensão de recolhimento apenas para dobrar, mas ela não fornece uma IU tão boa e não fornece uma maneira de editar a mensagem de confirmação resultante. Editar a mensagem de confirmação resultante também permite limpar a mensagem final, que é algo que sempre acabo utilizando.

Stefan Rusek
fonte
obrigado, isso é exatamente o que eu precisava. Seria bom se você pudesse fazer isso de dentro do TortoiseHg - mas a linha de comando é simples o suficiente.
sylvanaar
21

Sim, você pode fazer isso com patches: vamos assumir que seu trabalho está nos conjuntos de alterações 100 a 110, inclusive

  1. Crie um patch:

    % hg export -o mypatch 100:110 --git

  2. Atualizar para 99:

    % hg update 99

  3. Aplique o patch com --no-commit (caso contrário, você receberá todos os seus changesets de volta):

    % hg import --no-commit mypatch

  4. Confirme todas as alterações de uma vez:

    % hg commit

  5. Agora você tem duas cabeças (110 e 111) que devem ser equivalentes em termos de arquivos que produzem em seu diretório de trabalho - talvez diferencie-as para sanidade antes de remover as antigas:

    % hg strip 100

OK, agora que já expliquei tudo, parece longo, mas, tendo feito isso um monte de vezes, não acho que seja muito trabalhoso ...

Arkady
fonte
1
Ótima resposta, mas há um pré-requisito: a extensão MQ deve estar habilitada .
Chris Kelly
Para incluir alterações em arquivos binários também, certifique-se de usar a opção --git: por exemplo: "hg export -o mypatch 100: 110 --git" Para obter mais informações, consulte: stackoverflow.com/a/12537738/ 367663 Tomei a liberdade de alterar a resposta.
Kharlos Dominguez
1
Parece complicado demais, por que não hg strip --keepe compromete tudo em um único commit?
G. Demecki
@ G.Demecki Porque é uma operação potencialmente com muitas perdas ..? Embora o MQ seja um exagero (e mesmo muitas vezes não recomendado), exceto quando se deseja tal fluxo de trabalho.
user2864740
@ user2864740 Você pode estar certo, porque não sou um especialista em Mercurial. Mas, por padrão, hg stripcolocará um backup no .hg/strip-backup/diretório. Eu acho que não é tão seguro, git reflogmas ainda fornece algum tipo de resgate.
G. Demecki
19

Se você estiver usando TortoiseHg, use pode apenas selecionar duas revisões (use CTRL para selecionar as não subsequentes), clique com o botão direito e selecione "Compactar histórico" .

Depois disso, você obterá uma nova lista de alterações no novo cabeçalho, começando com a primeira alteração selecionada antes, ela conterá todas as listas de alterações descendentes entre as que você selecionou.

Você pode simplesmente remover listas de alterações antigas se não precisar mais delas: use extensões MQ para isso. Novamente, em TortoiseHg: clique com o botão direito na primeira lista de alterações que precisa ser removida com todos os seus descendentes, "Modificar Histórico -> Remover" .

George marian
fonte
18

Meu método preferido de usar mq para esta dobra é usando TortoiseHg conforme descrito aqui . No entanto, isso pode ser feito facilmente na linha de comando da seguinte forma:

hg qimport -r <first>:<last> 
    -- where <first> and <last> are the first and last changesets 
    -- in the range of revisions you want to collapse

hg qpop <first>.diff
    -- remove all except for the first patch from the queue
    -- note: mq names patches <#>.diff when it imports them, so we're using that here

hg qfold <next>.diff
    -- where <next> is <first>+1, then <first>+2, until you've reached <last>

hg qfinish -a
    -- apply the folded changeset back into the repository

(Pode haver uma maneira melhor de fazer a etapa qfold, mas não estou ciente disso, pois geralmente uso o TortoiseHg para essa operação.)

Parece um pouco complicado no início, mas depois que você começa a usar o mq, é bastante simples e natural - além disso, você pode fazer todos os tipos de outras coisas com o mq que podem ser muito úteis!

Chris Phillips
fonte
4

hg collapsee hg histeditsão as melhores maneiras. Ou melhor, seriam as melhores maneiras, se funcionassem de forma confiável ... Eu tive histeditque travar com um despejo de pilha em três minutos. Collapsenão é muito melhor.

Pensei em compartilhar dois outros BKMs:

  1. hg rebase --collapse

    Esta extensão é distribuída com o Mercurial. Ainda não tive problemas com isso. Você pode ter que jogar alguns jogos para contornar as hg rebaselimitações - basicamente, não gosta de rebase para um ancestral no mesmo branch, nomeado ou padrão, embora permita que seja feito rebase entre branches (nomeados).

  2. Mova o repositório ( foo/.hg) para o diretório de trabalho ( bar) e seus arquivos. Não o contrário.

Algumas pessoas falaram sobre a criação de duas árvores clones e a cópia de arquivos entre elas. Ou remendando entre eles. Em vez disso, é mais fácil mover os .hgdiretórios.

hg clone project work
... lots of edits
... hg pull, merge, resolve
hg clone project, clean
mv work/.hg .hg.work
mv clean/.hg work/.hg
cd work
... if necessary, pull, nerge, reconcile - but that would only happen because of a race
hg push

Isso funciona desde que os verdadeiros repositórios, as .hgárvores, sejam independentes do diretório de trabalho e de seus arquivos.

Se eles não são independentes ...

Krazy Glew
fonte
Em 2015, histedité uma opção muito boa para essa tarefa. Eu ainda não confio nisso enquanto faço um git rebase -i, mas ele não trava .. pelo menos as versões mais recentes irão deixá-lo em um branch temporário se algo der terrivelmente errado, então a única vez que os changesets serão removidos é após a confirmação do novo branch.
user2864740
2

Eu nunca usei o Mercurial, mas isso se parece muito com o que Martin Fowler estava falando em seu blog não muito tempo atrás:

http://martinfowler.com/bliki/MercurialSquashCommit.html

Joseph
fonte
Parece mais do que complicado, mas obrigado pelo link. Honestamente, estou esperando por alguma extensão mágica que fará exatamente o que eu quero, como buscar e transplantar ao puxar e escolher changsets.
Lucas
0

Por que não apenas hg strip --keepcomandar?

Então você pode confirmar todas as alterações como um único commit.

G. Demecki
fonte
@Strawberry não dá uma resposta ?? Acho que responde perfeitamente à pergunta do autor. Você pode explicar seu ponto de vista?
G. Demecki
É uma história antiga, então vou retratar a observação - mas a resposta aprovada parece ser uma referência mais confiável.
Morango
1
@Strawberry Na verdade, é um tópico antigo. Mas a resposta aceita está desatualizada, porque o Mercurial não precisa mais de uma extensão de terceiros separada para este trabalho.
G. Demecki
0

HistEdit fará o que você quiser, mas provavelmente é um exagero. Se a única coisa que você precisa é dobrar alguns conjuntos de alterações, a extensão de recolhimento fará o trabalho.

Steve Losh
fonte
1
embora forneça uma IU muito mais fácil de usar e entender, o que é uma razão mais do que suficiente para usá-la, mas também fornece um mecanismo para editar a mensagem do changeset mesclado, que é outra coisa que sempre quero fazer quando eu mesclar conjuntos de alterações.
Stefan Rusek
E o problema de apenas entender a interface do usuário é que realmente não entendemos ... De qualquer forma, no passado enquanto o histedit permitia mudar as 'mensagens', bem como mudar as mensagens ao 'dobrar'. O histedit é perfeito; se houver alguma coisa, a extensão de colapso é insuficiente.
user2864740
0

Suponha que você tenha dois commits THISe não publicados THATno Mercurial e gostaria que eles se juntassem em um único commit no THISponto:

... --> THIS --> ... --> THAT --> ... --> LAST

Verifique se seus commits não foram publicados:

$ hg glog -r "draft() & ($THIS | $THAT)"

Atualizar para LASTconfirmar:

$ hg up

e a importação confirma até THISno MQ ::

$ hg qimport $THIS::.

Cancele a aplicação de todos os patches e aplique apenas primeiro THIS::

$ hg qpop -a
$ hg qpush
$ hg qapplied
... THIS ...

Junte-se a THAT::

$ hg qfold $THATNAME

NOTA Para encontrar o nome, THATNAMEuse:

$ hg qseries

Aplique todos os patches e mova-os para o histórico do repositório ::

$ hg qpush -a
$ hg qfinish -a

Minha postagem no blog sobre o assunto é Juntando dois commits no Mercurial .

Gavenkoa
fonte
0

Sim, strip --keepfunciona para a pergunta do autor. Mas era um pouco diferente dos outros, por exemplo, se você tiver a versão de 1 a 30, mas quiser apenas recolher a versão 12-15. Outras soluções funcionam, mas não strip --keep.

Frank tao
fonte