Mercurial workflow

Imparare un flusso di lavoro che permetta la condivisione del codice fra colleghi in modalità idonea alla revisione del codice.

In particolare saranno di grande aiuto le seguenti estensioni/comandi:

  • topics

  • histedit

  • absorb

Gran parte delle cose che presento si basano sulla alcuni concetti:

fasi

mercurial distingue i commit in base alla fase, la vedete anche in tortoisehg. Quando un commit viene creato (localmente) è in fase draft, quando in seguito viene eseguito hg push il file viene considerato pubblico. Esiste la possibilità di create un repository «non pubblico» per cui il changeset non diventi pubblico

code-review

è la possibilità di commentare del codice altrui e suggerire miglioramenti. È auspicabile che poi i «balbettamenti» non finiscano nel codice finale.

I topics sono un nuovo modello di branching che viene implementata da heptapod che si basa sulla possibilità di condividere codice in fase draft.

Suggerimenti di letture

Linee guida

Dal momento che in questo modo è possibile correggere quello che si pubblica, vi consigliamo di pubblicare spesso in modo da dare la possibilità ai colleghi di commentare il codice.

È importante che si tengano presente in modo ferreo alcune regole importanti:

  1. I commit devono essere atomici ovvero devono ciascuno contenere un solo punto (topic, appunto), ma nello stesso tempo deve contenere tutto quello che questo topic richiede.

    Ad esempio, se serve documentazione (sia generica sia nelle docstring delle funzioni) deve essere presente nello stesso commit del codice. Idem, quando vengono fatti per i test / remote test.

  2. Richiesta di merge: una volta pronti deve essere fatta la richesta di merge, basta seguire il link generato in automatico dal push (che altrimenti ignorate). Aprite il link dal terminale al solito con click destro.

    È importante che compiliate nella pagina che vi compare gli assegnatari (presumibilmente il vostro responsabile e Vitto che dopo la prima fase deciderà se continuare a ricevere…

    È importante -per progetti Django- chiarire nel messaggio di merge almeno 2 cose:

    1. Se il branch include delle migrazioni

    2. Se il branch aggiunge delle dipendenze

Alcuni suggerimenti pratici

Q: come mai il repo locale non è imparentato con quello da cui avevo clonato?

È importante che il primo commit sia già public e non draft. Il motivo è banalmente che potrete non essere in grado di committare le modifiche se viene reso obsoleto il primo changeset che quindi di fatto cambia. È importante che esista almeno un antenato comune nel momento in cui fate push.

Per comprendere quanto sopra ricordo che ogni volta che facciamo un amend (ma la stessa cosa vale per histedit, absorb e simili) di fatto si genera un nuovo commit che sostituisce il primo. Se fate questo al primo commit di fatto nascondete il commit comune con il repository remoto e quindi vi trovereste nella situazione in cui il remoto non è imparentato con il locale.

Per ovviare a questa situazione suggerisco di fare sempre un primo commit, che banalmente potrebbe essere .hgignore che facilmente è il medesimo per tutti i progetti.

Q: Come convertire in topics una stack (non ancora pubblicata)?

Il comando topics ha un’opzione -r che può avere come argomento il range (con ::) che si vuole tramutare in topic.:

hg topic -r sx::sy topic-name

Q: Come fare il merge di un topic se non ci son biforcazioni?

In questa situazione non si riesce a fare merge, verrà fuori il messaggio che non c’è nulla da «mergiare». È suff. rendere pubblic le parti interessate:

hg phase -r sx::sy --publish

o alternativamente se si prevede di pubblicare:

hg push --publish [-t topic_name]

Q: Come eliminare un topic condiviso ma errato?

Se avete creato e poi condiviso un topic che però deve essere eliminato (ad esempio perché bocciato), potete usare il comando hg prune:

hg prune -r "topic(nome-de-topic)"
hg push

Faccio notare che "topic(nome-de-topic)" è un modo molto efficace di produrre la lista dei commit che appartengono a quel topic. Potremmo anche eliminare solo alcuni changeset, ad esempio:

sandro@bluffx:/tmp/tut$ hg s
### topic: sd
### target: default (branch)
s4@ quattro (current)
s3: tre
s2: due
s1: uno
s0^ provay (base)
sandro@bluffx:/tmp/tut$ hg prune -r s2:s4
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
working directory is now at 95cc7b2dfb9e
3 changesets pruned
sandro@bluffx:/tmp/tut$ hg s
### topic: sd
### target: default (branch)
s1@ uno (current)
s0^ provay (base)

Nota

Quando non funziona… Esistono delle circostanze in cui hg non si accorge del marker che invalida il topic (obsolescce marker), i quel caso è necessario fare nuovamente push del changeset padre di quello da cui nasceva il topic. Per trovarlo può essere necessario usare hg log --hidden

Q: come inviare solo un topic sul repo condiviso?

Esistono 2 possibilità:

hg push -t my_topic

Q: Fallisce hg in

Questo si risolve facendo prima hg pull. A mio avviso succede quando la struttura dati interna è stata fatta da mercurial pre 5 senza topics. Una volta fatto hg pull viene aggiornata e l’errore sparisce.

Q: come eliminare dei file capitati erroneamente in un commit?

Basta eliminarlo usando hg amend:

hg amend --extract file-or-directory [file-or-directory ...]

Quel file rimarrà nella working directory e quindi andrà gestito (ad esempio creando un commit per lui, o eliminandolo). Supponiamo voi creiate un nuovo commit per questo:

$ mkdir /tmp/test && cd /tmp/test $ hg init $ touch .hgignore $ hg ci -A -m hgignore $ hg topics conta $ touch uno due tre otto $ hg ci -Am «init» $ touch quter cinq $ hg ci -Am «altro giro» $ touch ses sett $ hg ci -Am «ultimo arrivato paga da bere» $ hg up s1 $ hg stack ### topic: conta ### target: default (branch) s3: ultimo arrivato paga da bere s2: altro giro s1@ init (current) s0^ hgignore (base)

$ hg st –ch . A due A otto A tre A uno

$ hg amend –extract otto 2 new orphan changesets $ hg st A otto

La nostra correzione ha lasciato il file otto aggiunto da committare ma ha anche cambiato i due commit successivi che quindi sono ora orfani, indicato dal $ nella stack:

$ hg stack
### topic: conta
### target: default (branch)
s3$ ultimo arrivato paga da bere (orphan)
s2$ altro giro (orphan)
s1@ init (current)
s0^ hgignore (base)

Ci occupiamo anzitutto del file da committare:

hg ci -m "otto"

che ci porta in una situazione biforcata:

$ hg log
@  changeset: [draft] 5 : d9ae185e86b6 default [#conta] tip
|  node:      d9ae185e86b68a5f716b55c868bf3845308806fa
|  author:    Sandro Dentella <adentella@thux.it>
|  date:      Mon, 23 Mar 2020 19:55:46 +0100 (2 seconds ago)
|  summary:   otto
|
o  changeset: [draft] 4 : 572ee3d89198 default [#conta]
|  node:      572ee3d891986a5c3490b18d1d64530a3927e15f
|  author:    Sandro Dentella <adentella@thux.it>
|  date:      Mon, 23 Mar 2020 19:43:38 +0100 (12 minutes ago)
|  summary:   init
|
| *  changeset: [draft] 3 : dacdfc8e209a default [#conta]
| |  node:      dacdfc8e209a75ae660273b2f9ad73aad23ec200
| |  author:    Sandro Dentella <adentella@thux.it>
| |  date:      Mon, 23 Mar 2020 19:43:38 +0100 (12 minutes ago)
| |  summary:   ultimo arrivato paga da bere
| |
| *  changeset: [draft] 2 : 0b82bf9cdc53 default [#conta]
| |  node:      0b82bf9cdc53b8f85b172bcf767159e7ff3af46d
| |  author:    Sandro Dentella <adentella@thux.it>
| |  date:      Mon, 23 Mar 2020 19:43:38 +0100 (12 minutes ago)
| |  summary:   altro giro
| |
| x  changeset: [draft] 1 : 0190f266a5c7 default [#conta]
|/   node:      0190f266a5c7dc00bbc05a97e25b462bd402038c
|    author:    Sandro Dentella <adentella@thux.it>
|    date:      Mon, 23 Mar 2020 19:43:38 +0100 (12 minutes ago)
|    summary:   init
|
o  changeset: [draft] 0 : 4d506ac20847 default
   node:      4d506ac20847a463a15e049734f4b9441e25af7d
   author:    Sandro Dentella <adentella@thux.it>
   date:      Mon, 23 Mar 2020 19:43:37 +0100 (12 minutes ago)
   summary:   hgignore

che sistemeremo in 2 mosse::

$ hg evolve
$ hg log
o  changeset: [draft] 7 : bb9b54592e7b default [#conta] tip
|  node:      bb9b54592e7b412617784e5deb68d72eada4f320
|  author:    Sandro Dentella <adentella@thux.it>
|  date:      Mon, 23 Mar 2020 19:43:38 +0100 (13 minutes ago)
|  summary:   ultimo arrivato paga da bere
|
o  changeset: [draft] 6 : 3d788e78fe92 default [#conta]
|  node:      3d788e78fe92933f177e7bf420f1f382e9ed8721
|  author:    Sandro Dentella <adentella@thux.it>
|  date:      Mon, 23 Mar 2020 19:43:38 +0100 (13 minutes ago)
|  summary:   altro giro
|
| @  changeset: [draft] 5 : d9ae185e86b6 default [#conta]
|/   node:      d9ae185e86b68a5f716b55c868bf3845308806fa
|    author:    Sandro Dentella <adentella@thux.it>
|    date:      Mon, 23 Mar 2020 19:55:46 +0100 (67 seconds ago)
|    summary:   otto
|
o  changeset: [draft] 4 : 572ee3d89198 default [#conta]
|  node:      572ee3d891986a5c3490b18d1d64530a3927e15f
|  author:    Sandro Dentella <adentella@thux.it>
|  date:      Mon, 23 Mar 2020 19:43:38 +0100 (13 minutes ago)
|  summary:   init
|
o  changeset: [draft] 0 : 4d506ac20847 default
   node:      4d506ac20847a463a15e049734f4b9441e25af7d
   author:    Sandro Dentella <adentella@thux.it>
   date:      Mon, 23 Mar 2020 19:43:37 +0100 (13 minutes ago)
   summary:   hgignore

Ora vedete che non esistono più orfani: in questa visualizzazione non ci son più * o x. Esiste però una biforcazione che sistemiamo subito:

$ hg rebase [ -d tip ]
rebasing 5:d9ae185e86b6 "otto" (conta)
sandro@bluffx:/tmp/test$ hg log
@  changeset: [draft] 8 : 9697e04af32a default [#conta] tip
|  node:      9697e04af32a3fe2333ae54e04d4c6a5e39b27e4
|  author:    Sandro Dentella <adentella@thux.it>
|  date:      Mon, 23 Mar 2020 19:55:46 +0100 (7 minutes ago)
|  summary:   otto
|
o  changeset: [draft] 7 : bb9b54592e7b default [#conta]
|  node:      bb9b54592e7b412617784e5deb68d72eada4f320
|  author:    Sandro Dentella <adentella@thux.it>
|  date:      Mon, 23 Mar 2020 19:43:38 +0100 (19 minutes ago)
|  summary:   ultimo arrivato paga da bere
|
o  changeset: [draft] 6 : 3d788e78fe92 default [#conta]
|  node:      3d788e78fe92933f177e7bf420f1f382e9ed8721
|  author:    Sandro Dentella <adentella@thux.it>
|  date:      Mon, 23 Mar 2020 19:43:38 +0100 (19 minutes ago)
|  summary:   altro giro
|
o  changeset: [draft] 4 : 572ee3d89198 default [#conta]
|  node:      572ee3d891986a5c3490b18d1d64530a3927e15f
|  author:    Sandro Dentella <adentella@thux.it>
|  date:      Mon, 23 Mar 2020 19:43:38 +0100 (19 minutes ago)
|  summary:   init
|
o  changeset: [draft] 0 : 4d506ac20847 default
   node:      4d506ac20847a463a15e049734f4b9441e25af7d
   author:    Sandro Dentella <adentella@thux.it>
   date:      Mon, 23 Mar 2020 19:43:37 +0100 (19 minutes ago)
   summary:   hgignore

Tutto è in ordine, otto che si era maldestramente infilato nel changeset iniziale è tornato dopo gli altri (e paga da bere). Abbiamo ordinato i commit con un rebase invece che un hg histedit, ma avremmmo anche potuto fare diversamente.