Mercurial

From Omnia
Revision as of 04:27, 25 November 2017 by Kenneth (talk | contribs) (→‎waiting for lock)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Mercurial

Mercurial is a free, distributed source control management tool. It efficiently handles projects of any size and offers an easy and intuitive interface

http://mercurial.selenic.com

Mercurial - Wikipedia, the free encyclopedia - http://en.wikipedia.org/wiki/Mercurial

"Mercurial is a cross-platform, distributed revision control tool for software developers. It is mainly implemented using the Python programming language, but includes a binary diff implementation written in C. It is supported on Windows, Unix-like systems including FreeBSD, OSX and Linux. Mercurial is primarily a command line program but graphical user interface extensions are available. All of Mercurial's operations are invoked as keyword options to its driver program hg, a reference to the chemical symbol of the element mercury.
Mercurial's major design goals include high performance and scalability, decentralized, fully distributed collaborative development, robust handling of both plain text and binary files, and advanced branching and merging capabilities, while remaining conceptually simple. It includes an integrated web interface.
The creator and lead developer of Mercurial is Matt Mackall. Released under the terms of the GNU General Public License (version 2 or any later version)."

hg-panel.png

.hgrc

Simple ~/.hgrc:

[ui]
username =  Kenneth Burgener <kenneth@demo.oeey.com>

~/.hgrc: (%homepath%\.hgrc in windows)

# Mercurial Config for Kenneth Burgener

[ui]
username =  Kenneth Burgener <kenneth@demo.oeey.com>
editor = vim

[extensions]
color =
purge =
transplant =
rebase =
mq =
graphlog =
pager =

[pager]
pager = LESS='FRX' less

Windows:

[ui]
#ssh = "C:\Program Files\TortoiseHg\TortoisePlink.exe" -ssh -2 -i "C:\Users\kenneth\id_rsa.ppk"
#ssh = "C:\Program Files (x86)\PuTTY\plink.exe" -ssh -2 -i "C:\Users\kenneth\id_rsa.ppk"
#ssh = C:\Users\kenneth\bin\TortoisePlink.exe -ssh -2 -i C:\Users\kenneth\bin\id_rsa.ppk
#ssh = "C:\Program Files (x86)\PuTTY\plink.exe" -ssh -2 -i C:\Users\kenneth\bin\id_rsa.ppk
ssh = c:\cygwin64\bin\ssh -i /cygdrive/c/Users/kenneth/bin/id_rsa -l jenkins
username =  Kenneth Burgener <kenneth@demo.oeey.com>

[extensions]
color =
purge =
transplant =
rebase =
mq =
graphlog =
pager =
# largefiles =

[color]
mode = ansi

[pager]
attend = annotate, cat, diff, export, glog, help, log, qdiff, status, tip
pager = C:\dev\cygwin\bin\less -FSRX
#hg16mode = yes

[http_proxy]
host =
no =
user =
passwd =

repo .hg/hgrc

[paths]
default = https://kiloforce@bitbucket.org/kiloforce/pygamephysics

Mercurial Book

Mercurial: The Definitive Guide - http://hgbook.red-bean.com/

Commands

remote repository

Clone remote repository:

hg clone ssh://kenneth@demo.oeey.com/test
hg clone http://demo.oeey.com/test  # read only access

incomming

See incoming changes from remote since last update: (aliases: in)

hg incoming

outgoing

See outgoing changes to remote since last update:

hg outgoing
hg outgoing [URL]  # see changes to specified target

pull

To see the incomming changes:

hg incomming
hg inc

Pull incomming changes from remote:

hg pull
hg pull -u  # pull and update in one command (or --update)

Example of a pull that needs a merge:

$ hg pull
pulling from /sysbackup/home/kenneth/test1
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)

branches

"There is always one named branch in existence: default. This is normally where mainline development occurs, and is equivalent to trunk in Subversion, or master in git." [1]

List branches:

hg branches

Show current branch:

hg branch

To close a branch after merge: [2]

hg up [BRANCH]
hg ci -m 'Closed branch [BRANCH]' --close-branch

To reopen a branch, simply update to the hidden branch and commit a change.

A dirty reopen, which will cause the branch name to be reused: (preferred to not use!) [3]

hg branch -f [OLDBRANCH]

"Named branches have the advantage that they make it easy to distinguish the two branches. They have the disadvantage that they are permanent. Permanent means that you cannot remove the branch name from the changesets on the branch — the name is literally baked directly into the changeset." [4]

