Posso schiacciare i commit in Mercurial?


109

Ho un paio di commit che dovrebbero essere uno solo. Se stessi usando git, userei:

git rebase -i <some-commit-before>

e poi schiacciarli.

Posso farlo in Mercurial? Se é cosi, come?

Risposte:


88

Sì, puoi farlo usando Mercurial senza alcuna estensione concatenando i changeset .

In alternativa, se desideri utilizzare un'estensione, puoi utilizzare:


Sì, ho pescato quella risposta dalle domande ingannevoli che mi piacevano nel mio commento alla domanda generale. Penso che sia la tua risposta su quello.
Ry4an Brase

4
Una piccola nota a margine: l'estensione Histedit è distribuita con Mercurial 2.3 e versioni successive. Devi solo abilitarlo.
Paidhi

1
Nel documento Concatenating Changesets si usano concetti astratti di "repository", come faccio a fare riferimento a quelli? Ad esempio: hg -R oldrepo export ... produce "abort: repository oldrepo non trovato!
Aleksandr Levchuk

13
Sto solo cercando di schiacciare 2 commit. Ho davvero bisogno di una pagina wiki con più di 10 comandi o estensioni alternative?
Aleksandr Levchuk

3
Vedi i commenti. Histedit è ora integrato, devi solo abilitarlo (perché nessun comando predefinito modificherà la cronologia)
Ry4an Brase

43

Il mio preferito è il hg strip --keepcomando. E poi effettuo tutte le modifiche in un unico commit.

È il modo più veloce e comodo per me, perché mi piace fare tanti piccoli impegni durante il mio lavoro quotidiano;)


Nota 1: stripnecessita di un'estensione incorporata mqper essere abilitata.
Nota 2: il mio client Git / Mercurial preferito (SmartGit / Hg) aggiunge il --keepparametro predefinito durante strip. E ciò che è ancora più conveniente: fornisce un'opzione chiamata join commits:]


4
Il comando completo per hg strip è: hg strip --keep --rev [rev] Dov'è revil numero di revisione del primo commit che vuoi schiacciare con l'ultimo
Nicolas Forney

3
@NicolasForney Non esattamente, --revè opzionale, il comando completo èhg strip --keep [rev]
G. Demecki

La revisione è obbligatoria per me in 3.3.3: hg help striphg strip [-k] [-f] [-n] [-B bookmark] [-r] REV...e omettendo la revisione mi dà abort: empty revision set.
Roman Starkov

3
L'utilizzo hg stripnon è l'idea migliore. Non è esattamente sicuro. Prova hg histedit, forse anche provare a utilizzare l'estensione evolve.
Martin Thomson,

Sembra il modo più naturale per le persone git;)
foo

32

L' estensione Rebase ha funzionato a meraviglia . Per schiacciare 2 commit:

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

Il punto è una scorciatoia per la revisione corrente.

È ancora più semplice quando hai alcuni commit su un ramo e vuoi comprimerli tutti in uno:

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

Come funziona:

inserisci qui la descrizione dell'immagine

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


1
Dove hai trovato "~ 2" per due commit?
Mi-La

1
È spiegato nell'argomento revsets, vedere hg help revsets.
Markand

13

Se stai leggendo questa risposta, puoi dimenticare ogni altra opzione menzionata in questa risposta e utilizzare il foldcomando dall'estensione evolve .

evolveè un'estensione di mercurial che ci aiuta ad avere una storia mutevole sicura, ma è ancora sperimentale. Puoi usarlo clonandolo dal suo repository e aggiungendolo nel tuo .hgrc in questo modo.

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

Supponendo che tu abbia clonato evolve repo nella tua home directory. Adesso sei a posto. Puoi anche cercare aiuto da hg help fold.

Fold Command

Dici folddi schiacciare / piegare una catena lineare di commit che non è interrotta. Quello che fa fold è che crea un nuovo changeset che contiene le modifiche da tutti i changeset e contrassegna tutti quei commit come obsoleti. Puoi avere una visione più approfondita di questo in docs .

Supponiamo ora di avere la seguente cronologia.

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

Si vuole schiacciare e, fe g. Tu puoi fare

hg up g
hg fold -r e

Il risultato sarà

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

dov'è hil changeset che contiene le modifiche da tutti e tre i commit e, fe g.

Puoi anche piegare i changeset dal centro della cronologia, cioè non devi necessariamente scegliere una catena che include la punta. Si supponga di voler piegare b, ce d. Tu puoi fare

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

Questo risulterà in

a -> i -> j

dove iè il changeset piegato b, c, ded jè la stessa come changeset h. La guida per l'utente Evolve è assolutamente da leggere.


