Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Mercurial: Experimente für Fortgeschrittene

Mercurial: Experimente für Fortgeschrittene

Dieser Vortrag zeigt die vielfältigen Einsatzmöglichkeiten von Mercurial abseits der häufig genutzten Funktionen.

Themen des Vortrags sind unter anderem: Cherry Picking, Bookmarks, Patches, Subrepositories, Konvertieren und Zusammenführen von Repositories, Umgang mit großen Dateien sowie das Veröffentlichen von Repositories.

Markus Zapke-Gründemann

March 16, 2013
Tweet

More Decks by Markus Zapke-Gründemann

Other Decks in Programming

Transcript

  1. Markus Zapke-Gründemann • Softwareentwickler seit 2001 • Softwareentwicklung mit Python,

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

    Jeder Client hat eine komplette Kopie des Repositories • Neue Entwicklungsmodelle möglich
  3. 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)
  4. Extensions installieren [extensions] # Extension im $PYTHONPATH color = #

    Pfad zur Extension manuell angegeben hgshelve = ~/.hgext/hgshelve/hgshelve.py
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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')"
  10. 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)"
  11. 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):
  12. [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
  13. 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
  14. merge vs. rebase C1 C2 L1 R1 L2 R2 M1

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

    hg rebase -s L1 -d R2 C1 C2 L1 R1 L2 R2 $ hg pull
  16. 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 #
  17. 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)
  18. 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
  19. 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.”
  20. 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
  21. 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'
  22. largefiles [extensions] largefiles = $ hg lfconvert --size 10 oldrepo

    newrepo [largefiles] minsize = 10 patterns = *.jpg library.zip content/audio/*
  23. $ 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
  24. $ 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
  25. $ 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
  26. $ 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