"Bookmarks provide a way to have non-permanent branch names, see hg help bookmarks." [5]

tags

Tags - Name a particular revision using <name>. Tags should not change - ever.

hg tag - add one or more tags for the current or given revision

List tags:

hg tags

Tag current revision:

hg tag [TAG_NAME]

bookmarks

Bookmarks - pointers to certain commits that move when committing. Bookmarks are local. They can be renamed, copied and deleted.

"Bookmarks provide a way to have non-permanent branch names" [6]

List bookmarks:

hg bookmarks
hg bo  # shortest version

Set a bookmark:

hg bookmarks [NAME]

Delete bookmark:

hg bookmarks --delete [NAME]  # -d

Rename bookamrk:

hg bookmarks --rename [OLDNAME] [NEWNAME]  # -m

tags vs bookmarks

Bookmarks are local only, by default.

tag vs bookmark: [7]

  • The biggest difference is that a bookmark is automatically moved forward when you commit.

tag vs bookmark: [8]

  • A tag is like as stamp that the editor put on your manuscript to say "ok, we keep a trace of your current work, in case something happens."
  • A named branch would be a chapter. You have to choose at one point which chapter you'll have to write, and they are there to stay. Some will merge back, some will end (sorry, you died.)
  • A bookmark is, well, a bookmark. It follows you while you're reading (committing) the book. It helps you to keep tracks of "what you were reading at that time", so you can remove them, move them to a different "chapter". When you share the book (push), you usually don't share your bookmarks, unless you explicitly want to. So you usually use them on anonymous branches because their life cycle is shorter than named branches.

---

Remote bookmarks: [9]

  • bookmarks on a server will automatically be updated
  • a local only bookmarks can be pushed to the server with 'hg push -B [bookmark]'
  • once a bookmark exists on both the server and client, then it will auto push too

See what server bookmarks are missing locally:

hg incoming -B

See what local bookmarks are missing from server:

hg outgoing -B

To pull a bookmark from the server:

hg pull -B [BOOKMARK]

To push a bookmark to the server:

hg push -B [BOOKMARK]

To delete a remote bookmark:

hg -d [BOOKMARK]
hg push -B [BOOKMARK]

There are actually five concepts to play with: [stackoverflow.com/questions/5385813/whats-the-difference-between-hg-tag-and-hg-bookmark]

  • tags
  • local tags
  • bookmarks
  • lightweight branches
  • named branches

heads

Show heads:

hg heads
hg heads [branch]  # show only heads for specified branch

Close out spurious head: (Mercurial: beheading a head)

hg update [head_revision]
hg commit -m 'closing spurious heads' --close-branch
hg push

Show closed heads:

hg heads --closed

update

Update to branch: (aliases: up, checkout, co)

hg update          # update to latest on current branch
hg update default  # default branch
hg update 0.2.15   # 0.2.15 branch
hg update null     # remove all working files, but keep repo intact (good for servers)

Update to init commit:

hg update null
hg update 000000000000
hg update 00

cwd

Update change working directory and report tip version:

hg --cwd esx tip

logs

Show change log:

hg log
hg log -v           # include changed files
hg log -l 1         # limit to last entry
hg log -r [REV] -v  # show revision details
hg log -r [REV]:[REV] -v  # show revision details with the revision range
hg log -b [BRANCH]  # show logs for target branch

hg log --rev "ancestors(.)"
hg log --rev "reverse(ancestors(.))"  # Output in the same order as vanilla hg log

hg log -f/--follow  # show only current branch related logs

Show current working reivison summary log:

hg summary

Show changes between two branches: [10]

hg log -r "branch('foo') - branch('default')"

diff

Show code changes from working directory to parent revision:

hg diff

Show code changes between two branches: [11]

hg diff -r "ancestor(default, foo)" -r foo

Show changes since previous revision (numerically, possibly not on same branch, sadness). If you use a negative number as a revision it means “X revisions back from the tip revision of the repository”. -1 means the tip itself, -2 means the tip’s parent, and so on.

hg diff -r -2

The -1 says previous changeset on this branch. the '.' means the current changeset. You can use -2, -3 etc, but once you hit a merge point, it gets a little more interesting:

hg diff -r -1:. filename

Others:

hg diff -r -3 -r -2 file

status

Show changes in working folder: (aliases: st)

hg status

Show only modified, added or removed (not untracked or deleted files):

hg status -mar

add

Add file to be tracked:

hg add [file]

If you need to unadd (unwatch) a file, use 'revert' or 'forget'.

forget