Sembra che rebase copra la maggior parte (forse tutti?) I casi d'uso di quell'estensione, e certamente quello che viene chiesto in questa domanda. La caratteristica killer di quell'estensione è nascondere (piuttosto che eliminare) le revisioni che sostituisci, ma l' --keepopzione di rebase copre questo (seguito dal contrassegno delle revisioni come segrete o dall'uso di strisce su di esse dopo aver controllato il risultato). Anche lo spostamento delle revisioni tra altre revisioni è possibile con una sequenza di due comandi rebase.
Arthur Tacca

... inoltre, se stai facendo qualcosa di veramente complicato, puoi sempre clonare prima il repository locale da utilizzare come backup. Considerando quanto raro (si spera!) Sia, è meno faticoso che imparare a usare un'estensione completamente nuova.
Arthur Tacca

"NameError: il nome 'execfile' non è definito", il che significa che evolve è scritto in Python 2, che è fondamentalmente l'età della pietra.
Neil G

1
@NeilG mercurial non supporta ancora Python 3.
Pulkit Goyal

2
@NeilG sì, la community di Mercurial sta lavorando duramente per ottenere il supporto di py3 al più presto.
Pulkit Goyal

1

Con Mercurial 4.8 (novembre 2018, 9 anni dopo), potresti prendere in considerazione il nuovo comando hg absorb(prima era una funzionalità sperimentale ).

Vedi " Assorbimento dei cambiamenti di commit in Mercurial 4.8 "

L'estensione per assorbire prenderà ogni modifica nella directory di lavoro, scoprirà quali commit nella serie hanno modificato quella riga e modificherà automaticamente la modifica a quel commit.
Se c'è qualche ambiguità (cioè più commit modificati sulla stessa riga), allora Absorb ignorerà semplicemente quel cambiamento e lo lascerà nella tua directory di lavoro per essere risolto manualmente.

A livello tecnico, hg absorbtrova tutte le modifiche non confermate e tenta di mappare ogni riga modificata su un commit precedente non ambiguo.
Per ogni modifica che può essere mappata in modo pulito, le modifiche non salvate vengono assorbite nel commit precedente appropriato. I commit influenzati dall'operazione vengono ribasati automaticamente.
Se una modifica non può essere mappata a un commit precedente non ambiguo, non viene eseguito il commit e gli utenti possono tornare a un flusso di lavoro esistente (ad esempio utilizzando hg histedit).

La logica di riscrittura automatica di hg absorbviene implementata seguendo la cronologia delle righe: Questo è fondamentalmente diverso dall'approccio adottato da hg histedito git rebase, che tende a fare affidamento su strategie di unione basate sull'unione a 3 vie per derivare una nuova versione di un file dato più input versioni.

Questo approccio combinato con il fatto che hg Absorb salta le modifiche con un commit dell'applicazione ambiguo significa che hg Absorb non incontrerà mai conflitti di unione!

Ora, potresti pensare che se ignori le righe con obiettivi di applicazione ambigui, la patch si applicherebbe sempre in modo pulito utilizzando una classica unione a 3 vie. Questa affermazione sembra logicamente corretta. Ma non lo è: hg absorbpuò evitare conflitti di unione quando l'unione eseguita da hg histedito git rebase -ifallirebbe.


0

Penso che chistedit(integrato a partire da Mercurial 2.3) sia il più vicino a rebase -iquello puro Mercurial ( chisteditè la versione interattiva di histedit). Una volta in histedit, il foldcomando mappa a rebase squashe il rollcomando mappa a rebase fixup. Vedi la documentazione di histedit per maggiori informazioni.

Qui c'è un semplice esempio. Supponiamo di avere quanto segue e di voler spostare tutte le modifiche di 1e21c4b1 nella revisione precedente mantenendo solo il messaggio della revisione precedente.

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

Puoi eseguire la hg chistedit -r b4a738a4modifica della cronologia su b4a738a4. In chistedit si sposta quindi il cursore verso il basso su 1e21c4b1 e si preme rper indicare che si desidera ottenere quella revisione. Si noti che l'ordine in histedit (dal più vecchio al più recente) è invertito da hg log( dal più recente al più vecchio).

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

Dopo aver scelto le modifiche, scegli cdi eseguirle. Il risultato è il seguente:

@ bfa4a3be drees tip | Un commit o 788aa028 drees | Cose più vecchie

Se sei relativamente nuovo a loro, allora histeditpuò essere una scelta migliore rispetto al chisteditfatto che fornisce le descrizioni dei comandi nel file histedit come riferimento. Ci vuole solo un po 'più di editing per impostare i comandi usando la normale modifica del testo (proprio come il normale rebase).

Nota, per utilizzare histedito chisteditè necessario aggiungere histeditalle estensioni nel tuo ~ / .hgrc:

[extensions]
histedit =

Ho suggerito chisteditpoiché è il più vicino rebase -ie funziona ovunque nella storia. Se vuoi solo riassumere / modificare la revisione corrente in quella precedente, allora @G. Il stripsuggerimento di Demecki può essere buono poiché ciò che sta accadendo è chiaro. È costruito a partire da Mercuria 2.8. Per ottenere i risultati equivalenti come sopra, puoi fare quanto segue:

hg strip .
hg add
hg commit --amend

Nota strip, come histedit, deve essere abilitato nel tuo ~ / .hgrc:

[extensions]
strip =

0

Supponiamo che tu voglia schiacciare (unire) i 2 commit più recenti.

  1. Trova un numero di revisione

    hg log -G -l 3
    

    possibile output:

    @  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. Ramo di soft reset

    hg strip --keep -r 155
    
  3. Esegui nuovamente il commit delle modifiche

    hg commit -m "new commit message"
    

Appunti

striprichiede un'estensione incorporata per essere abilitata. Crea / modifica ~/.hgrcfile di configurazione con il seguente contenuto:

[extensions]
strip = 

-1

Io uso:

hg phase --draft --force -r 267
...
hg rebase --dest 282 --source 267 --collapse
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.