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. Mercurial:
    Experimente
    für Fortgeschrittene
    Markus Zapke-Gründemann
    Chemnitzer Linux-Tage 2013

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  5. hgweb

    View Slide

  6. View Slide

  7. View Slide

  8. View Slide

  9. RhodeCode
    rhodecode.org

    View Slide

  10. View Slide

  11. View Slide

  12. View Slide

  13. Hilfe!
    hg help [TOPIC]

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  23. [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

    View Slide

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

    View Slide

  25. rebase
    [extensions]
    rebase =

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  30. 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
    #

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  34. 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.”

    View Slide

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

    View Slide

  36. Eigene Extensions

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  40. Subrepos

    View Slide

  41. $ 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

    View Slide

  42. $ 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

    View Slide

  43. $ 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

    View Slide

  44. $ 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

    View Slide

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

    View Slide

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

    View Slide