If you need to unadd (unwatch) a file:

hg forget [file]

commit

Commit: (aliases: ci)

hg commit -m 'message'

id

Show current changeset hash and revision: (+ indicates changes from checkout)

hg id     # hash and branch
hg id -n  # revision

tip

WARNING: TIP IS USELESS!!!

tip - "show the tip revision"

"The tip revision (usually just called the tip) is the changeset most recently added to the repository (and therefore the most recently changed head)."

What this means - it show the tip of of the repository, not the current branch!

push

Push changes:

hg push               # if 'abort: repository is unrelated' something has changed on remote, do pull first.
hg push --new-branch  # if pushing a new branch
hg push -f            # if having to force a new head after a branch

Example of a failed push due to missing changes

pushing to /home/kenneth/test1
searching for changes
abort: push creates new remote head a5febe590809!
(you should pull and merge or use push -f to force)

WARNING: Don't ever force a push. This causes spurious/superfluous heads! Merge first, silly.

paths

paths - "show aliases for remote repositories"

$ hg paths
default = /sysbackup/home/kenneth/test1
$ hg paths default
/sysbackup/home/kenneth/test1

close a branch

Close a branch: [12]

hg up -C badbranch
hg commit --close-branch -m 'close badbranch, this approach never worked'
hg up -C default      # switch back to "good" branch
hg push  # push to remote repo if needed

NOTE: This does not delete the branch, just makes it inactive. To see deactivated branches:

hg branches --closed

bare repo

Create a bare remote repository (with only .hg folder):

mkdir test
hg init test
hg clone test ssh://kburgener@hg/~kburgener/test
# ignore 'no changes found' message

If you have updated the server repo, you can clean it back out (to bare repo) with:

hg update null     # remove all working files, but keep repo intact (good for servers)
hg update 000000000000
hg update 00

clean up and revert

Delete all untracked files: [13]

hg clean
hg st -un0 | xargs -0 rm     # without purge extension installed

Revert files to last update: (creates .orig files, kill with 'hg clean')

hg revert [file]
hg revert .                  # all files
hg revert --all
hg revert --all --no-backup  # do not create .orig files
hg revert . -r -2            # revert all files in current directory to last committed revision, but leave working revision alone.

