Charles Forsyth <
charles...@gmail.com> writes:
>> What? You mean to tell me I have to learn a new DVCS? What am I
>> supposed to do with all the code I've developed under Mercurial? Has
>> the "official" source for the OS migrated to git, or is this just a git
>> "mirror" of the current Mercurial repo?
>
> I agree with the sentiment (and your and others' comments after
> that). As others supposed, it was only because bitbucket discarded
> support for hg that I migrated it to git, and then tried to set up a
> mirror on github, which rightly or wrongly is where people now look
> first.
So, I just finished reading all those tutorials and user's guides on Git
in a vulgar attempt to learn to live with this DVCS from hell. At
first, what I was reading about git began to make sense, and found this
quite encouraging. But, the more I read about git, the more confused I
became, as I began to realize that there's no rhyme, reason, symmetry,
or sense to the way git is used. The underlying database (with its four
object types and SHA-1 sums) is clever, but there is NO identifiable
model or theory of interaction for the user interface. Every command
seems to use some "magic" combination of options and parameters, with no
discernable pattern or logic. In this sense, Git is very much like a
natural language, such as English, with all sorts of irregular verbs and
noun forms (one "goose" "was" "good", but two "geese" "were" "better"?).
Fortunately, like English, Git can be learned by repeated, repeated,
repeated, repeated, repeated exposure. If you read ENOUGH about it, the
irregular patterns begin to "sink in"---even if they don't make any
sense. So, it is in this bizarre "Git as a second language" hinterland
that I currently find myself. :) :( :/
Converting Mercurial to Git
===========================
For converting Mercurial "changesets" to Git "commits", there appear to
be two main tools: "hg-fast-export" and Mercurial's "hg-git" plugin.
hg-fast-export
--------------
"hg-fast-export" can be found at
https://github.com/frej/fast-export.git
It's a shell script wrapper around a Python script which, in turn,
parses Mercurial repositories and generates a bytestream suitable as
input to Git's "fast-import" (sub)command, which adds a series of
commits to a (initially empty) Git repository. In this way, an entire
Mercurial repository can be converted into a Git repository. (Details
can be found in the file named README.md.) Git's "fast-import"
mechanism is explained very well in the book "Pro Git," avalailable at:
https://github.com/progit/progit2/releases/download/2.1.337/progit.pdf
Hg-Git
------
The other tool is Hg-Git, as...
Unfortunately, that Web site is broken (just a blank page). Attempting
to guess the repo and clone it:
hg clone
https://foss.heptapod.net/mercurial/hg-git
just returns an error stating that the site only supports the latest
version of some protocol. Fortunately, Hg-Git can be obtained from a
mirror on (of all places) github!
git clone
https://github.com/schacon/hg-git
Hg-Git is a Mercurial extension which lets Mercurial push/pull hg
changesets to/from a Git repository. Hg-Git is implemented entirely in
Python, but has a dependency upon the Dulwich library, which "...is a
Python implementation of the file formats and protocols used by the Git
version control system." In order to use a repository with more than
one branch, however, Hg-Git appears to require a Mercurial "bookmark"
corresponding to each Git "branch". According to the README.md:
> Hg-Git pushes your bookmarks up to the Git server as branches and will
> pull Git branches down and set them up as bookmarks.
If the README.md doesn't provide enough ambiguous detail, additional
ambiguous detail can be found in the file DESIGN.txt.
<breath depth="deep"/>
Fitting the Pieces Together
===========================
So, all of this leaves me with a good general understanding of how
Mercurial, Git, hg-fast-export, and Hg-Git work, but with no idea how to
fit all the pieces together to solve my particular problem: I have a
bunch of commits in the Mercurial version of the Inferno repository
which I want to transplant to the new, Git version of the repository.
Maybe Using hg-fast-export?
---------------------------
hg-fast-export.sh lists the following command-line options:
Options:
--quiet Passed to git-fast-import(1)
-r <repo> Mercurial repository to import
--force Ignore validation errors when converting, and pass --force
to git-fast-import(1)
-m <max> Maximum revision to import
-s Enable parsing Signed-off-by lines
--hgtags Enable exporting .hgtags files
-A <file> Read author map from file
(Same as in git-svnimport(1) and git-cvsimport(1))
-B <file> Read branch map from file
-T <file> Read tags map from file
-M <name> Set the default branch name (defaults to 'master')
-n Do not perform built-in (broken in many cases) sanitizing
of branch/tag names.
-o <name> Use <name> as branch namespace to track upstream (eg 'origin')
--hg-hash Annotate commits with the hg hash as git notes in the
hg namespace.
-e <encoding> Assume commit and author strings retrieved from
Mercurial are encoded in <encoding>
--fe <filename_encoding> Assume filenames from Mercurial are encoded
in <filename_encoding>
--mappings-are-raw Assume mappings are raw <key>=<value> lines
--filter-contents <cmd> Pipe contents of each exported file through <cmd>
with <file-path> <hg-hash> <is-binary> as arguments
--plugin <plugin=init> Add a plugin with the given init string (repeatable)
--plugin-path <plugin-path> Add an additional plugin lookup path
This appears great if I want to convert an ENTIRE repository from
Mercurial to Git, but it doesn't appear to offer any way to specify
specific changesets or branches (sequences of changesets) to export, nor
any way to specify the parent commit(s) in the Git repo onto which the
new branches should be grafted.
Maybe Using Hg-Git?
-------------------
At first glance, Hg-Git appears more promising. But it's complicated by
the fact that Mercurial supports anonymous branches (or "dangling
heads"), while Git treats dangling heads like garbage and throws them
away when "git gc" or "git prune" are invoked. In theory, I could do
something like:
~/repos$ git clone
https://bitbucket.org/inferno-os/inferno-os.git gitrepo
~/repos$ touch namelist.txt
~/repos$ cd myhg # my Inferno development repo
~/repos/myhg$ hg heads >> ../namelist.txt
~/repos/myhg$ hg tags >> ../namelist.txt
~/repos/myhg$ vim ../namelist.txt # create a table of "branch" names
~/repos/myhg$ cat ../namelist.txt | while read revspec tagspec; do
hg bookmarks -r "$revspec" "$tagspec"
done
~/repos/myhg$ hg push ../gitrepo `awk '{print $2}' < ../namelist.txt`
The problem with this is that there's no way for hg (or Hg-Git) to find
the common ancestor that the branches in namelist.txt share with the
"master" branch in gitrepo. The two repositories, ostensibly, don't
have any common history. So, presumably, this would push an entire
duplicate history(!) into gitrepo. Unfortunately, the documentation
doesn't provide any guidance regarding how a particular Mercurial
changeset maps to its corresponding Git commit, and vice versa.
Any ideas what to do, here? I mean, besides suing the Git Foundation
for injunctive relief?