Pro Yearly is on sale from $80 to $50! »

Mercurial - ein verteiltes Versionskontrollsystem

Mercurial - ein verteiltes Versionskontrollsystem

Mercurial ist ein verteiltes Versionskontrollsystem. Die Befehle und Funktionen sind einfach zu lernen.

Da es unabhängig vom einem Server arbeitet kann jeder lokal und auch ohne Internetverbindung Dokumente oder Quellcode damit verwalten. Trotzdem kann man mit Mercurial die Repositories untereinander austauschen und so auch über weite Entfernungen zusammen arbeiten.

Mercurial ist komplett in Python geschrieben und lässt sich deshalb einfach erweitern.

Viele bekannte Open Source Projekte und Firmen setzen Mercurial ein. So zum Beispiel Atlassian, Dovecot, Gajim, Google, Facebook, Mozilla, OpenOffice, OpenSolaris, Python, PyPy, RabbitMQ, Unity, Vim oder Xen.

16ae0a49ce39c086a67090ad54fbf67f?s=128

Markus Zapke-Gründemann

November 01, 2012
Tweet

Transcript

  1. Mercurial Ein verteiltes Versionskontrollsystem Markus Zapke-Gründemann PyCon DE 2012

  2. Übersicht • Vorstellung • Allgemeines zu DVCS und Mercurial •

    Einführung • Fortgeschrittene Themen
  3. Markus Zapke-Gründemann • Softwareentwickler seit 2001 • Softwareentwicklung mit Python,

    Django und Mercurial • Selbstständig seit 2008 • Seit 2011 Geschäftsführer bei Inqbus
  4. Verteilte Versionskontrollsysteme • Kein zentrales Repository nötig (aber möglich) •

    Jeder Client hat eine komplette Kopie des Repository • Fast alle Operationen können ohne ein zentrales Repository ausgeführt werden • Neue Entwicklungsmodelle möglich
  5. Mercurial • Verteiltes Versionskontrollsystem • Mercurial v0.1 im April 2005

    • Fast vollständig in Python geschrieben • Plattformunabhängig • Einfach zu erlernen • Einfach Erweiterbar durch Python Extensions • Open Source (GNU GPL 2)
  6. Einführung

  7. Mercurial installieren & einrichten $ pip install Mercurial $ vim

    ~/.hgrc $ cat ~/.hgrc [ui] username = Markus Zapke-Gründemann <markus@keimlink.de>
  8. hg

  9. Ein neues Repository $ hg init myproject $ cd myproject

    $ ls -A .hg
  10. Eine Datei hinzufügen $ echo "print('Hello world!')" > hello.py $

    hg status ? hello.py $ hg add adding hello.py $ hg st A hello.py
  11. Der erste Commit $ hg commit -m "Initial commit." $

    hg log changeset: 0:538ecb2ccb6a user: Markus Zapke-Gründemann <markus@keimlink.de> date: Thu Nov 01 08:23:14 2012 +0100 summary: Initial commit.
  12. Die Datei ändern $ echo "print('Hello user.')" >> hello.py $

    hg st M hello.py $ hg diff diff --git a/hello.py b/hello.py --- a/hello.py +++ b/hello.py @@ -1,1 +1,2 @@ print('Hello world!') +print('Hello user.')
  13. Der zweite Commit $ hg commit -m "Added line two."

    $ hg log changeset: 1:b847a3052569 tag: tip user: Markus Zapke-Gründemann <markus@keimlink.de> date: Thu Nov 01 08:24:05 2012 +0100 summary: Added line two. changeset: 0:538ecb2ccb6a user: Markus Zapke-Gründemann <markus@keimlink.de> date: Thu Nov 01 08:23:14 2012 +0100 summary: Initial commit.
  14. Unterschiede feststellen $ hg diff -r 0:1 diff --git a/hello.py

    b/hello.py --- a/hello.py +++ b/hello.py @@ -1,1 +1,2 @@ print('Hello world!') +print('Hello user.') $ hg diff -r 0:tip diff --git a/hello.py b/hello.py --- a/hello.py +++ b/hello.py @@ -1,1 +1,2 @@ print('Hello world!') +print('Hello user.')
  15. Zeitreisen $ hg identify b847a3052569 tip $ hg update 0

    1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cat hello.py print('Hello world!') $ hg id 538ecb2ccb6a $ hg up 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg id b847a3052569 tip
  16. Aufräumen $ echo "Lorem ipsum dolor sit amet." >> hello.py

    $ hg st M hello.py $ hg up -C 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg st
  17. Zusammenfassung

  18. Zusammenfassung $ hg init REPOSITORY # Repository erstellen

  19. Zusammenfassung $ hg init REPOSITORY # Repository erstellen $ hg

    status # Status der Dateien im Repository anzeigen
  20. Zusammenfassung $ hg init REPOSITORY # Repository erstellen $ hg

    status # Status der Dateien im Repository anzeigen $ hg st # Alias für status
  21. Zusammenfassung $ hg init REPOSITORY # Repository erstellen $ hg

    status # Status der Dateien im Repository anzeigen $ hg st # Alias für status $ hg add # Dateien zum Repository hinzufügen
  22. Zusammenfassung $ hg init REPOSITORY # Repository erstellen $ hg

    status # Status der Dateien im Repository anzeigen $ hg st # Alias für status $ hg add # Dateien zum Repository hinzufügen $ hg commit # Commit hinzugefügter und geänderter Dateien
  23. Zusammenfassung $ hg init REPOSITORY # Repository erstellen $ hg

    status # Status der Dateien im Repository anzeigen $ hg st # Alias für status $ hg add # Dateien zum Repository hinzufügen $ hg commit # Commit hinzugefügter und geänderter Dateien $ hg log # Geschichte anzeigen
  24. Zusammenfassung $ hg init REPOSITORY # Repository erstellen $ hg

    status # Status der Dateien im Repository anzeigen $ hg st # Alias für status $ hg add # Dateien zum Repository hinzufügen $ hg commit # Commit hinzugefügter und geänderter Dateien $ hg log # Geschichte anzeigen $ hg diff # Änderungen an der Arbeitskopie anzeigen
  25. Zusammenfassung $ hg init REPOSITORY # Repository erstellen $ hg

    status # Status der Dateien im Repository anzeigen $ hg st # Alias für status $ hg add # Dateien zum Repository hinzufügen $ hg commit # Commit hinzugefügter und geänderter Dateien $ hg log # Geschichte anzeigen $ hg diff # Änderungen an der Arbeitskopie anzeigen $ hg diff -r REV1:REV2 # Änderungen zwischen Revisionen anzeigen
  26. Zusammenfassung $ hg init REPOSITORY # Repository erstellen $ hg

    status # Status der Dateien im Repository anzeigen $ hg st # Alias für status $ hg add # Dateien zum Repository hinzufügen $ hg commit # Commit hinzugefügter und geänderter Dateien $ hg log # Geschichte anzeigen $ hg diff # Änderungen an der Arbeitskopie anzeigen $ hg diff -r REV1:REV2 # Änderungen zwischen Revisionen anzeigen $ hg update REV # Zu einer Revision wechseln
  27. Zusammenfassung $ hg init REPOSITORY # Repository erstellen $ hg

    status # Status der Dateien im Repository anzeigen $ hg st # Alias für status $ hg add # Dateien zum Repository hinzufügen $ hg commit # Commit hinzugefügter und geänderter Dateien $ hg log # Geschichte anzeigen $ hg diff # Änderungen an der Arbeitskopie anzeigen $ hg diff -r REV1:REV2 # Änderungen zwischen Revisionen anzeigen $ hg update REV # Zu einer Revision wechseln $ hg up REV # Alias für update
  28. Zusammenfassung $ hg init REPOSITORY # Repository erstellen $ hg

    status # Status der Dateien im Repository anzeigen $ hg st # Alias für status $ hg add # Dateien zum Repository hinzufügen $ hg commit # Commit hinzugefügter und geänderter Dateien $ hg log # Geschichte anzeigen $ hg diff # Änderungen an der Arbeitskopie anzeigen $ hg diff -r REV1:REV2 # Änderungen zwischen Revisionen anzeigen $ hg update REV # Zu einer Revision wechseln $ hg up REV # Alias für update $ hg identify # Aktuelle Revision identifizieren
  29. Zusammenfassung $ hg init REPOSITORY # Repository erstellen $ hg

    status # Status der Dateien im Repository anzeigen $ hg st # Alias für status $ hg add # Dateien zum Repository hinzufügen $ hg commit # Commit hinzugefügter und geänderter Dateien $ hg log # Geschichte anzeigen $ hg diff # Änderungen an der Arbeitskopie anzeigen $ hg diff -r REV1:REV2 # Änderungen zwischen Revisionen anzeigen $ hg update REV # Zu einer Revision wechseln $ hg up REV # Alias für update $ hg identify # Aktuelle Revision identifizieren $ hg id # Alias für identify
  30. Zusammenfassung $ hg init REPOSITORY # Repository erstellen $ hg

    status # Status der Dateien im Repository anzeigen $ hg st # Alias für status $ hg add # Dateien zum Repository hinzufügen $ hg commit # Commit hinzugefügter und geänderter Dateien $ hg log # Geschichte anzeigen $ hg diff # Änderungen an der Arbeitskopie anzeigen $ hg diff -r REV1:REV2 # Änderungen zwischen Revisionen anzeigen $ hg update REV # Zu einer Revision wechseln $ hg up REV # Alias für update $ hg identify # Aktuelle Revision identifizieren $ hg id # Alias für identify $ hg up -C # Alle Änderungen ohne Commit rückgängig machen
  31. Weitere Befehle

  32. Weitere Befehle $ hg help # Hilfe ausgeben

  33. Weitere Befehle $ hg help # Hilfe ausgeben $ hg

    help COMMAND # Hilfe zu einem Befehl anzeigen
  34. Weitere Befehle $ hg help # Hilfe ausgeben $ hg

    help COMMAND # Hilfe zu einem Befehl anzeigen $ hg copy SOURCE DEST # Eine Datei kopieren
  35. Weitere Befehle $ hg help # Hilfe ausgeben $ hg

    help COMMAND # Hilfe zu einem Befehl anzeigen $ hg copy SOURCE DEST # Eine Datei kopieren $ hg cp SOURCE DEST # Alias für copy
  36. Weitere Befehle $ hg help # Hilfe ausgeben $ hg

    help COMMAND # Hilfe zu einem Befehl anzeigen $ hg copy SOURCE DEST # Eine Datei kopieren $ hg cp SOURCE DEST # Alias für copy $ hg remove FILE # Eine Datei löschen
  37. Weitere Befehle $ hg help # Hilfe ausgeben $ hg

    help COMMAND # Hilfe zu einem Befehl anzeigen $ hg copy SOURCE DEST # Eine Datei kopieren $ hg cp SOURCE DEST # Alias für copy $ hg remove FILE # Eine Datei löschen $ hg rm FILE # Alias für remove
  38. Weitere Befehle $ hg help # Hilfe ausgeben $ hg

    help COMMAND # Hilfe zu einem Befehl anzeigen $ hg copy SOURCE DEST # Eine Datei kopieren $ hg cp SOURCE DEST # Alias für copy $ hg remove FILE # Eine Datei löschen $ hg rm FILE # Alias für remove $ hg mv SOURCE DEST # Eine Datei verschieben
  39. Weitere Befehle $ hg help # Hilfe ausgeben $ hg

    help COMMAND # Hilfe zu einem Befehl anzeigen $ hg copy SOURCE DEST # Eine Datei kopieren $ hg cp SOURCE DEST # Alias für copy $ hg remove FILE # Eine Datei löschen $ hg rm FILE # Alias für remove $ hg mv SOURCE DEST # Eine Datei verschieben $ hg revert FILE # Eine Revision wieder herstellen
  40. Weitere Befehle $ hg help # Hilfe ausgeben $ hg

    help COMMAND # Hilfe zu einem Befehl anzeigen $ hg copy SOURCE DEST # Eine Datei kopieren $ hg cp SOURCE DEST # Alias für copy $ hg remove FILE # Eine Datei löschen $ hg rm FILE # Alias für remove $ hg mv SOURCE DEST # Eine Datei verschieben $ hg revert FILE # Eine Revision wieder herstellen $ hg annotate FILE # Informationen zu jeder Zeile
  41. hgweb $ hg serve listening at http://localhost:8000/ (bound to *:8000)

  42. hg heads $ hg up 0 1 files updated, 0

    files merged, 0 files removed, 0 files unresolved $ echo "# A comment." >> hello.py $ hg commit -m "Added a comment." created new head
  43. $ hg heads changeset: 2:7e974277052b tag: tip parent: 0:538ecb2ccb6a user:

    Markus Zapke-Gründemann <markus@keimlink.de> date: Thu Nov 01 08:41:52 2012 +0100 summary: Added a comment. changeset: 1:b847a3052569 user: Markus Zapke-Gründemann <markus@keimlink.de> date: Thu Nov 01 08:24:05 2012 +0100 summary: Added line two. hg heads 0 1 2 4 3 5
  44. hg merge $ hg merge merging hello.py 0 files updated,

    1 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) $ hg diff diff --git a/hello.py b/hello.py --- a/hello.py +++ b/hello.py @@ -1,2 +1,2 @@ print('Hello world!') -# A comment. +print('Hello user.') $ hg commit -m "Merged."
  45. hg merge 0 1 2 4 3 5 6

  46. Entfernte Repositories $ hg clone http://user@hg.example.com/repo # Alice schreibt neuen

    Code. $ hg in ... $ hg pull ... $ hg up # hack hack hack $ hg out $ hg push
  47. Fortgeschrittene Themen

  48. hg help vs. hg help --debug

  49. $ hg help Mercurial Distributed SCM list of commands: add

    add the specified files on the next commit addremove add all new files, delete all missing files annotate show changeset information by line for each file archive create an unversioned archive of a repository revision backout reverse effect of earlier changeset bisect subdivision search of changesets bookmarks track a line of development with movable markers branch set or show the current branch name branches list repository named branches bundle create a changegroup file
  50. $ hg help --debug Mercurial Distributed SCM list of commands:

    add add the specified files on the next commit addremove add all new files, delete all missing files annotate, blame show changeset information by line for each file ... commit, ci commit the specified files or all outstanding changes copy, cp mark files as copied for the next commit debugancestor find the ancestor revision of two revisions in a given index debugbuilddag builds a repo with a given DAG from scratch in the current empty repo debugbundle lists the contents of a bundle debugcheckstate validate the correctness of the current dirstate debugcommands list all available commands and options
  51. hg grep $ hg grep "def forget\(" mercurial/subrepo.py:17895: def forget(self,

    ui, match, prefix): mercurial/subrepo.py:17895: def forget(self, ui, match, prefix): mercurial/commands.py:17892:def forget(ui, repo, *pats, **opts): mercurial/cmdutil.py:17891:def forget(ui, repo, match, prefix, explicitonly): hgext/largefiles/lfutil.py:17878: def forget(self, f): mercurial/context.py:17832: def forget(self, files, prefix=""): mercurial/dirstate.py:14273: def forget(self, f): mercurial/localrepo.py:11301: def forget(self, list): mercurial/hg.py:1072: def forget(self, files): mercurial/hg.py:1072: def forget(self, list):
  52. [alias] [alias] # diff stat dst = diff --stat #

    diff nur für geänderte Dateien dmod = !hg status $($HG root) -mn | xargs hg diff # status mit relativen Pfaden str = !hg status $($HG root) $HG_ARGS
  53. Extensions installieren [extensions] # Extension ist im PYTHONPATH color =

    # Pfad zur Extension ist manuell konfiguriert hgshelve = ~/.hgext/hgshelve/hgshelve.py
  54. crecord https://bitbucket.org/edgimar/crecord/wiki/Home [extensions] crecord = <path/to/crecord/package> $ hg crecord

  55. mercurial_keyring $ pip install mercurial_keyring [extensions] mercurial_keyring = [auth] myremote.schemes

    = https myremote.prefix = hg.example.com/repo myremote.username = bob http://pypi.python.org/pypi/mercurial_keyring
  56. merge vs. rebase [extensions] rebase = $ hg pull --rebase

    C1 C2 L1 R1 L2 R2 C1 C2 L1 R1 L2 R2
  57. Phases immutable shared public X X draft X secret $

    hg phase -r 8184::8186 8184: public 8185: secret 8186: secret $ hg phase -v --draft 8185 phase change for 1 changesets $ hg phase -r 8184::8186 8184: public 8185: draft 8186: secret http://mercurial.selenic.com/wiki/Phases
  58. branches vs. bookmarks • branches sind in Mercurial permanent •

    bookmarks eignen sich deshalb besser für Feature branches • Ab Mercurial 2.3 gibt es verbesserte Unterstützung für bookmarks bei pull und merge
  59. bookmarks $ hg bookmark feature1 $ hg bookmarks * feature1

    1:0b89bcda3dcf $ hg up 2 $ hg bookmark feature2 $ hg bookmarks feature1 1:0b89bcda3dcf * feature2 2:f1cd0e213eec $ hg up feature1 1 files updated, 0 files merged, 1 files removed, 0 files unresolved $ hg bookmarks * feature1 1:0b89bcda3dcf feature2 2:f1cd0e213eec $ hg bookmark --delete feature2
  60. bookmarks $ hg outgoing -B comparing with http://hg.example.com/repo searching for

    changed bookmarks feature1 1:0b89bcda3dcf $ hg push -B feature1 pushing to http://hg.example.com/repo searching for changes no changes found exporting bookmark feature1 $ hg pull pulling from http://hg.example.com/repo ... divergent bookmark feature1 stored as feature1@default (run 'hg heads .' to see heads, 'hg merge' to merge) $ hg merge
  61. Subrepos

  62. $ hg init mainrepo $ cd mainrepo $ hg init

    subrepo $ echo subrepo = subrepo > .hgsub $ hg add .hgsub $ hg commit -m "Subrepositories added" $ echo "main repo" > README $ echo "sub repo" > subrepo/README $ hg st ? README $ hg st -S ? README ? subrepo/README $ hg add adding README $ hg add -S adding subrepo/README subrepo erstellen
  63. $ hg diff diff --git a/README b/README new file mode

    100644 --- /dev/null +++ b/README @@ -0,0 +1,1 @@ +main repo $ hg diff -S diff --git a/README b/README new file mode 100644 --- /dev/null +++ b/README @@ -0,0 +1,1 @@ +main repo diff --git a/subrepo/README b/subrepo/README new file mode 100644 --- /dev/null +++ b/subrepo/README @@ -0,0 +1,1 @@ +sub repo diff mit subrepos
  64. $ hg commit abort: uncommitted changes in subrepo subrepo (use

    --subrepos for recursive commit) $ hg commit -S -m "Added README" committing subrepository subrepo $ cat .hgsubstate 8496febd9224bdb2a2e5c9dbff051b166f5cfece subrepo $ hg id -R subrepo --debug 8496febd9224bdb2a2e5c9dbff051b166f5cfece tip commit mit subrepos
  65. $ cd .. $ hg clone mainrepo mainrepo-clone updating to

    branch default cloning subrepo subrepo from /tmp/mainrepo/subrepo 3 files updated, 0 files merged, 0 files removed, 0 files unresolved $ tree -a -L 2 mainrepo-clone mainrepo-clone !"" .hg # !"" 00changelog.i # !"" branch # !"" cache # !"" dirstate # !"" hgrc # !"" requires # $"" store !"" .hgsub !"" .hgsubstate !"" README $"" subrepo !"" .hg $"" README clone mit subrepos
  66. Eigene Extensions

  67. totalnodes.py """totalnodes Prints total number of nodes in a repo.

    """ def totalnodes(ui, repo, **opts): """Prints total number of nodes in a repo.""" if opts['prefix']: ui.write(opts['prefix']) ui.write('%d\n' % len(repo)) cmdtable = { 'totalnodes': (totalnodes, [('p', 'prefix', '', 'prefix option')], '[options]') } buglink = 'http://bugs.example.com/' testedwith = '2.2 2.3'
  68. Links • http://mercurial.selenic.com/ • http://hgbook.red-bean.com/ • http://hginit.com/ • http://mercurial.aragost.com/kick-start/en/

  69. Fragen? www.inqbus.de www.keimlink.de @keimlink