Complete revert and cleanup: (this won't remove files from the .hgignore)

hg revert .
hg clean

archive

Archive - create an unversioned archive of a repository revision: (aka export dump in other CVS)

hg archive [outpath]

merge

Merge branch code into default:

hg update default
hg merge [BRANCH]

To close a branch after merge: [14]

hg up [BRANCH]
hg ci -m 'Closed branch [BRANCH]' --close-branch

Example of merge failure due to uncommitted local changes:

$ hg merge
abort: outstanding uncommitted changes
(use 'hg status' to list changes)

Manual Merge:

# method 1: first merge, then revert the file back to the state you want it at:
hg merge esx_paramiko
hg revert esx.py -r default
vimdiff esx.py esx.py.orig
hg commit -m 'merged my way'
# method 2: ?

To abort a merge:

hg update -C .

blame

Alias for #annotate

summary

Show current working reivison summary log:

hg summary

See also #logs

annotate

Show user who made last change, line by line:

hg annotate * -u

transplant

Updated .hgrc:

[extentions]
transplant =

Push a change from a revision to the current working directory:

hg log -l 1  # get revision from the last submission
hg update [BRANCH]  # update to branch wanting transplant
hg transplant [REV]  # transplant revision from other branch to here, including commit
hg push  # push changes back to main

rebase

rebase - "move changeset (and descendants) to a different branch"

Note: "You should not rebase changesets that have already been shared with others."

Merge vs Rebase: [15]

  • "Merging brings two lines of development together while preserving the ancestry of each commit history."
  • "Rebasing unifies the lines of development by re-writing changes from the source branch so that they appear as children of the destination branch – effectively pretending that those commits were written on top of the destination branch all along"
  • "So merging keeps the separate lines of development explicitly, while rebasing always ends up with a single linear path of development for both branches. But this rebase requires the commits on the source branch to be re-written, which changes their content and their SHAs."

"When contributing to a project, sometimes there is the need to keep some patches private, while keeping the whole repository up-to-date. In those cases it can be useful to "detach" the local changes, synchronize the repository with the mainstream and then append the private changes on top of the new remote changes. This operation is called rebase." [16]

Updated .hgrc:

[extentions]
rebase =

Problem: "Every other commit reads some variant of, “Merged with stable,” “merged with base,” or some such. These commits convey no useful information, yet completely clutter your commit history. How do you make your history more useful?" [17]

Solution: "The answer lies in rebasing. Rebasing is a technique made popular by git where you rewrite your not-yet-pushed patches so that they apply against the current remote tip, rather than against the tip of the repository you happened to last pull. The benefit is that your merge history shows useful merges—merges between major branches—rather than simply every single merge you did with the upstream repository." [18]

Example: [19]

hg push  # error about new heads
hg pull
hg rebase
hg push

Or simplify with

hg pull --rebase

References:

graphlog

Updated .hgrc:

[extentions]
graphlog =
hg glog | less

Example:

@
|
| o
| |
o |
|/

strip

Strip commits from history - destroy!

hg out
hg strip [REV]  # repeat for each revision

Requires 'mq' extention

rollback

Able to rollback the last commit (only do this if it hasn't been shared!)

hg rollback

backout

backout - reverse effect of earlier changeset

"Mercurial can backout an old changeset from the past for you. It looks at the changeset, figures out the opposite, and does that to your current working directory. " [20]

hg backout -r [REV] --merge

verify

"Repository Maintenance - The Mercurial repository format ("reflog") is designed to be reliable and efficient. Unlike the git storage format, it does not require ongoing maintenance (such as garbage collection). Since file systems and hard drives are fallible, it is possible that an error could corrupt a repository. To verify the integrity of the repository, run:

$ hg verify

This will perform an extensive series of tests, and report the results." [21]

Show Current Changeset

Checked out changeset revision hash:

# hg id
44459a99be45 tip

# hg id -i
44459a99be45

# hg log -l1|grep changeset|cut -d: -f3    # show last in log
44459a99be45

# hg log -l 1 --template '{node|short}\n'  # show last in log
44459a99be45

# hg parents
changeset:   0:44459a99be45
...

# hg summary
parent: 0:44459a99be45 tip
...

# hg --debug id -i
44459a99be4594fb78ff19b41fa835d70307d255

# hg parent --template '{node}\n'
44459a99be4594fb78ff19b41fa835d70307d255

# hexdump -n 20 -e '1/1 "%02x"' .hg/dirstate
44459a99be4594fb78ff19b41fa835d70307d255

NOTE: if you get a has with a "+" (44459a99be45+) it is because the working directory has changed from the checked out version.

References:

Binary Data

Options:

  1. store locally, cluttering up .hg - bad!
  2. store remotely
    1. subrepo (like svn) [22]
    2. #largefiles Extension [23] (This extension is distributed with Mercurial 2.0 and later.)
    3. bigfile extension

"Handling Large Files - Some projects (games are an excellent example) feature large binary resources, which do not lend themselves well to management under a VCS. Examples include images, movies, sound files, level data, and so on. You don't want to keep multiple versions of these files around if you can help it, and performance can suffer for files over about 10MB. The bigfile extension aims to solve this problem by storing large binary files (Binary Large Objects, or BLOBs) in a separate location, while still allowing you to manage the files using Mercurial." [24]

"SVN doesn't handle binary files much differently, the difference is that with Mercurial you have the whole repository on every system. A diff of a binary file is often the size of the file itself, so clone/push/pull operations can take a long time if there have been many changes to binary files. Solutions might be the bfiles or bigfiles extensions or use a SVN subrepo for any binary files. A minor inconvienence for the many advantages that Mercurial gives for working with code or text." [25]

hg serve

Start server:

hg serve    # port 8000
hg serve -p 8080    # port 8080
hg serve -p 8080 -d    # daemon mode

Default port is 8000

"abort: cannot start server at ':8000': Address already in use"

SSL required for commits:

$ hg push
pushing to http://demo.oeey.com:8080/
searching for changes
remote: ssl required

Allow anyone to update: (requires a restart of the server)

# .hg/hgrc
[web]
push_ssl=False
allow_push=*

References:

hgweb

hgweb.cgi -


"Note that starting with version 1.6 of Mercurial, the hgwebdir.cgi script no longer exists, and its functionality has been merged into the hgweb.cgi script which in most cases can be used with the same configuration." [26]


To setup hgweb to publish a single repository or multiple repositories, perform the following steps:

  1. Find the necessary script in the root of your Mercurial source tree.
  2. Copy it to a directory where your Web server can access it. This will be illustrated below using /home/user/webdir as this directory.
  3. Edit its contents. In particular, you will need to edit it so that it is reading the correct config file.
  4. Make sure the Web server (such as Apache) is configured and can execute the script.


The hgweb script is provided in more than one form:

  • hgweb.cgi is a script for deployment using CGI and is provided in the top-level directory of the source distribution of Mercurial.
  • hgweb.wsgi is a script for deployment using WSGI and is provided in the contrib directory in the distribution.

Much better performance can be achieved by using WSGI instead of CGI.


Download latest: http://www.selenic.com/repo/hg-stable/raw-file/tip/hgweb.cgi (pretty minimal script)

Warning: symlinks can cause issues, as hgweb will take the first alphabetical entry found as the official path!


---

/www/hg/hgweb.cgi:

config = "/opt/hg/hgweb.config"

Apache VirtalHost config:

<VirtualHost *:80>
    ServerName hg.demo.oeey.com

    #DirectoryIndex hgweb.cgi

    RewriteEngine On
    RewriteRule ^(.*)$ /hgweb.cgi/$1 [L,QSA]

    DocumentRoot /www/hg

    <Location />
        AddHandler cgi-script .cgi
        Options +ExecCGI

        AuthType Basic
        AuthName "HG Repository"
        AuthUserFile /etc/svn-passwd
        Require valid-user
    </Location>

    ServerAdmin admin@hg.demo.oeey.com
    ErrorLog logs/hg.demo.oeey.com-error_log
    CustomLog logs/hg.demo.oeey.com-access_log common
</VirtualHost>

/opt/hg/hgweb.config:

[web]
motd = <p><small>Hello World</small></p>
#baseurl = /    # for url rewrite

[paths]
/ = /opt/hg/*

/opt/hg/ken/.hg/hgrc:

[web]
description = Ken's Repo
contact = Kenneth Burgener <kenneth@demo.oeey.com>
#push_ssl = false
#allow_push = *
#hidden = false

References:

Extentions

Pager

.hgrc:

[extensions]
pager =

[pager]
pager = LESS='FRX' less

or instead of [pager] section use:

export PAGER='less -FRX'

PagerExtension - Mercurial - http://mercurial.selenic.com/wiki/PagerExtension

WARNING: for some reason this extension didn't work on the 'yum install mercurial' version on CentOS 5...

---

For Windows: [28]

[extensions]
color =
pager =

[color]
mode = ansi

[pager]
attend = annotate, cat, diff, export, glog, help, log, qdiff, status, tip
pager = C:\dev\cygwin\bin\less -FSRX

Mercurial Queues

[extensions]
mq =

MqExtension - Mercurial Queues Extension - Mercurial - http://mercurial.selenic.com/wiki/MqExtension

largefiles

"The largefiles extension allows for tracking large, incompressible binary files in Mercurial without requiring excessive bandwidth for clones and pulls. Files added as largefiles are not tracked directly by Mercurial; rather, their revisions are identified by a checksum, and Mercurial tracks these checksums. This way, when you clone a repository or pull in changesets, only the largefiles needed to update to the current version are downloaded. This saves both disk space and bandwidth." [29]

.hgrc:

[extensions]
largefiles =

Usage:

dd if=/dev/urandom of=thisfileislarge count=2000
hg add --large thisfileislarge
hg commit -m 'add thisfileislarge, which is large, as a largefile'

References:

convert

"The Convert extension converts repositories from other SCMs (or even Mercurial itself) into Mercurial repositories, with options for filtering and renaming. It can also be used to filter Mercurial repositories to get subsets of an existing one. "

ConvertExtension - Mercurial - http://mercurial.selenic.com/wiki/ConvertExtension

-- convert from git to hg --

Really easy!

hg convert [git_repo] [hg_repo]

-- Split a subdirectory into a separate project --

Split a subdirectory into a separate project - http://mercurial.selenic.com/wiki/TipsAndTricks#Split_a_subdirectory_into_a_separate_project

  • Use ConvertExtension with --filemap option.

Filter single folder (and move to top while we are at it):

hg convert --filemap filter.txt sandbox kentank

filter.txt:

include "ken_tank"
rename "ken_tank" "."

Enabling clean extension

Add the Mercurial Extension called purge. It is distributed by Mercurial.

This extension adds a “purge” command to “hg” that removes files not known to Mercurial. i.e. untracked Files. So your command would be,

hg purge
hg clean  # either works

It is not enabled by default, maybe to avoid accidentally removing files that you forgot to add.

To install this extension, add this to your mercurial settings file (.hgrc on Unix, Mercurial.ini on Windows)

~/.hgrc:

[extensions]
purge =

Source: How do I delete all untracked files from my working directory in Mercurial? - Stack Overflow - http://stackoverflow.com/questions/1212370/how-do-i-delete-all-untracked-files-from-my-working-directory-in-mercurial

Tutorials

Hg Init: a Mercurial tutorial by Joel Spolsky - http://hginit.com/

"Mercurial is a modern, open source, distributed version control system, and a compelling upgrade from older systems like Subversion. In this user-friendly, six-part tutorial, Joel Spolsky teaches you the key concepts."

hg-panel.png

Subrepository

Subrepository - Mercurial - http://mercurial.selenic.com/wiki/Subrepository

WARNING: Requires Mercurial version 1.3 or higher for support!

Create subrepo:

echo conf = ssh://kenneth@demo.oeey.com/mysub > .hgsub
hg add .hgsub
hg clone ssh://kenneth@demo.oeey.com/mysub mysub

List subrepos:

cat .hgsub

Note: when you update the top repo, it will update all subrepos to match the top repo. If the sub repo needs further updating, it will need to be updated individually:

cd conf
hg pull
hg update

See changes in subrepo: [30]

hg status -S

How to find out what changeset of main repository contains specified changeset of subrepository: [31]

hg grep hash_you_are_looking_for_blablabla .hgsubstate

hgignore

Note: .hgignore lives in the root directory of a repo.

.hgignore:

.*\.pyc$

Sample: .hgignore:

# use glob syntax.
syntax: glob
*.pyc
*~

# switch to regexp syntax.
syntax: regexp
^\.pc/

Note: The default syntax is regexp.

---

Ignore files with not extension: [32]

syntax: regexp
^[^.]+$

ERROR: Does not work, as this will include directories too!

"Because Mercurial matches files and directories top-down while traversing your working copy, and because it doesn't distinguish between files and directories when matching against the patterns in the .hgignore file, you cannot include a directory while ignoring files with the same name."

hgignore whitelist

Ignore all files, except for those in root, and specified folders:

syntax: regexp
^(?!(scripts|foo|bar)/)[^/]+/

This one does work.

mercurial - How can I ignore all directories except one using .hgignore? - Stack Overflow - http://stackoverflow.com/questions/3637496/how-can-i-ignore-all-directories-except-one-using-hgignore

-

Ignore everything, and then manually add what you want:

.*

-

Ignore Extensions - Don't bother. It is broken!

"There is no straightforward way to ignore all but a set of files. Attempting to use an inverted regex match will fail when combined with other patterns. This is an intentional limitation, as alternate formats were all considered far too likely to confuse users to be worth the additional flexibility." [33]

Uses "negative look ahead"

- Whitelist only .py and .txt files: [34] [35] [36]

syntax: regexp
^(?!.*(py|txt)).*$
^some/folder/(?!.*(py|txt)).*$

Note: the above only works for the top level (or specified) directory. Sub directories cause negative failures. See: [37] [38]

References:

Git

Mercurial vs Git

Articles:

See Git vs Mercurial

Mercurial for Git users

Mercurial for Git users - http://mercurial.selenic.com/wiki/GitConcepts

Mercurial and Git differ only in nomenclature and interface. Git tends to expose more concepts to the user, but gives hints to the user what command might make sense next.

One of the first Git lessons is the repository basic object types: blob, tree and commit. These are the building blocks for the history model. Mercurial also builds up history upon the same three concepts, respectively: file, manifest and changeset.

Command equivalence table - http://mercurial.selenic.com/wiki/GitConcepts#Command_equivalence_table

Git vs Mercurial - WikiVS - http://www.wikivs.com/wiki/Git_vs_Mercurial

Hg-Git Mercurial Plugin

Hg-Git Mercurial Plugin - http://hg-git.github.io/

"This is the Hg-Git plugin for Mercurial, adding the ability to push to and pull from a Git server repository from Mercurial. This means you can collaborate on Git based projects from Mercurial, or use a Git server as a collaboration point for a team with developers using both Git and Mercurial."

Installation:

pip install hg-git

Add to .hgrc:

[extensions]
hgext.bookmarks =
hggit =

Usage: (read only)

hg clone git://github.com/schacon/munger.git

Example read/write:

# Github shows "git@github.com:oeey/test.git"
hg clone git+ssh://git@github.com/oeey/test.git
touch test.txt
hg add test.txt
hg commit -m 'test'
hg push

WARNING: it does not appear to handle HTTPS format, so use "git+ssh":

# hg clone https://github.com/oeey/test.git
# ... does not appear to be an hg repository:

Convert Git to Mercurial

Really easy!

hg convert [git_repo] [hg_repo]

Convert Mercurial to Git

cd ~
git clone git://repo.or.cz/fast-export.git
git init git_repo
cd git_repo
~/fast-export/hg-fast-export.sh -r /path/to/old/mercurial_repo
git checkout HEAD

Source: Convert Mercurial project to Git - Stack Overflow - http://stackoverflow.com/questions/16037787/convert-mercurial-project-to-git

Installation

RPMForge Installation

Install RPMForge repo, then:

yum install mercurial

APT

apt-get install mercurial

Manual Installation

Quick install:

#MVER=2.9.1
MVER=3.0
mkdir -p ~/.src ; cd ~/.src
wget http://mercurial.selenic.com/release/mercurial-$MVER.tar.gz
tar -zvxf mercurial-$MVER.tar.gz
cd mercurial-$MVER
sudo python setup.py install

Fix path, if needed:

MPATH=$( dirname `which python` )
sed -i 's#\#!/usr/bin/python#\#!/usr/bin/env python#' $MPATH/hg

---

Dependencies: msgfmt in gettext

yum -y install gcc make python python-devel gettext
# for python compiled:
yum -y install gettext

Optional Dependency: docutils (for python) (fast) - is this even needed any more???

mkdir ~/.src ; cd ~/.src
#DVER=0.7
DVER=0.10
wget http://prdownloads.sourceforge.net/docutils/docutils-$DVER.tar.gz?download
tar -zvxf docutils-$DVER.tar.gz
cd docutils-$DVER
sudo python setup.py install
# installed to /opt/python26/bin/
#    /opt/python26/lib/python2.6/site-packages/docutils-0.7-py2.6.egg-info

See http://mercurial.selenic.com/release/ for release files.

Mercurial Extract:

#MVER=1.4.2
#MVER=1.8.3
#MVER=2.0
#MVER=2.2.2
#MVER=2.2.3
#MVER=2.6.2
#MVER=2.7.2
MVER=2.9.1
mkdir -p ~/.src ; cd ~/.src
wget http://mercurial.selenic.com/release/mercurial-$MVER.tar.gz
tar -zvxf mercurial-$MVER.tar.gz
cd mercurial-$MVER

Now to build and install...

#PYTHON=/opt/python26/bin/python
#$PYTHON setup.py clean    # not required
#$PYTHON setup.py build    # not required
#sudo $PYTHON setup.py install
sudo python setup.py install

Fix hg script to use environment:

MPATH=$( dirname `which python` )
sed -i 's#\#!/usr/bin/python#\#!/usr/bin/env python#' $MPATH/hg

Installs to:

/opt/python26/bin/hg
/opt/python26/lib/python2.6/site-packages/mercurial-2.2.3-py2.6.egg-info
/opt/python26/lib/python2.6/site-packages/mercurial/*
/opt/python26/lib/python2.6/site-packages/hgext/*  # commingled with other files!

If /opt/python26/bin/ not in path:

sudo ln -sfn /usr/local/bin/hg /opt/python26/bin/hg

--

Prefix option: -- why would you do this??

/opt/python/bin/python setup.py build
sudo /opt/python/bin/python setup.py install --prefix /opt/mercurial

Installs to:

/opt/mercurial/lib/python2.6/site-packages/mercurial/
/opt/mercurial/bin/

---

Build install system wide: (successful with dependency)

make clean && make all && su -c "make install" && hg version

---

Build and install with PREFIX target:

sudo mkdir -p /opt/mercurial
sudo chown kenneth /opt/mercurial
make clean && make install PREFIX=/opt/mercurial
# add to path:
ln -s /opt/mercurial/bin/hg /usr/local/bin/hg
# test
hg version
which hg

NOTE: not sure why 'make all' isn't included, but it works

NOTE: tried 'sudo make install' and this failed due to not finding docutils

Add library to Python path (if needed)

export PYTHONPATH=$PYTHONPATH:/opt/mercurial/lib/python2.6/site-packages
echo "export PYTHONPATH=\$PYTHONPATH:/opt/mercurial/lib/python2.6/site-packages" >> ~/.bash_profile

---

Local install (this dir)

make local && ./hg version

Other targets:

make clean    # clean build
make build    # don't build doc
make install-bin    # don't install doc
    # change install path

Quick Start

Clone a project and push changes

$ hg clone http://selenic.com/repo/hello
$ cd hello
$ (edit files)
$ hg add (new files)
$ hg commit -m 'My changes'
$ hg push

Create a project and commit

$ hg init (project-directory)
$ cd (project-directory)
$ (add some files)
$ hg add
$ hg commit -m 'Initial commit'

Password

NOTE: For SSH access, just use SSH keys.

The following is to remember https passwords.

[auth]
bb.prefix = https://bitbucket.org/foo/
bb.username = foo
bb.password = foo_passwd

Note: The ‘bb’ part is an arbitrary identifier and is used to match prefix with username and password.

Note: for bb.prefix, just use simple url, not the full one with user name! (eg. bb.prefix = https://bitbucket.org)

References:

SSH Windows Access

Connect at least one time to save the key:

"C:\Program Files (x86)\PuTTY\plink.exe" -ssh -i "C:\Users\kenneth\private.key" kburgener@hg

mercurial.ini

[ui]
ssh="C:\Program Files (x86)\PuTTY\plink.exe" -ssh -i "C:\Users\kenneth\private.key"

Another version using TortoisePlink:

[ui]
ssh = C:\Users\kenneth\TortoisePlink.exe -ssh -2 -i C:\Users\kenneth\kmg_id_rsa.ppk

Using Cygwin ssh:

[ui]
ssh = c:\cygwin64\bin\ssh -i /cygdrive/c/Users/kenneth/bin/kmg_id_rsa -l jenkins

Clone:

hg clone ssh://kburgener@hg//srv/hg/QA/automation

References:

Issues

requirement dotencode not supported

If an older Mercurial version tries to access a repository that was created by a newer Mercurial version, an error message like

abort: requirement 'dotencode' not supported!

may be displayed, which means the Mercurial version used to access that repository doesn't know how to interpret it, because accessing it would require knowledge about the 'dotencode' capability.

If such an error message appears, a newer Mercurial version must be used to access the repository or the repository must be converted to an older format understood by that version (by using 'hg clone --pull').

The format configuration option may be used to instruct Mercurial to create older repository formats. For example, to convert a 'dotencode' repository into the previous format, the command

hg --config format.dotencode=0 clone --pull repoA repoB

can be used, which of course requires a Mercurial version that supports the 'dotencode' capability.

Source:

abort: repository is unrelated

Error:

# hg pull
...
abort: repository is unrelated

Cause:

  • somehow the local repository does not match the remote

Solution:

  • recheck out repository

abort: push creates new remote head

Error:

# hg push
...
abort: push creates new remote head 0c4f58c283a7!
(you should pull and merge or use push -f to force)

Cause:

  • There was a change made to the remote repo that has not been pulled yet.

Solution #1: merge with your commit

hg pull
hg heads  # to see new head (fyi)
hg merge
hg commit -m 'some message'
hg push

Solution #2: rollback last commit, update and recommit

# do not pull first, or you can't roll back
hg rollback  # only can roll back immediate last working command
hg pull
hg update
hg commit -m 'some message'
hg push

Solution #3: rebase *favorite* [39]

# hg push
hg pull
hg rebase
hg push

Solution #4: abandon all hope, revert all commits [40]

hg outgoing
hg strip [REV]  # repeat for each outgoing revision
hg pull --update

# tricky method:
hg strip 'roots(outgoing())'

certificate with fingerprint not verified

Error:

$ hg pull
warning: hg.demo.oeey.com certificate with fingerprint 3f:2e:bf:3c:84:f6:78:f5:f3:e2:25:9c:27:8f:c1:f6:17:e3:61:92 not verified (check hostfingerprints or web.cacerts config setting)

Solution: Use the [hostfingerprints] in your .hg/hgrc file.

[hostfingerprints]
demo.oeey.com = 38:76:52:7c:87:26:9a:8f:4a:f8:d3:de:08:45:3b:ea:d6:4b:ee:cc

References:

waiting for lock

Error:

waiting for lock on repository C:\dev\PyDev\workspace\pygamephysics held by 'alienware:5072'

Solution:

  • Delete the repository file: .hg/store/lock
  • hg recover should be run after a broken locking situation.

Mercurial stuck "waiting for lock" - Stack Overflow - http://stackoverflow.com/questions/12865/mercurial-stuck-waiting-for-lock

Not trusting file

Issue:

Not trusting file /dev/.hg/hgrc from untrusted user root, group dev
Not trusting file .hg/hgrc from untrusted user root, group dev
[trusted]
users = root
groups = dev

mercurial - Not trusting file .hg/hgrc from untrusted user root, group dev - Stack Overflow [41]

keywords