<<

SCM (Hg) Toomas Laasik

1.06.2018 Mercurial

Mercurial is a free, distributed source control management tool, like Mercurial

Mercurial is a free, distributed source control management tool, like git

Philosophy and key points:

● Usability first, has consistent syntax and help Mercurial

Mercurial is a free, distributed source control management tool, like git

Philosophy and key points:

● Usability first, has consistent syntax and help ● Each command does one thing Mercurial

Mercurial is a free, distributed source control management tool, like git

Philosophy and key points:

● Usability first, has consistent syntax and help ● Each command does one thing ● History should be preserved Mercurial

Mercurial is a free, distributed source control management tool, like git

Philosophy and key points:

● Usability first, has consistent syntax and help ● Each command does one thing ● History should be preserved ● Works well on all major OSes, including Windows Mercurial

Mercurial is a free, distributed source control management tool, like git

Philosophy and key points:

● Usability first, has consistent syntax and help ● Each command does one thing ● History should be preserved ● Works well on all major OSes, including Windows ● Easy to install and configure. It just works Mercurial

Mercurial is a free, distributed source control management tool, like git

Philosophy and key points:

● Usability first, has consistent syntax and help ● Each command does one thing ● History should be preserved ● Works well on all major OSes, including Windows ● Easy to install and configure. It just works ● Extensible (but base version is often enough) Mercurial. Who uses it?

Facebook

● Why? Because git had trouble handling huge repositories ● Facebook has its own extensions for Hg

Mozilla Firefox

● 10+ million LOC Mercurial anatomy

Hg repository consists of a working directory and .hg/ directory

Working directory is a copy of the project's files at a given point in time plus uncommited edits (rev 2 is a parent of working directory) Mercurial anatomy

