Introduction to source control management with Mercurial and Gitlab#
Motivations#
Why source control management?#
Source control management (also known as simply “Git” nowadays 🙂) is an essential tool for scientists and developers!
Why Mercurial?#
Why not Git? Git is a very good tool for advanced users but it is really too complicated and unsafe for what we need as scientists / students / teachers / developers of most scientific programs.
I (Pierre Augier) think that Mercurial is more adapted for us in academics:
simpler and safer for beginners,
very powerful for advanced users (it is used for example at Facebook and Mozilla… and for the PyPy repository).
For advanced Git users, when using Mercurial, you lose the Git index (but not what you usually do with it) and you gain very interesting features, like for example long-term named branches, safe distributed history edition (phases, obsolete changesets, evolve extension) and the command hg absorb
(automatic injection of uncommitted changes into prior commits in a PR).
Why Gitlab?#
“GitLab is a web-based DevOps lifecycle tool that provides a Git-repository manager providing wiki, issue-tracking and continuous integration and deployment pipeline features, using an open-source license” (from https://en.wikipedia.org/wiki/GitLab).
Gitlab is an open-source and self-hosted alternative to Github (which is not open-source, not self-hosted and now owned by Microsoft).
Many public institutions choose Gitlab for their hosting tool, in particular our university UGA has it own Gitlab instance: https://gricad-gitlab.univ-grenoble-alpes.fr.
Level 0: command help
#
export HGRCPATH=""
hg help
Mercurial Distributed SCM
list of commands:
Repository creation:
clone make a copy of an existing repository
init create a new repository in the given directory
Remote repository management:
incoming show new changesets found in source
outgoing show changesets not found in the destination
paths show aliases for remote repositories
pull pull changes from the specified source
push push changes to the specified destination
serve start stand-alone webserver
Change creation:
commit commit the specified files or all outstanding changes
Change manipulation:
backout reverse effect of earlier changeset
graft copy changes from other branches onto the current branch
merge merge another revision into working directory
Change organization:
bookmarks create a new bookmark or list existing bookmarks
branch set or show the current branch name
branches list repository named branches
phase set or show the current phase name
tag add one or more tags for the current or given revision
tags list repository tags
File content management:
annotate show changeset information by line for each file
cat output the current or given revision of files
copy mark files as copied for the next commit
diff diff repository (or selected files)
grep search for a pattern in specified files
Change navigation:
bisect subdivision search of changesets
heads show branch heads
identify identify the working directory or specified revision
log show revision history of entire repository or files
Working directory management:
add add the specified files on the next commit
addremove add all new files, delete all missing files
files list tracked files
forget forget the specified files on the next commit
purge removes files not tracked by Mercurial
remove remove the specified files on the next commit
rename rename files; equivalent of copy + remove
resolve redo merges or set/view the merge status of files
revert restore files to their checkout state
root print the root (top) of the current working directory
shelve save and set aside changes from the working directory
status show changed files in the working directory
summary summarize working directory state
unshelve restore a shelved change to the working directory
update update working directory (or switch revisions)
Change import/export:
archive create an unversioned archive of a repository revision
bundle create a bundle file
export dump the header and diffs for one or more changesets
import import an ordered set of patches
unbundle apply one or more bundle files
Repository maintenance:
manifest output the current or given revision of the project manifest
recover roll back an interrupted transaction
verify verify the integrity of the repository
Help:
config show combined config settings from all hgrc files
help show help for a given topic or a help overview
version output version and copyright information
additional help topics:
Mercurial identifiers:
filesets Specifying File Sets
hgignore Syntax for Mercurial Ignore Files
patterns File Name Patterns
revisions Specifying Revisions
urls URL Paths
Mercurial output:
color Colorizing Outputs
dates Date Formats
diffs Diff Formats
templating Template Usage
Mercurial configuration:
config Configuration Files
environment Environment Variables
extensions Using Additional Features
flags Command-line flags
hgweb Configuring hgweb
merge-tools Merge Tools
pager Pager Support
rust Rust in Mercurial
Concepts:
bundlespec Bundle File Formats
evolution Safely rewriting history (EXPERIMENTAL)
glossary Glossary
phases Working with Phases
subrepos Subrepositories
Miscellaneous:
deprecated Deprecated Features
internals Technical implementation topics
scripting Using Mercurial from scripts and automation
(use 'hg help -v' to show built-in aliases and global options)
hg help init
hg init [-e CMD] [--remotecmd CMD] [DEST]
create a new repository in the given directory
Initialize a new repository in the given directory. If the given directory
does not exist, it will be created.
If no directory is given, the current directory is used.
It is possible to specify an "ssh://" URL as the destination. See 'hg help
urls' for more information.
Returns 0 on success.
options:
-e --ssh CMD specify ssh command to use
--remotecmd CMD specify hg command to run on the remote side
--insecure do not verify server certificate (ignoring web.cacerts
config)
(some details hidden, use --verbose to show complete help)
export HGRCPATH=$PWD/hgrc4ipynb
Level 0: one local repository#
Commands init
, status
, add
, remove
, addremove
, commit
, log
and summary
#
# cleanup
rm -rf /tmp/myrepos
Let’s create a directory and a file in it.
mkdir -p /tmp/myrepos/myrepo0
cd /tmp/myrepos/myrepo0
touch file0.txt
Let’s tell Mercurial that we want to make a new repository from this directory.
hg init
Let’s ask Mercurial what is new in this repository.
hg status
? file0.txt
# equivalent command (shorter)
hg st
? file0.txt
We want to “Schedule files to be version controlled and added to the repository.”
hg add
adding file0.txt
A new status
gives
hg st
A file0.txt
Let’s now create the first commit (or “changeset”). We can think about it as a snapshot of the code as it is now.
hg commit -m "First commit"
A new status
returns nothing because there is nothing new from the last commit.
hg st
Let’s add a new file:
touch file1.txt
hg st
? file1.txt
rm -f file0.txt
hg st
! file0.txt
? file1.txt
One new file and one file removed from the working directory. We want to take a new snapshot of the code how it is now. addremove
is very useful is that common situation.
hg addremove
# or
# hg addre
removing file0.txt
adding file1.txt
hg st
A file1.txt
R file0.txt
hg commit -m "Remove file0 and add file1"
hg st
ls
file1.txt
Let’s modify the file file1.txt
:
echo "Hello world!" >> file1.txt
hg st
M file1.txt
There is no “Git index” in Mercurial. A modification in a versioned file is automatically included in the next commit.
We can really think about the commits as “snapshots of the code” as it is in the working directory.
hg commit -m "Hello world in file1.txt"
hg st
We used a lot status
to get information about the state of the repository. Let’s discover 2 other very useful commands: sum
(or summary
) and log
.
hg sum
parent: 2:8bfba1b25e7d tip
Hello world in file1.txt
branch: default
commit: (clean)
update: (current)
phases: 3 draft
Mercurial tells us that we are in the branch default
, which is… the default “named branch”. Note that Mercurial “named branches” are used only for long term features or versions of software (for example “pypy2.7” and “pypy3.6” in Pypy repository) and not for feature branches like branches in Git. For this tutorial, we won’t use other named branches and we’ll always work in the default
branch.
hg log
changeset: 2:8bfba1b25e7d
tag: tip
user: Pierre Augier <pa@example.com>
date: Tue Sep 06 21:44:41 2022 +0200
summary: Hello world in file1.txt
changeset: 1:02ac2678cff1
user: Pierre Augier <pa@example.com>
date: Tue Sep 06 21:44:40 2022 +0200
summary: Remove file0 and add file1
changeset: 0:f7dcc9188623
user: Pierre Augier <pa@example.com>
date: Tue Sep 06 21:44:38 2022 +0200
summary: First commit
hg log --graph
@ changeset: 2:8bfba1b25e7d
| tag: tip
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:41 2022 +0200
| summary: Hello world in file1.txt
|
o changeset: 1:02ac2678cff1
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:40 2022 +0200
| summary: Remove file0 and add file1
|
o changeset: 0:f7dcc9188623
user: Pierre Augier <pa@example.com>
date: Tue Sep 06 21:44:38 2022 +0200
summary: First commit
hg log -G
@ changeset: 2:8bfba1b25e7d
| tag: tip
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:41 2022 +0200
| summary: Hello world in file1.txt
|
o changeset: 1:02ac2678cff1
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:40 2022 +0200
| summary: Remove file0 and add file1
|
o changeset: 0:f7dcc9188623
user: Pierre Augier <pa@example.com>
date: Tue Sep 06 21:44:38 2022 +0200
summary: First commit
Level 0.1: about the special files .hgignore and .gitignore#
There are files that you don’t want to include in a repository. Usually, you want to include the source but not what is produced with the source (programs, libraries, pdf files, etc.).
To avoid to have too many files listed when one call hg st
, one can add a file .hgignore
(or .gitignore
, when using hg-git).
See https://www.mercurial-scm.org/wiki/.hgignore and https://git-scm.com/docs/gitignore
Typical content of a .gitignore
file:
*.pyd*
*.pyc
*~
*tmp
\#*\#
*.slides.html
.ipynb_checkpoints
Level 1.0: command revert
#
cat file1.txt
Hello world!
echo "Something wrong" > file1.txt
Oh, here, we really did something wrong. It’s buggy. Let’s see where is our problem.
hg st
M file1.txt
The command diff
shows the differences between the working directory and the parent commit.
hg diff
diff --git a/file1.txt b/file1.txt
--- a/file1.txt
+++ b/file1.txt
@@ -1,1 +1,1 @@
-Hello world!
+Something wrong
We could also use hg meld
which opens the program meld
to present the same thing graphically.
hg revert file1.txt
# or to revert all files:
# hg revert --all
ls
file1.txt file1.txt.orig
hg st
? file1.txt.orig
rm -f file1.txt.orig
Level 1.1: command update
#
hg log -G
@ changeset: 2:8bfba1b25e7d
| tag: tip
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:41 2022 +0200
| summary: Hello world in file1.txt
|
o changeset: 1:02ac2678cff1
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:40 2022 +0200
| summary: Remove file0 and add file1
|
o changeset: 0:f7dcc9188623
user: Pierre Augier <pa@example.com>
date: Tue Sep 06 21:44:38 2022 +0200
summary: First commit
hg update 0
# `update` or just `up`
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
hg sum
parent: 0:f7dcc9188623
First commit
branch: default
commit: (clean)
update: 2 new changesets (update)
phases: 3 draft
ls
file0.txt
echo "A line in file0.txt" >> file0.txt
hg st
M file0.txt
hg commit -m "A line in file0.txt"
created new head
We were at commit 0 and we commited. It created a (unnamed) branch.
hg log -G
@ changeset: 3:d7f0bba98ea8
| tag: tip
| parent: 0:f7dcc9188623
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:46 2022 +0200
| summary: A line in file0.txt
|
| o changeset: 2:8bfba1b25e7d
| | user: Pierre Augier <pa@example.com>
| | date: Tue Sep 06 21:44:41 2022 +0200
| | summary: Hello world in file1.txt
| |
| o changeset: 1:02ac2678cff1
|/ user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:40 2022 +0200
| summary: Remove file0 and add file1
|
o changeset: 0:f7dcc9188623
user: Pierre Augier <pa@example.com>
date: Tue Sep 06 21:44:38 2022 +0200
summary: First commit
hg up 1
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
hg sum
parent: 1:02ac2678cff1
Remove file0 and add file1
branch: default
commit: (clean)
update: 2 new changesets (update)
phases: 4 draft
hg up
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
updated to "8bfba1b25e7d: Hello world in file1.txt"
1 other heads for branch "default"
hg sum
parent: 2:8bfba1b25e7d
Hello world in file1.txt
branch: default
commit: (clean)
update: 1 new changesets, 2 branch heads (merge)
phases: 4 draft
ls
file1.txt
touch file2.txt
hg st
? file2.txt
hg add
adding file2.txt
hg commit -m "Add file 2"
hg log -G
@ changeset: 4:bd539f0ab390
| tag: tip
| parent: 2:8bfba1b25e7d
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:49 2022 +0200
| summary: Add file 2
|
| o changeset: 3:d7f0bba98ea8
| | parent: 0:f7dcc9188623
| | user: Pierre Augier <pa@example.com>
| | date: Tue Sep 06 21:44:46 2022 +0200
| | summary: A line in file0.txt
| |
o | changeset: 2:8bfba1b25e7d
| | user: Pierre Augier <pa@example.com>
| | date: Tue Sep 06 21:44:41 2022 +0200
| | summary: Hello world in file1.txt
| |
o | changeset: 1:02ac2678cff1
|/ user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:40 2022 +0200
| summary: Remove file0 and add file1
|
o changeset: 0:f7dcc9188623
user: Pierre Augier <pa@example.com>
date: Tue Sep 06 21:44:38 2022 +0200
summary: First commit
We cleanup a bit to get back a linear history. Since all commits are local, they are in a draft phase and they can be obsoleted without problem.
hg prune 3
1 changesets pruned
hg log -G
@ changeset: 4:bd539f0ab390
| tag: tip
| parent: 2:8bfba1b25e7d
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:49 2022 +0200
| summary: Add file 2
|
o changeset: 2:8bfba1b25e7d
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:41 2022 +0200
| summary: Hello world in file1.txt
|
o changeset: 1:02ac2678cff1
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:40 2022 +0200
| summary: Remove file0 and add file1
|
o changeset: 0:f7dcc9188623
user: Pierre Augier <pa@example.com>
date: Tue Sep 06 21:44:38 2022 +0200
summary: First commit
Level 2: working with a remote repository (usually on the web)#
Commands clone
, push
, pull
#
The most standard way to create a local repository is to clone a remote repository available on the web. This is done with the command clone
like this:
hg clone ssh://hg@foss.heptapod.net/fluiddyn/fluidsim
Here, I used ssh, which is usually more convenient than https, but one can also use http addresses like https://github.com/hpyproject/hpy.git
. On Github, Gitlab, Heptapod, there is usually a blue button Code
or Clone
from which one can get the right address to clone a repository.
Warning: sometimes, the addresses are not exactly like the web address, for example git@github.com:hpyproject/hpy.git
.
Note: with the extension hggit
, one can work on remote Git repositories with a local Mercurial repository (more on that later).
For this tutorial, we will create a local “web” repository.
cd ..
pwd
/tmp/myrepos
hg clone myrepo0 myrepo_web
requesting all changes
adding changesets
adding manifests
adding file changes
added 4 changesets with 4 changes to 3 files
1 new obsolescence markers
new changesets f7dcc9188623:bd539f0ab390
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
Now, we have a “web” repository that we can use as if it was on the web. Let’s first clone it.
hg clone myrepo_web myrepo1
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
cd myrepo1
ls
file1.txt file2.txt
echo "Hello" > file2.txt
hg st
M file2.txt
hg commit -m "Improve file2"
hg log -G
@ changeset: 4:c3c17f042f45
| tag: tip
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:51 2022 +0200
| summary: Improve file2
|
o changeset: 3:bd539f0ab390
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:49 2022 +0200
| summary: Add file 2
|
o changeset: 2:8bfba1b25e7d
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:41 2022 +0200
| summary: Hello world in file1.txt
|
o changeset: 1:02ac2678cff1
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:40 2022 +0200
| summary: Remove file0 and add file1
|
o changeset: 0:f7dcc9188623
user: Pierre Augier <pa@example.com>
date: Tue Sep 06 21:44:38 2022 +0200
summary: First commit
hg push
pushing to /tmp/myrepos/myrepo_web
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
At this point, we have 2 repositories.
cd /tmp/myrepos
pwd
ls
/tmp/myrepos
myrepo0 myrepo1 myrepo_web
Let’s create a new repository from the repo on the web. (Usually, it is done in another computer.)
hg clone myrepo_web myrepo_other_computer
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
cd myrepo_other_computer
ls
file1.txt file2.txt
cat file2.txt
Hello
echo "Hello Word!" > file2.txt
hg st
M file2.txt
hg commit -m '"Hello Word!" is even nicer'
hg st
We push the new changeset towards the default repository (from which this repository has been created), which is the “web” repository.
hg push
pushing to /tmp/myrepos/myrepo_web
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
Let’s come back to the original repository in the first computer.
cd ../myrepo1
cat file2.txt
Hello
hg sum
parent: 4:c3c17f042f45 tip
Improve file2
branch: default
commit: (clean)
update: (current)
hg pull
pulling from /tmp/myrepos/myrepo_web
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
new changesets d416bb8bde96
(run 'hg update' to get a working copy)
hg up
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
We could have just run hg pull -u
to pull and update to the tip of the branch where we are, i.e. the last commit since the repository is now in a linear state.
hg sum
parent: 5:d416bb8bde96 tip
"Hello Word!" is even nicer
branch: default
commit: (clean)
update: (current)
cat file2.txt
Hello Word!
Level 3: nonlinear history, unnamed branches and merge
/rebase
commands#
We can now consider the case in which 2 persons (Alice and Bob) work at the same time on the same project. First they both clone the web repository.
# Alice
cd /tmp/myrepos/
hg clone myrepo_web myrepo_Alice
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
# Bob
hg clone myrepo_web myrepo_Bob
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
Just for this notebook, we can tell Mercurial who is the owner of Alice’s and Bob’s repositories.
# not useful in real life!
echo "username = Alice <alice@mail.wonderland>" >> /tmp/myrepos/myrepo_Alice/.hg/hgrc
echo "username = Bob <bob@mail.wonderland>" >> /tmp/myrepos/myrepo_Bob/.hg/hgrc
# Alice works
cd /tmp/myrepos/myrepo_Alice
touch Alice_file.py
hg add
hg commit -m "Alice adds a file"
hg push
adding Alice_file.py
pushing to /tmp/myrepos/myrepo_web
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
# Bob works
cd /tmp/myrepos/myrepo_Bob
touch Bob_file.py
hg add
hg commit -m "Bob adds a file"
adding Bob_file.py
At this point, hg push
would lead to the following error:
pushing to /tmp/myrepos/myrepo_web
searching for changes
remote has heads on branch 'default' that are not known locally: 69b3f39e70ab
abort: push creates new remote head 938fc2084593!
(pull and merge or see 'hg help push' for details about pushing new heads)
Bob encounters a problem… The remote repository has a commit which is not know locally. Let’s first pull this commit.
hg pull
pulling from /tmp/myrepos/myrepo_web
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
new changesets faaf587b5bd9
(run 'hg heads' to see heads, 'hg merge' to merge)
Now we can examine the situation.
hg heads
changeset: 7:faaf587b5bd9
tag: tip
parent: 5:d416bb8bde96
user: Alice <alice@mail.wonderland>
date: Tue Sep 06 21:44:57 2022 +0200
summary: Alice adds a file
changeset: 6:39d0c9e5a69f
user: Bob <bob@mail.wonderland>
date: Tue Sep 06 21:44:58 2022 +0200
summary: Bob adds a file
hg log -G -l 4
o changeset: 7:faaf587b5bd9
| tag: tip
| parent: 5:d416bb8bde96
| user: Alice <alice@mail.wonderland>
| date: Tue Sep 06 21:44:57 2022 +0200
| summary: Alice adds a file
|
| @ changeset: 6:39d0c9e5a69f
|/ user: Bob <bob@mail.wonderland>
| date: Tue Sep 06 21:44:58 2022 +0200
| summary: Bob adds a file
|
o changeset: 5:d416bb8bde96
| user: Pierre Augier <pa@example.com>
| date: Tue Sep 06 21:44:53 2022 +0200
| summary: "Hello Word!" is even nicer
|
o changeset: 4:c3c17f042f45
| user: Pierre Augier <pa@example.com>
~ date: Tue Sep 06 21:44:51 2022 +0200
summary: Improve file2
We have 2 “unnamed branches” (in the “named branch” default
), i.e. 2 different commits with the same parent (changeset 5).
A simple way to avoid this situation is to pull just before a commit and to make sure to commit from the last commit in the shared repository.
There are different ways to solve this problem. The nicest would be to move changeset 6 above changeset 7 (actually change the parent of changeset 6 to changeset 7). It’s very simple to do with the command hg rebase -s 6 -d 7
(-s
and -d
mean source and destination, respectively). It is nice since it leads to a linear state but it is a little bit too complicated (history rewriting).
In the error log, Mercurial tells us about the simple way to solve the situation: pull and merge. Let’s try that.
hg merge
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
hg sum
parent: 6:39d0c9e5a69f
Bob adds a file
parent: 7:faaf587b5bd9 tip
Alice adds a file
branch: default
commit: 1 modified (merge)
update: (current)
phases: 1 draft
hg st
M Alice_file.py
# The repository is in an unfinished *merge* state.
# To continue: hg commit
# To abort: hg merge --abort
ls
Alice_file.py Bob_file.py file1.txt file2.txt
hg commit -m "Merge Alice and Bob commits"
hg log -G -l 4
@ changeset: 8:ba60c7f77030
|\ tag: tip
| | parent: 6:39d0c9e5a69f
| | parent: 7:faaf587b5bd9
| | user: Bob <bob@mail.wonderland>
| | date: Tue Sep 06 21:45:00 2022 +0200
| | summary: Merge Alice and Bob commits
| |
| o changeset: 7:faaf587b5bd9
| | parent: 5:d416bb8bde96
| | user: Alice <alice@mail.wonderland>
| | date: Tue Sep 06 21:44:57 2022 +0200
| | summary: Alice adds a file
| |
o | changeset: 6:39d0c9e5a69f
|/ user: Bob <bob@mail.wonderland>
| date: Tue Sep 06 21:44:58 2022 +0200
| summary: Bob adds a file
|
o changeset: 5:d416bb8bde96
| user: Pierre Augier <pa@example.com>
~ date: Tue Sep 06 21:44:53 2022 +0200
summary: "Hello Word!" is even nicer
Note that the history is no longer linear. However, the repository is now in a good state so we should be able to push in the remote repository.
hg push
pushing to /tmp/myrepos/myrepo_web
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 1 changes to 1 files
And Alice can get Bob’s file.
# Alice works
cd /tmp/myrepos/myrepo_Alice
hg pull -u
pulling from /tmp/myrepos/myrepo_web
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 1 changes to 1 files
new changesets 39d0c9e5a69f:ba60c7f77030
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
hg sum
parent: 8:ba60c7f77030 tip
Merge Alice and Bob commits
branch: default
commit: (clean)
update: (current)
ls
Alice_file.py Bob_file.py file1.txt file2.txt
Working with Gitlab#
We are going to use the UGA instance https://gricad-gitlab.univ-grenoble-alpes.fr.
Login on the website.
From the website, create a repository
Clone it with Mercurial locally (once again, you need to activate the extension
hggit
enabled in the user Mercurial config file).Note the difference between the https and ssh addresses. To use ssh, one first has to setup a ssh key. Let’s do it! It is easy and very useful!
Create a
README.md
file and fill it with few lines of markdown code.Commit and push:
hg st
hg add
# create a commit locally on your computer
hg commit -m "Modify README.md"
# push it on the web server
hg push
Mercurial configuration files#
Simple text files… They can be edited with any text editors.
~/.hgrc
(per user)
If you don’t have this file, you can create a reasonable conf. file with hg config --edit
. See https://fluiddyn.readthedocs.io/en/latest/mercurial_heptapod.html#set-up-mercurial. This file contains in particular the list of activated Mercurial extensions.
To use Mercurial with Git repositories hosted on Github/Gitlab, one need at least (yes, nothing after the =
):
[extensions]
hggit =
my_repo/.hg/hgrc
(per repo)
This file contains in particular the path from which to pull/push by default. Something like:
[paths]
default = ssh://hg@foss.heptapod.net/fluiddyn/transonic
To work with hg-git, it is convenient to have something like:
[paths]
default = git@github.com:paugier/pythran.git
upstream = https://github.com/serge-sans-paille/pythran.git
Standard Github / Gitlab workflow#
Git branches are really like “bookmarks” that point towards a commit. In Mercurial, such things are called “bookmarks”.
To create a Git branch in your remote forked repository, one can do:
hg pull upstream
# update the code to the last commit of the `main` Git branch
hg up main
# create a new bookmark for our new Git branch
hg bookmark my-fix-or-new-feature
hg commit
# ...
hg push -B my-fix-or-new-feature
Then, one can create the Pull Request (Github) or Merge Request (Gitlab). Usually, it it done through the web interface.
Heptapod workflow (without forks)#
Mercurial feature branches are called “topics”.
To create a Merge Request in the remote repository, one can do:
hg pull
hg up default
hg topic my-fix-or-new-feature
hg commit
# ...
hg push