Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Übersicht • Vorstellung • Allgemeines zu DVCS und Mercurial • Einführung • Fortgeschrittene Themen

Slide 3

Slide 3 text

Markus Zapke-Gründemann • Softwareentwickler seit 2001 • Softwareentwicklung mit Python, Django und Mercurial • Selbstständig seit 2008 • Seit 2011 Geschäftsführer bei Inqbus

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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)

Slide 6

Slide 6 text

Einführung

Slide 7

Slide 7 text

Mercurial installieren & einrichten $ pip install Mercurial $ vim ~/.hgrc $ cat ~/.hgrc [ui] username = Markus Zapke-Gründemann

Slide 8

Slide 8 text

hg

Slide 9

Slide 9 text

Ein neues Repository $ hg init myproject $ cd myproject $ ls -A .hg

Slide 10

Slide 10 text

Eine Datei hinzufügen $ echo "print('Hello world!')" > hello.py $ hg status ? hello.py $ hg add adding hello.py $ hg st A hello.py

Slide 11

Slide 11 text

Der erste Commit $ hg commit -m "Initial commit." $ hg log changeset: 0:538ecb2ccb6a user: Markus Zapke-Gründemann date: Thu Nov 01 08:23:14 2012 +0100 summary: Initial commit.

Slide 12

Slide 12 text

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.')

Slide 13

Slide 13 text

Der zweite Commit $ hg commit -m "Added line two." $ hg log changeset: 1:b847a3052569 tag: tip user: Markus Zapke-Gründemann date: Thu Nov 01 08:24:05 2012 +0100 summary: Added line two. changeset: 0:538ecb2ccb6a user: Markus Zapke-Gründemann date: Thu Nov 01 08:23:14 2012 +0100 summary: Initial commit.

Slide 14

Slide 14 text

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.')

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

Zusammenfassung

Slide 18

Slide 18 text

Zusammenfassung $ hg init REPOSITORY # Repository erstellen

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Weitere Befehle

Slide 32

Slide 32 text

Weitere Befehle $ hg help # Hilfe ausgeben

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

hgweb $ hg serve listening at http://localhost:8000/ (bound to *:8000)

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

$ hg heads changeset: 2:7e974277052b tag: tip parent: 0:538ecb2ccb6a user: Markus Zapke-Gründemann date: Thu Nov 01 08:41:52 2012 +0100 summary: Added a comment. changeset: 1:b847a3052569 user: Markus Zapke-Gründemann date: Thu Nov 01 08:24:05 2012 +0100 summary: Added line two. hg heads 0 1 2 4 3 5

Slide 44

Slide 44 text

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."

Slide 45

Slide 45 text

hg merge 0 1 2 4 3 5 6

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

Fortgeschrittene Themen

Slide 48

Slide 48 text

hg help vs. hg help --debug

Slide 49

Slide 49 text

$ 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

Slide 50

Slide 50 text

$ 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

Slide 51

Slide 51 text

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):

Slide 52

Slide 52 text

[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

Slide 53

Slide 53 text

Extensions installieren [extensions] # Extension ist im PYTHONPATH color = # Pfad zur Extension ist manuell konfiguriert hgshelve = ~/.hgext/hgshelve/hgshelve.py

Slide 54

Slide 54 text

crecord https://bitbucket.org/edgimar/crecord/wiki/Home [extensions] crecord = $ hg crecord

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

merge vs. rebase [extensions] rebase = $ hg pull --rebase C1 C2 L1 R1 L2 R2 C1 C2 L1 R1 L2 R2

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

Subrepos

Slide 62

Slide 62 text

$ 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

Slide 63

Slide 63 text

$ 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

Slide 64

Slide 64 text

$ 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

Slide 65

Slide 65 text

$ 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

Slide 66

Slide 66 text

Eigene Extensions

Slide 67

Slide 67 text

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'

Slide 68

Slide 68 text

Links • http://mercurial.selenic.com/ • http://hgbook.red-bean.com/ • http://hginit.com/ • http://mercurial.aragost.com/kick-start/en/

Slide 69

Slide 69 text

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