There are two main ways to organize branches in Mercurial: named branches and bookmarks. Bookmarks are used for short-term feature or topic branches whereas named branches are used for long-term branches.
Ramos nomeados funcionam bem em uma configuração em que você precisa rastrear o contexto em que cada changeset foi feito; o nome do ramo fica embutido no changeset e você pode se referir a ele anos depois. Como o nome do ramo é embutido no histórico, ramos nomeados são ótimos quando se precisa auditar os registros e é necessário ver quem fez o que e quando.
Há contextos em que ramos nomeados não funcionam tão bem: se você não precisa rastrear ou quer rastrear o nome do ramo depois que o ramo já começou, então os ramos nomeados não são para você. Talvez você só queira experimentar um pouco sem se comprometer com um nome de ramo, ou talvez você queira poder mudar o nome do ramo depois.
Se é o seu caso, então os bookmarks do Mercurial serão de grande ajuda.
Note
Você deve usar a versão 2.1 ou mais recente do Mercurial para acompanhar os exemplos desta seção.
Contents
A seguir, vamos explorar os bookmarks em detalhes, mas em resumo, um bookmark permite que você associe um nome a um changeset. Isto é útil quando se está trabalhando em várias coisas diferentes ao mesmo tempo — tal como em dois ramos de funcionalidades.
Rótulos (tags) também adicionam novos nomes a changesets, mas diferente de rótulos, bookmarks são mutáveis e transientes: você pode mover, renomear ou deletá-los e eles não são armazendos no histórico. Isto significa que bookmarks não deixam registros para auditoria.
Imagine que Alice, Bob e Carla estão escrevendo um livro de sentenças (de viagem) juntos. No projeto, eles trabalharão em sentenças de diferentes categorias, e algumas vezes terão de trabalhar em diferentes categorias ao mesmo tempo Sendo assim, eles naturalmente terão vários ramos em andamento ao mesmo tempo. Bookmarks permitirão rastrear esses ramos de modo leve.
Carla é a chefe, então ela começa criando o repositório que será usado pelo projeto:
carla$ hg init phrases carla$ cd phrases carla$ echo "The Phrase Book Project" > README.txt carla$ hg add adding README.txt carla$ hg commit -m "Added a README"
Alice e Bob cada um tem seu próprio clone e empurram/puxam para e a partir do repositório de Carla, que age como um repositório central. Geralmente, o repositório central fica hospedado em um servidor da empresa e os clones nas máquinas dos desenvolvedores. Mas por simplicidade, vamos manter todos os três repositórios no mesmo sistema de arquivos.
Alice e Bob agora podem fazer um clone do repositório que Carla acabou de montar. Para Alice, a clonagem será assim:
alice$ hg clone ../carla/phrases destination directory: phrases updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved alice$ cd phrases
Elas estarão trabalhando em sentenças de diferentes categorias e começarão pela coleta de sentenças em Inglês. Carla pede a Alice para adicionar sentenças usadas para saudações:
alice$ echo "Hello!" > greetings.txt alice$ hg add adding greetings.txt alice$ hg commit -m "First greeting"
Carla pede para Alice começar a procurar por sentenças de viagem. Alice já estava trabalhando nas saudações, e gostaria de separar as duas tarefas — misturar mudanças relacionadas a saudações com mudanças de viagem tornará mais difícil a revisão depois. Portanto, Alice retornará (hg update) à revisão 0 e iniciará um novo ramo de tarefa a partir de lá. Mas para lembrar onde ela estava antes ela criará um bookmark antes. Nesse momento, o repositório dela ainda está assim:
As mudanças relacionadas com saudações estão identificadas como estando no ramo default e sendo o changeset tip. Estes identificadores se moverão quando ela começar a trabalhar no novo ramo, então ela precisa de algo mais estável — um bookmark. Ela cria o bookmark:
alice$ hg bookmark greetings
O changeset agora tem um bookmark associado a ele:
Ela pode ver o bookmark usando hg bookmarks:
alice$ hg bookmarks * greetings 1:0b89bcda3dcf
O asterisco (*) indica que o bookmark está ativo, o que significa que ele se moverá à medida que ela fizer novas consolidações. Como o bookmark se move a cada consolidação, ele sempre apontará para a ponta (head) do ramo em que você estiver trabalhando.
Alice deseja criar um novo ramo para sentenças de viagem. O ramo deve começar na revisão 0, de modo que ela atualiza sua revisão antes. Isto faz com que o bookmark greetings ficar inativo pois ela se moveu para fora do ramo de desenvolvimento:
alice$ hg update 0 0 files updated, 0 files merged, 1 files removed, 0 files unresolved alice$ hg bookmarks greetings 1:0b89bcda3dcf
O bookmark permanece no lugar original:
Isto significa que Alice podem sempre executar hg update greetings para voltar a ele novamente. Por enquanto, ela será esperta o suficiente para criar um novo bookmark chamado traveling para o novo ramo que Carla pediu para ela fazer. O novo bookmark se torna ativo automaticamente:
alice$ hg bookmark traveling alice$ hg bookmarks greetings 1:0b89bcda3dcf * traveling 0:4326a390b9b6
O bookmark ativo também pode ser visto no TortoiseHg:
Agora, quando Alice criar uma nova consolidação, o bookmark traveling irá, bem…, viajar com a consolidação:
alice$ echo "When does the bus arrive?" > traveling.txt alice$ hg add traveling.txt alice$ hg commit -m "Started on traveling phrases" created new head
Agora que Alice tem bookmarks na revisão 1 e 2, ela pode usar os nomes dos bookmarks em todos os comandos que esperam um número de revisão. Isto é, ela pode usar 1 (o número de revisão local), 0b89bcda3dcf (o identificado global do changeset) e greetings (o bookmark) alternadamente:
alice$ hg log -r 1 changeset: 1:0b89bcda3dcf bookmark: greetings user: Alice <alice@example.net> date: Tue May 01 10:20:35 2012 +0000 summary: First greeting alice$ hg log -r 0b89bcda3dcf changeset: 1:0b89bcda3dcf bookmark: greetings user: Alice <alice@example.net> date: Tue May 01 10:20:35 2012 +0000 summary: First greeting alice$ hg log -r greetings changeset: 1:0b89bcda3dcf bookmark: greetings user: Alice <alice@example.net> date: Tue May 01 10:20:35 2012 +0000 summary: First greeting
Da mesma forma que rótulos e nomes de ramos, bookmarks também funcionarão com todos os comandos — hg diff, hg merge etc.. A atualização fica assim:
alice$ hg update greetings 1 files updated, 0 files merged, 1 files removed, 0 files unresolved alice$ hg bookmarks * greetings 1:0b89bcda3dcf traveling 2:f1cd0e213eec alice$ hg update traveling 1 files updated, 0 files merged, 1 files removed, 0 files unresolved alice$ hg bookmarks greetings 1:0b89bcda3dcf * traveling 2:f1cd0e213eec
Note como o bookmark que ela atualizou se tornou o bookmark ativo no momento. Uma nova consolidação avançará o bookmark ativo, de forma que hg update traveling é suficiente para preparar a cópia de trabalho de Alice para trabalhar no ramo traveling.
The distinguishing feature of bookmarks compared to named branches is that they exist outside of the history. Here, “history” means the immutable changesets that cannot be changed without changing their changeset IDs. Bookmarks are not stored in the changesets and they are not part of the computation of changeset IDs. They can therefore be deleted and renamed at will.
Imagine que Alice adicione um novo bookmark:
alice$ hg bookmark some-name alice$ hg bookmarks greetings 1:0b89bcda3dcf * some-name 2:f1cd0e213eec traveling 2:f1cd0e213eec
Ela pode renomear o bookmark:
alice$ hg bookmark --rename some-name new-name alice$ hg bookmarks greetings 1:0b89bcda3dcf * new-name 2:f1cd0e213eec traveling 2:f1cd0e213eec
E também removê-lo:
alice$ hg bookmark --delete new-name alice$ hg bookmarks greetings 1:0b89bcda3dcf traveling 2:f1cd0e213eec
Não fica rastro de um bookmark removido; ninguém pode dizer que um dia existiram. Isto faz com que bookmarks sejam bons para rastrear pequenos ramos de funcionalidades que não precisam ser registrados no histórico de longo prazo da mesma forma que os ramos nomeados são registrados.
Depois de remover o bookmark new-name, não há nenhum bookmark ativo. Nós continuaremos trabalhando no ramo traveling, que precisa ser ativado novamente:
alice$ hg update traveling 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
Enquanto Alice estava trabalhando, Carla também esteve ocupada. Ela atualizou o arquivo README com os autores:
carla$ echo "by Alice, Bob, and Carla" >> README.txt carla$ hg commit -m "Added authors"
Isto significa que o ramo traveling de Alice se tornará uma segunda head quando ela empurrar seus changesets. Por padrão, o Mercurial não permite que esta situação aconteça:
alice$ hg push -r traveling pushing to /home/carla/phrases searching for changes abort: push creates new remote head f1cd0e213eec! (you should pull and merge or use push -f to force)
Para investigar a situação, Alice terá de primeiro puxar e olhar o repositório pelo TortoiseHg:
alice$ hg pull pulling from /home/carla/phrases searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) (run 'hg heads .' to see heads, 'hg merge' to merge)
Há três heads! Empurrar a head do ramo traveling na verdade criará duas heads no repositório remoto e o Mercurial se protege contra isso pois várias heads sem nome podem ser confusas: usuários que clonem o repositório não saberão qual head eles devem usar como a base para seu próprio trabalho. Quando só há uma head, não há dúvida — você apenas clona e começa a trabalhar.
Acima, o Mercurial sugere a mesclagem das heads ou o uso de -f para forçar o envio. Forçar costuma ser um sinal de que você não está usando a ferramenta como projetada, mas esta é uma situação que você realmente quer adicionar a opção -f. A razão é que o trabalho de Alice no ramo traveling ainda não está terminado e, por isso, ela ainda não quer misturar as mudanças desse ramo com as mudanças do ramo prncipal. Se houvesse uma correção importante no ramo principal, então ela poderia ter mesclado no seu ramo, mas aqui não é o caso.
Alice forçará o envio do seu ramo para o repositório remoto:
alice$ hg push -f -r traveling pushing to /home/carla/phrases searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads)
É muito importante que Alice restrinja a operação para empurrar apenas o ramo que ela deseja! Ela tem dois ramos que não existem no repositório de Carla, e a opção -f diz ao Mercurial para empurrar cegamente todas os changesets possíveis. Algum cuidado é necessário para empurrar um de todos os ramos privados. Aqui, a mensagem +1 heads indica que Alice fez o desejado — ela enviou um único novo ramo ao repositório.
Como as coisas se parecem a partir da perspectiva de Carla? Ela agora tem duas heads anônimas no seu repositório:
carla$ hg heads changeset: 2:f1cd0e213eec tag: tip parent: 0:4326a390b9b6 user: Alice <alice@example.net> date: Tue May 01 10:20:40 2012 +0000 summary: Started on traveling phrases changeset: 1:4b18431b805d user: Carla <carla@example.net> date: Tue May 01 10:20:45 2012 +0000 summary: Added authors
Chamamos de anônimo porque não há nomes associadas a elas — elas estão no mesmo ramo nomeado e não têm bookmarks:
carla$ hg bookmarks no bookmarks set
Uma vez que Alice pretende continuar trabalhando no ramo, seria conveniente que seu bookmark fosse enviado também. Originalmente, (antes da versão 1.6 do Mercurial), bookmarks eram estritamente locais, mas agora é possível puxar e empurrar bookmarks.
Bookmarks podem ser empurrados e puxados entre repositórios. Isto funciona sobre qualquer um dos protocolos usados pelo Mercurial: SSH, HTTP e acesso ao sistema de arquivos local. A habilidade de empurrar um bookmark é regida pelas mesmas regras de acesso a uma operação de push. Se você pode empurrar um changeset para um repositório, então você também pode empurrar um bookmark.
Alice pode facilmente consertar seu erro anterior. Primeiro, ela usa hg outgoing -B para ver quais os bookmarks presentes no repositório local que não estão presentes no repositório do servidor (de modo análogo, hg incoming -B relatará os bookmarks presentes no servidor que não existem no repositório local):
alice$ hg outgoing -B comparing with /home/carla/phrases searching for changed bookmarks greetings 0b89bcda3dcf traveling f1cd0e213eec
Ela tem dois bookmarks locais que não existem no servidor. Para empurrar um bookmark, basta ela usar -B ao invés de -r no comando de push:
alice$ hg push -B traveling pushing to /home/carla/phrases searching for changes no changes found exporting bookmark traveling
Isto fará o Mercurial empurrar os changesets apontados por traveling e exportar o bookmark para o servidor. Como ela já empurrou os changesets, apenas o bookmark é empurrado agora. O repositório de Carla agora está muito mais organizado que antes:
Alice publicará seu ramo gretings da mesma maneira, e fará do modo correto desta vez:
alice$ hg push -f -B greetings pushing to /home/carla/phrases searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) exporting bookmark greetings
Agora que Alice publicou seu bookmark traveling, ela pode continuar trabalhando e empurrar de volta para Carla periodicamente. Isto automaticamente avançará o bookmark no servidor — a opção -B não será mais necessária:
alice$ echo "Two tickets, please!" >> traveling.txt alice$ hg commit -m "A ticket phrase" alice$ hg push pushing to /home/carla/phrases searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files updating bookmark traveling
Note a mensagem updating bookmark traveling embaixo. Isto informa a Alice que o bookmark está sincronizado nos dois repositórios.
Alice e Bob podem trabalhar juntos no mesmo ramo. Primeiro, Bob puxará o ramo de Carla. Bob precisa importar explicitamente o bookmark com a opção -B na primeira vez que puxa o ramo:
bob$ hg pull -B traveling pulling from /home/carla/phrases searching for changes adding changesets adding manifests adding file changes added 2 changesets with 2 changes to 1 files (run 'hg update' to get a working copy) importing bookmark traveling bob$ hg bookmarks traveling 2:0098cff6f6d8
Note
Este comportamento mudará na versão 2.3 do Mercurial. A partir desta versão, o Mercurial automaticamente importará os bookmarks remotos dos changesets empurrados. Isto significa que Bob precisa apenas executar hg pull para pegar todos os changesets e bookmarks de Carla.
Bob irá para o ramo, fará uma mudança e a empurrará de volta:
bob$ hg update traveling 1 files updated, 0 files merged, 0 files removed, 0 files unresolved bob$ echo "Where is the train station?" >> traveling.txt bob$ hg commit -m "Asking for a train station" bob$ hg push pushing to /home/carla/phrases searching for changes note: unsynced remote changes! adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files updating bookmark traveling
Note como o bookmark traveling foi atualizado automaticamente no servidor. Geralmente, o Mercurial cuida de sincronizar um bookmark durante as operações de push e pull tão logo ele exista local e remotamente. Há uma restrição adicional: hg push apenas atualiza o bookmark remoto se ele for um ancestral do bookmark local. Se os bookmarks divergirem, então alguém mais trabalhou no ramo e duas heads deverão ser mescladas antes da publicação. Veremos isso na próxima situação.
Bob acabou de empurrar um changeset no ramo traveling, mas Alice ainda não o puxou. Antes de puxá-lo, ela faz sua própria consolidação no ramo:
alice$ echo "How much for a ticket?" >> traveling.txt alice$ hg commit -m "Asking for the ticket price"
Como é comum no Mercurial, ela notará a nova consolidação de Bob quando tentar empurrar de volta ao servidor:
alice$ hg push pushing to /home/carla/phrases searching for changes abort: push creates new remote head e0c765eadfc4! (you should pull and merge or use push -f to force)
Aqui ela deseja puxar e mesclar — ela não está publicando um novo ramo de funcionalidade, logo seria errado usar a opção -f.
Quando Alice puxa, ela obterá o changeset de Bob:
alice$ hg pull pulling from /home/carla/phrases searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) divergent bookmark traveling stored as traveling@default (run 'hg heads .' to see heads, 'hg merge' to merge)
Além da saída normal de hg pull, o Mercurial imprime uma mensagem sobre o aparecimento de um bookmark divergente que foi chamado de traveling@default. No TortoiseHg, a situação fica assim:
O que aconteceu é que o Mercurial detectou que o traveling no servidor divergiu do traveling local. Como explicado acima, a divergência significa que os bookmarks são irmãos — um não é ancestral do outro. O bookmark remoto foi renomeado para traveling@default. O @default vem do caminho default. Se Alice tivesse:
[paths] carla = /home/carla/phrases
no seu arquivo .hg/hgrc, então o bookmark teria sido renomeado para traveling@carla.
Alice agora mesclará com a outra head. Normalmente, ela pode executar hg merge e o Mercurial automaticamente seleciona a outra head no ramo como o candidato óbvio da mesclagem. Mas isto não funciona com bookmarks:
alice$ hg merge abort: branch 'default' has 4 heads - please merge with an explicit rev (run 'hg heads .' to see heads)
Ela tem de especificar o bookmark divergente manualmente:
alice$ hg merge "traveling@default" merging traveling.txt warning: conflicts during merge. merging traveling.txt incomplete! (edit conflicts, then use 'hg resolve --mark') 0 files updated, 0 files merged, 0 files removed, 1 files unresolved use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
Há um conflito porque Alice e Bob adicionaram uma nova linha depois da primeira linha. Alice resolve o conflito incorporando ambas as linhas no arquivo:
alice$ cat traveling.txt When does the bus arrive? Two tickets, please! <<<<<<< local How much for a ticket? ======= Where is the train station? >>>>>>> other alice$ hg resolve --tool internal:local traveling.txt alice$ echo "Where is the train station?" >> traveling.txt
Ela verifica as diferenças e como parece tudo certo, ela consolida a mesclagem:
alice$ hg diff diff -r e0c765eadfc4 traveling.txt --- a/traveling.txt Tue May 01 10:21:00 2012 +0000 +++ b/traveling.txt Tue May 01 10:21:03 2012 +0000 @@ -1,3 +1,4 @@ When does the bus arrive? Two tickets, please! How much for a ticket? +Where is the train station? alice$ hg commit -m "Merged with Bob"
Depois da mesclagem, os bookmarks divergentes ainda estão lá:
alice$ hg bookmarks greetings 1:0b89bcda3dcf * traveling 7:0e1a5b84f635 traveling@default 6:888ae5a9e614
Alice não precisa mais do bookmark, então ela o apaga:
alice$ hg bookmarks --delete "traveling@default"
O repositório fica assim:
Note
A versão 2.3 melhorará isso: hg merge selecionará automaticamente um bookmark divergente como candidato à mesclagem. Depois que a mesclagem for consolidada, o bookmark divergente será removido automaticamente.
Quando ela empurra de volta para Carla, o bookmark traveling se moverá adiante. Antes de empurrar, ele estava apontando para 888ae5a9e614, e como 0e1a5b84f635 é um descendente, o bookmark pode se mover adiante no servidor.
alice$ hg push pushing to /home/carla/phrases searching for changes adding changesets adding manifests adding file changes added 2 changesets with 2 changes to 1 files updating bookmark traveling
Alice e Bob coletaram três sentenças sobre viagem, e decidem que o ramo traveling pode ser mesclado de volta na linha principal.
Alice fará a mesclagem. Ela inicial puxando de Carla para garantir que ela tem as mudanças mais recentes. Em seguida, ela atualiza para a head sem nome onde Carla estava editando o arquivo README.txt:
alice$ hg pull pulling from /home/carla/phrases searching for changes no changes found alice$ hg update -r "head() and not bookmark()" 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
In the update command, Alice used a revision set to select the changeset that is a head with no bookmark. She can see in TortoiseHg that she ended up at the correct changeset:
Ela pode agora simplesmente mesclar com o ramo traveling:
alice$ hg merge traveling 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) alice$ hg commit -m "Merged with traveling branch"
O resultado é o esperado:
o ramo foi mesclado e o bookmark não é mais necessário. Alice pode apagá-lo:
alice$ hg bookmark --delete traveling
Ela também pode empurrar a mesclagem de volta:
alice$ hg push pushing to /home/carla/phrases searching for changes adding changesets adding manifests adding file changes added 1 changesets with 0 changes to 0 files (-1 heads)
Embora ela tenha removido o bookmark localmente e empurrado o changeset da mesclagem, o bookmark ainda existe no servidor:
alice$ hg incoming -B comparing with /home/carla/phrases searching for changed bookmarks traveling 0e1a5b84f635
Para remover no servidor, Alice executa
alice$ hg push -B traveling pushing to /home/carla/phrases searching for changes no changes found deleting remote bookmark traveling
Especificar um bookmark que não existe localmente mas existe no servidor removerá o bookmark do servidor. Isto é parecido com quando ele publicou o bookmark da primeira vez: hg push -B NOME fará NOME apontar no servidor para a mesma coisa que ele aponta localmente — se NOME não existe localmente, ele também não existirá no servidor.
Alice poderia ter empurrado a mesclagem e removido o bookmark em uma única operação. Vamos ilustrar isto pela mesclagem do ramo greetings:
alice$ hg merge greetings 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) alice$ hg commit -m "Merged greetings branch" alice$ hg bookmark --delete greetings alice$ hg push -B greetings -r . pushing to /home/carla/phrases searching for changes adding changesets adding manifests adding file changes added 1 changesets with 0 changes to 0 files (-1 heads) deleting remote bookmark greetings
Aqui, -B greetings é o que faz o Mercurial remover o bookmark remoto, e -r . é o que faz ele enviar o changeset da mesclagem recém criada: a revisão . (ponto) é um atalho para a revisão-pai da cópia de trabalho. Sem a opção -r ., hg push teria empurrado apenas o changeset de greetings — e assim o changeset da mesclagem não teria sido incluído na operação.
Bookmarks fornecem uma maneira leve para rastrear várias linhas de desenvolvimento (heads) no seu repositório. As principais características dos bookmarks são:
Mútáveis: Bookmarks ficam fora do histórico do changeset e podem ser adicionados, renomeados e removidos sem deixar rastro. Isto torna os bookmarks bons para rastrear ramos de funcionalidades ou de tópicos.
Compartilháveis: Bookmarks podem ser empurrados e puxados entre os repositórios. Quando um bookmark é publicado, o Mercurial o manterá sincronizado. Como os bookmarks não são publicados automaticamente, você pode mantê-los privados até decidir compartilhá-los.
Os principais comandos usados para trabalhar com bookmarks são:
hg bookmarks: Listam todos os bookmarks.
hg bookmark NOME: Cria um novo bookmark chamado NOME.
hg update NOME: Atualiza a cópia de trabalho para a revisão apontada por NOME e torna o bookmark ativo.
hg incoming -B: Mostra todos os bookmarks que existem no repositório remoto mas que não existem no repositório local.
hg push -B NOME: Publica um ramo NOME e o bookmark associado. Se NOME não existe localmente, apaga o bookmark NOME no repositório remoto.
hg pull -B NAME: Puxa o ramo NOME junto com seu bookmark.
Uma pessoa do grupo deve criar um repositório e as outras devem cloná-lo.
Crie um bookmark depois que você fez algumas consolidações.
Publique seu bookmark no repositório central e puxe os outros ramos para o seu próprio repositório.
See the revision set documentation and try a query like hg log -r "ancestors(NAME) - ancestors(.)" to see changesets on the branch NAME that have not yet been merged into your current revision. Revision sets also work in TortoiseHg.
Atualize para um dos outros ramos e faça uma consolidação. Empurre de volta para o servidor e experimente lidar com bookmarks divergentes.
Enable the rebase extension and try rebasing a feature branch on top of the main line of development. The bookmarks should follow along automatically.
As primeiras versões do Mercurial não tinha nem ramos nomeados nem bookmarks. Ramos nomeados foram introduzidos na versão 0.9.2 (Dezembro de 2006) e bookmarks dois anos depois. Com o passar dos anos, bookmarks ganharam funcionalidades e se tornaram mais estáveis. Eventos de destaque até a versão 2.2 do Mercurial foram:
Devido ao longo histórico das funcionalidades trazida pelos bookmarks, há alguns guias por aí que contém informação desatualizada. Você pode comparar a data da publicação do guia com a tabela acima para ver quais características que o guia provavelmente não sabe.