.hgignore lists files that are not syntax: glob revisioned. Same as .gitignore *.sln Temp/* It is tracked as any other file site.cache Mercurial anatomy

.hgtags relates revisions to given 85a9d168e7aa1cd2e... build_273 human readable tag names 16c18a4302b89afd2... build_305

It is tracked as any other file Mercurial anatomy

Commit records state of the working directory relative to its parent in a new (rev 4). That changeset will become new parent for working directory.

Rev 4 is now a branch because “line of development diverged” Mercurial anatomy

A changeset:

● is an atomic group of related changes to multiple files ● has a revision number and hash id ● has one or two parents ()

Changeset without children is called a head, latest head is called a tip Mercurial anatomy

Hg is a distribured SCM

Each team member has their own cloned repository. Sometimes more than one

No central repository is needed, but often it is convenient to have a passive central repository (eg )

https://homes.cs.washington.edu/~mernst/advice/version-control.html Tools

Hg has CLI interface (hg …)

There are plugins to integrate Hg into all major IDEs: Eclipse, Visual Studio, IntelliJ, etc

There are multiple standalone GUIs for Hg. One of them is TortoiseHg:

● hg CLI tool ● TortoiseHg Workbench ● Windows Shell extension ● TortoisePlink for SSH tunnel Tools. TortoiseHg Setup and config

Install TortoiseHg ~/.hgrc or Mercurial.ini

Edit user wide config and add [ui] username = Toomas Laasik at least who you are (~/.hgrc) hg config --edit

Each repository has its own .hg/hgrc file that has repo specific lines and can override parts of user config Setup and config

Normally access to remote ~/.hgrc or Mercurial.ini private repo prompt you for [ui] password. It may be a good username = Toomas Laasik idea to use keys instead ssh = tortoiseplink.exe -ssh -i "c:\keys\toomas.ppk"

[extensions] strip =

An actual config I use --> Workflows

Workflow is a way how you, your team and others use SCM for a project.

Some basic workflows (https://www.mercurial-scm.org/guide):

● Log keeping ● Lone developer with nonlinear history ● Separate features ● Sharing changes

Many workflows can be mixed and matched.

Each team usually has a custom workflow best suitable for them Log keeping workflow

● Use Case: Look back when you did which changes ● 1 developer, 1 local repo

Very basic, this is here just to get accustomed to syntax Log keeping workflow hg init - create repo $ mkdir uthg/ $ cd uthg/ hg add - add $ echo Hello > hello.txt a file on the next . $ hg init Without filename all files $ hg add hello.txt are added $ hg commit -m "First commit" hg commit - commit $ hg log changes to default branch changeset: 0:f4d00ef06737 user: Toomas Laasik hg log - show revision date: Tue May 29 21:47:54 2018 +0300 summary: First commit history Log keeping workflow hg status - show changes $ echo world >> hello.txt in the working directory $ echo Read this > README $ hg status Commit changes M hello.txt ? README

$ hg commit Log keeping workflow hg status - show changes $ echo world >> hello.txt in the working directory $ echo Read this > README $ hg status Commit changes M hello.txt ? README

$ hg commit Oops, forgot to add $ hg add README! --amend flag adding README lets you recommit last change $ hg commit --amend saved backup bundle to c:\work\uth... Log keeping workflow hg status - show changes $ echo world >> hello.txt in the working directory $ echo Read this > README $ hg status Commit changes M hello.txt ? README

$ hg commit Oops, forgot to add $ hg add README! --amend flag adding README lets you recommit last change $ hg commit --amend saved backup bundle to c:\work\uth... There is also hg rollback Log keeping workflow hg - see changes $ echo asdasd >> hello.txt $ hg diff hg revert - diff -r 9fc99ad93c03 hello.txt reverts uncommited --- a/hello.txt Tue May 29 23:25:44 2018 +0300 +++ b/hello.txt Wed May 30 00:55:13 2018 +0300 changes. Creates backup @@ -1,2 +1,3 @@ file with orig extension Hello (disable with -C flag) world +asdasd

$ hg revert hello.txt $ hg status ? hello.txt.orig

$ rm *.orig Log keeping workflow hg cp $ hg cp hello.txt copy_of_hello.txt hg mv - $ hg mv hello.txt renamed_hello.txt copy or move file without $ hg summary loosing revision history. parent: 1:9fc99ad93c03 tip Don’t forget to commit! Added readme, changed hello branch: default hg summary - show commit: 1 renamed, 1 copied update: (current) working directory state $ hg commit -m “copy and rename” Log keeping workflow hg log -G - show revision $ hg log -G history with graph @ changeset: 2:4ca546cbe96a | tag: tip | user: Toomas Laasik | date: Wed May 30 01:36:00 2018 +0300 | summary: copy and rename | o changeset: 1:9fc99ad93c03 | user: Toomas Laasik | date: Tue May 29 23:25:44 2018 +0300 | summary: Added readme, changed hello | o changeset: 0:f4d00ef06737 user: Toomas Laasik date: Tue May 29 21:47:54 2018 +0300 summary: First commit Lone developer with nonlinear history

● Use Case: Go back at times and work onward from there ● 1 developer, 1 local repo

Basic, but shows how automatic anonymous branching and merging works. Lone developer with nonlinear history hg update - update ### continuing from code above working directory to $ hg update 1 changeset (needs clean $ echo Hello world! > hello.txt working directory) $ hg commit -m "Put hello on one line" created new head

After commit we have two heads. Later on heads need to be merged or closed Lone developer with nonlinear history hg merge - merge working $ hg merge directory with another merging hello.txt and copy_of_hello.txt to copy_of_.. merging hello.txt and renamed_hello.txt to renamed_.. revision. 0 files updated, 2 files merged, 0 files removed, 0.. (branch merge, don't forget to commit) No conflicts. $ hg commit -m “Merge” Here no arguments are given, because there we are on one head and there is only exactly one other head. Lone developer with nonlinear history hg merge - merge working $ hg merge directory with another merging hello.txt and copy_of_hello.txt to copy_of_.. merging hello.txt and renamed_hello.txt to renamed_.. revision. 0 files updated, 0 files merged, 0 files removed, 2.. (branch merge, don't forget to commit) Merge conflicts! If hg couldn’t resolve them $ hg resolve --list automatically you need to somefile.txt do it manually, mark them (edit files listed to manually resolve conflicts or resolved and commit retry automatic resolving hg resolve somefile.txt)

Nicer to do in GUI $ hg resolve --mark somefile.txt

$ hg commit -m “Merge” Lone developer with nonlinear history hg merge - merge working $ hg merge directory with another merging hello.txt and copy_of_hello.txt to copy_of_.. merging hello.txt and renamed_hello.txt to renamed_.. revision. 0 files updated, 0 files merged, 0 files removed, 2.. (branch merge, don't forget to commit) Merge conflicts! If you can’t resolve conflicts or $ hg resolve --list just want to cancel merge, somefile.txt then update to some other (edit files listed to manually resolve conflicts or revision retry automatic resolving hg resolve somefile.txt)

$ hg update --clean Lone dev...

Merge conflict resolving in TortoiseHg

Next: repo branches as TortoiseHg shows it Lone developer with nonlinear history Separate features

● Use Case: Work on several features in parallel ● 1 developer, many repos

Each feature is kept and developed in cloned repo.

In practice you can have many variations of it:

● stable, feature1, feature2, … ● stable, testing, features

(Using named branches gives somewhat similar workflow) Separate features hg clone - ### continuing from code above makes a clone of a repo. $ cd .. Can use folders, URLs $ hg clone uthg uthg_feature1 updating to branch default 3 files updated, 0 files merged, 0 files removed, 0..

$ cd uthg_feature1 $ hg mv renamed_hello.txt hello.txt $ echo Feature_1 >> hello.txt $ hg status A hello.txt R renamed_hello.txt

$ hg commit -m "Added feature 1" Separate features Separate features hg incoming $ cd ..\uthg - show new $ hg incoming ..\uthg_feature1 comparing with ..\uthg_feature1 found in source searching for changes changeset: 5:41e754a425d5 hg pull - pull tag: tip changes from source user: Toomas Laasik date: Thu May 31 21:01:39 2018 +0300 summary: Added feature 1

$ hg pull ..\uthg_feature1 pulling from ..\uthg_feature1 ... (run 'hg update' to get a working copy) Separate features

If there where no changes $ hg update tip in main uthg we can just 1 files updated, 0 files merged, 1 files removed, 0.. update working directory to the changeset we just pulled hg update tip - update working directory to latest head (tip) Separate features workflow

If there where changes $ hg update tip in main uthg repo we have $ hg merge to merge heads instead 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit)

Could use hg heads and $ hg commit -m "Merged feature 1" other CLI commands, but a nice GUI gives much better overview Separate features workflow Sharing changes workflow

● Use Case: Share your changes, receive changes made by others ● many developers, many repos

Many ways for doing it:

● no central repo, devs connect directly ● exchange patches ● use shared passive repo Sharing changes - hg serve hg serve - starts a simple $ hg serve stand-alone webserver listening at http://192.168.1.199:8000/ (bound..

Read only (no push unless specifically allowed)

No access control Sharing changes - hg serve

Useful for connecting directly $ hg serve to another dev repo in LAN. listening at http://192.168.1.199:8000/ (bound..

Even if using remote repo ### Other developer like BitBucket, occasionally this is useful for cases when: $ hg incoming http://192.168.1.199:8000 comparing with http://192.168.1.199:8000/ ● service is down searching for changes ● quickly restoring repo no changes found

after recover from disk ### or failure $ hg clone http://192.168.1.199:8000 ### or $ hg pull http://192.168.1.199:8000 Sharing changes - patches

Sending patches is useful if $ hg log you don’t have write access ... $ hg export -r 5:7 > changes.diff to target repo ### Other developer hg export … > - dump header and diff $ hg clone uthg integration between one or more $ cd integration changesets $ hg import changes.diff

### test if there are no issues, then hg import - import changes. Alias: $ cd ../uthg $ hg pull ../integration Sharing changes - shared repo

Using shared repo is very $ hg clone https://[email protected]/tooms/uthg similar to one-local-repo-per- ... feature workflow

The only differences:

● repo is in internet ● local repos are user repos, not feature repos Sharing changes - shared repo

Setup once: $ hg clone https://[email protected]/tooms/uthg ... 1. create repo over web 2. give access to devs $ hg pull ... Then each dev: $ hg merge ... 3. clones the repo $ hg push 4. push and pull regularly ... Sharing changes - shared repo How we use Mercurial at Interactive Fate

One Unity3D project

4 people team. Only one has SW development background and writes code (me)

Repo is 3.5Gb and has 1.5 years of history in it, most is binary and yaml

About 10-20 commits/merges per work day

Shared repo hosted by xp-dev.com (was in BitBucket.org, but it had 2Gb limit)

No issue tracking integration Real world challenges - lots of binary files

Photoshop PSD files are not kept in Hg repo, but on local drive

● some PSDs are hundreds of MB ● risky business ● final PNG files are in repo

Still, checked out repo can be directly opened/imported in Unity

Mercurial has bigfiles extension, but we don’t use it. Workflow not easy enough Real world challenges - hardware failures

One team member used faulty external USB HDD

● disconnected at will, corrupting parts of repo ● we saw changesets without parents, commited files reapparing as changed,etc ● to restore the repo we cloned .hg/ manually and changed .hg/hgrc afterwards

Occasionally we didn’t have internet or BitBucket was down

● Everyone kept working on their repo ● I used hg serve on LAN to let them get my changes Real world challenges - brances and tags

2 branches:

● “default” - bleeding edge code lives here ● “indiegogo” - branch for indiegogo release, later we plan to make more release branches ● code has been merged between those both ways

Tags:

● for public builds, like “build_305” from indiegogo branch ● build number comes from Unity Cloud Build that pulls code from xp-dev.com, but we have to add the tag manually Real world challenges - file renames, mass changes

Unity creates meta file for every other file, it’s a problem if viewed from hg side

● hg mv is tedious or sometimes impossible ● solution: TortoiseHg variant of hg addremove --similarity 100

Some code changes trigger serialized asset file changes

● example: adding “idleLogMessage” to crew causes 20 crew asset changes ● problem. sometimes those asset changes are delayed ● solution: be extra careful to ensure assets get updated ● even still, sometimes small code change causes hundreds of changes for another developer who just did pull Summary

By now you should know about:

● What is Mercurial and how it works on basic level ● Know basic workflows for team and single developer ● Know about some hosting options ● Know about some real life challenges that you may face when using Hg

Questions?