Slide 1

Slide 1 text

Mercurial: Experimente für Fortgeschrittene Markus Zapke-Gründemann Chemnitzer Linux-Tage 2013

Slide 2

Slide 2 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 3

Slide 3 text

Verteilte Versionskontrollsysteme • Kein zentrales Repository nötig (aber möglich) • Jeder Client hat eine komplette Kopie des Repositories • Neue Entwicklungsmodelle möglich

Slide 4

Slide 4 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 5

Slide 5 text

hgweb

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

RhodeCode rhodecode.org

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Hilfe! hg help [TOPIC]

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 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 17

Slide 17 text

branches vs. bookmarks • branches sind in Mercurial permanent • bookmarks eignen sich deshalb besser für Feature branches • Seit Mercurial 2.3 gibt es verbesserte Unterstützung für bookmarks bei pull und merge

Slide 18

Slide 18 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 19

Slide 19 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 20

Slide 20 text

file sets hg diff "set: not binary()" hg status "set: grep(foo) and modified()" hg locate "set: **.c and not encoding('UTF-8')" hg revert "set: copied() and binary() and size('>1M')"

Slide 21

Slide 21 text

rev sets hg log -r "branch(default)" hg log -r "1.3::1.5 and keyword(bug) hg log -r "sort(date('May 2012'), user)" hg log -r "children(98909dac31e0) and grep(bar)"

Slide 22

Slide 22 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 23

Slide 23 text

[alias] [alias] # diff stat dst = diff --stat # diff nur für geänderte Dateien dmod = diff "set: modified()" # status mit relativen Pfaden str = !hg status $($HG root) $HG_ARGS

Slide 24

Slide 24 text

Phases immutable shared public X X draft X secret $ hg phase -r 8184::8186 8184: public 8185: draft 8186: draft $ hg phase -v --secret 8185 phase change for 1 changesets $ hg phase -r 8184::8186 8184: public 8185: secret 8186: draft http://mercurial.selenic.com/wiki/Phases

Slide 25

Slide 25 text

rebase [extensions] rebase =

Slide 26

Slide 26 text

merge vs. rebase C1 C2 L1 R1 L2 R2 M1 $ hg pull $ hg merge $ hg commit

Slide 27

Slide 27 text

merge vs. rebase C1 C2 L1 R1 L2 R2 $ hg rebase -s L1 -d R2 C1 C2 L1 R1 L2 R2 $ hg pull

Slide 28

Slide 28 text

merge vs. rebase $ hg pull --rebase C1 C2 L1 R1 L2 R2

Slide 29

Slide 29 text

graft C12 C13 C14 ... C17 $ hg graft -r C17 default stable C17

Slide 30

Slide 30 text

histedit $ hg histedit -r c561b4e977df pick c561b4e977df Add beta pick 030b686bedc4 Add gamma pick 7c2fd3b9020c Add delta # Edit history between c561b4e977df and 7c2fd3b9020c # # Commands: # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but fold into previous commit (combines N and N-1) # d, drop = remove commit from history # m, mess = edit message without changing commit content #

Slide 31

Slide 31 text

convert $ hg branches foo 2:37ef0ce38ccd default 1:a3d14dced1a2 (inactive) $ cd .. $ echo ”foo bar” > branch.map $ hg convert --branchmap branch.map myrepo myrepo-fix $ cd myrepo-fix $ hg branches bar 2:d7d3f591f211 default 1:a3d14dced1a2 (inactive)

Slide 32

Slide 32 text

importfs $ pip install hg-importfs [extensions] importfs =

Slide 33

Slide 33 text

importfs $ hg up -R myproject 1.0 $ hg importfs myrepo myproject -t 1.0 created repository myrepo 0 files updated, 0 files merged, 0 files removed, 0 files unresolved adding ... $ hg up -R myproject 1.1 $ hg importfs myrepo myproject -m "Import v1.1" -t 1.1 8 files updated, 0 files merged, 1 files removed, 0 files unresolved removing ... adding ... https://pypi.python.org/pypi/hg-importfs

Slide 34

Slide 34 text

mq [extensions] mq = $ hg init --mq ...hack...hack $ hg qnew my_new_feature.patch ...hack...hack $ hg qrefresh $ hg st --mq A .hgignore A my_new_feature.patch A series $ hg qseries my_new_feature.patch $ hg ci --mq -m ”First version of patch.”

Slide 35

Slide 35 text

mq $ hg qpop popping my_new_feature.patch patch queue now empty $ hg qseries -v 0 U my_new_feature.patch $ hg qpush applying my_new_feature.patch now at: my_new_feature.patch $ hg qrefresh -e $ hg qfinish -a

Slide 36

Slide 36 text

Eigene Extensions

Slide 37

Slide 37 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.4 2.5'

Slide 38

Slide 38 text

Here be dragons Bildquelle: https://en.wikipedia.org/wiki/File:D%C3%BCrer_-_Michaels_Kampf_mit_dem_Drachen.jpg

Slide 39

Slide 39 text

largefiles [extensions] largefiles = $ hg lfconvert --size 10 oldrepo newrepo [largefiles] minsize = 10 patterns = *.jpg library.zip content/audio/*

Slide 40

Slide 40 text

Subrepos

Slide 41

Slide 41 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 42

Slide 42 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 43

Slide 43 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 44

Slide 44 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 45

Slide 45 text

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

Slide 46

Slide 46 text

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