3 # Copyright (c) 2007, 2008 Rocco Rutte <pdmef@gmx.net> and others.
4 # License: MIT <http://www.opensource.org/licenses/mit-license.php>
7 if command -v greadlink
> /dev
/null
; then
8 READLINK
="greadlink" # Prefer greadlink over readlink
11 if ! $READLINK -f "$(which "$0")" > /dev
/null
2>&1 ; then
12 ROOT
="$(dirname "$
(which "$0")")"
13 if [ ! -f "$ROOT/hg-fast-export.py" ] ; then
14 echo "hg-fast-exports requires a readlink implementation which knows" \
15 " how to canonicalize paths in order to be called via a symlink."
19 ROOT
="$(dirname "$
($READLINK -f "$(which "$0")")")"
30 if [ -z "${PYTHON}" ]; then
31 # $PYTHON is not set, so we try to find a working python with mercurial:
32 for python_cmd
in python2 python python3
; do
33 if command -v $python_cmd > /dev
/null
; then
34 $python_cmd -c 'from mercurial.scmutil import revsymbol' 2> /dev
/null
42 if [ -z "${PYTHON}" ]; then
43 echo "Could not find a python interpreter with the mercurial module >= 4.6 available. " \
44 "Please use the 'PYTHON' environment variable to specify the interpreter to use."
48 USAGE
="[--quiet] [-r <repo>] [--force] [-m <max>] [-s] [--hgtags] [-A <file>] [-B <file>] [-T <file>] [-M <name>] [-o <name>] [--hg-hash] [-e <encoding>]"
49 LONG_USAGE
="Import hg repository <repo> up to either tip or <max>
50 If <repo> is omitted, use last hg repository as obtained from state file,
51 GIT_DIR/$PFX-$SFX_STATE by default.
53 Note: The argument order matters.
56 --quiet Passed to git-fast-import(1)
57 -r <repo> Mercurial repository to import
58 --force Ignore validation errors when converting, and pass --force
60 -m <max> Maximum revision to import
61 -s Enable parsing Signed-off-by lines
62 --hgtags Enable exporting .hgtags files
63 -A <file> Read author map from file
64 (Same as in git-svnimport(1) and git-cvsimport(1))
65 -B <file> Read branch map from file
66 -T <file> Read tags map from file
67 -M <name> Set the default branch name (defaults to 'master')
68 -n Do not perform built-in (broken in many cases) sanitizing
70 -o <name> Use <name> as branch namespace to track upstream (eg 'origin')
71 --hg-hash Annotate commits with the hg hash as git notes in the
73 -e <encoding> Assume commit and author strings retrieved from
74 Mercurial are encoded in <encoding>
75 --fe <filename_encoding> Assume filenames from Mercurial are encoded
76 in <filename_encoding>
77 --mappings-are-raw Assume mappings are raw <key>=<value> lines
78 --filter-contents <cmd> Pipe contents of each exported file through <cmd>
79 with <file-path> <hg-hash> <is-binary> as arguments
80 --plugin <plugin=init> Add a plugin with the given init string (repeatable)
81 --plugin-path <plugin-path> Add an additional plugin lookup path
85 echo "usage: $(basename "$0") $USAGE"
91 IS_BARE
=$
(git rev-parse
--is-bare-repository) \
92 ||
(echo "Could not find git repo" ; exit 1)
93 if test "z$IS_BARE" != ztrue
; then
94 # This is not a bare repo, cd to the toplevel
95 TOPLEVEL
=$
(git rev-parse
--show-toplevel) \
96 ||
(echo "Could not find git repo toplevel" ; exit 1)
97 cd "$TOPLEVEL" ||
exit 1
99 GIT_DIR
=$
(git rev-parse
--git-dir) ||
(echo "Could not find git repo" ; exit 1)
103 IGNORECASE
=`git config core.ignoreCase`
104 if [ "true" = "$IGNORECASE" ]; then
105 IGNORECASEWARN
="true"
109 while case "$#" in 0) break ;; esac
112 -r|
--r|
--re|
--rep|
--repo)
116 --q|
--qu|
--qui|
--quie|
--quiet)
117 GFI_OPTS
="$GFI_OPTS --quiet"
120 # pass --force to git-fast-import and hg-fast-export.py
121 GFI_OPTS
="$GFI_OPTS --force"
126 # pass any other options down to hg2git.py
136 if [ ! -z "$IGNORECASEWARN" ]; then
137 echo "Error: The option core.ignoreCase is set to true in the git"
138 echo "repository. This will produce empty changesets for renames that just"
139 echo "change the case of the file name."
140 echo "Use --force to skip this check or change the option with"
141 echo "git config core.ignoreCase false"
145 # Make a backup copy of each state file
146 for i
in $SFX_STATE $SFX_MARKS $SFX_MAPPING $SFX_HEADS ; do
147 if [ -f "$GIT_DIR/$PFX-$i" ] ; then
148 cp "$GIT_DIR/$PFX-$i" "$GIT_DIR/$PFX-$i~"
152 # for convenience: get default repo from state file
153 if [ x
"$REPO" = x
-a -f "$GIT_DIR/$PFX-$SFX_STATE" ] ; then
154 REPO
="`grep '^:repo ' "$GIT_DIR/$PFX-$SFX_STATE" | cut -d ' ' -f 2`"
155 echo "Using last hg repository \"$REPO\""
158 if [ -z "$REPO" ]; then
159 echo "no repo given, use -r flag"
163 # make sure we have a marks cache
164 if [ ! -f "$GIT_DIR/$PFX-$SFX_MARKS" ] ; then
165 touch "$GIT_DIR/$PFX-$SFX_MARKS"
169 trap 'rm -f "$GIT_DIR/$PFX-$SFX_MARKS.old" "$GIT_DIR/$PFX-$SFX_MARKS.tmp"' 0
174 { read -r _err1 ||
:; read -r _err2 ||
:; } <<-EOT
176 exec 4>&3 3>&1 1>&4 4>&-
179 GIT_DIR="$GIT_DIR" "$PYTHON" "$ROOT/hg-fast-export.py" \
181 --marks "$GIT_DIR/$PFX-$SFX_MARKS" \
182 --mapping "$GIT_DIR/$PFX-$SFX_MAPPING" \
183 --heads "$GIT_DIR/$PFX-$SFX_HEADS" \
184 --status "$GIT_DIR/$PFX-$SFX_STATE" \
190 git fast-import $GFI_OPTS --export-marks="$GIT_DIR/$PFX-$SFX_MARKS.tmp" 3>&- || _e2=$?
196 [ "$_err1" = 0 -a "$_err2" = 0 ] ||
exit 1
198 # move recent marks cache out of the way...
199 if [ -f "$GIT_DIR/$PFX-$SFX_MARKS" ] ; then
200 mv "$GIT_DIR/$PFX-$SFX_MARKS" "$GIT_DIR/$PFX-$SFX_MARKS.old"
202 touch "$GIT_DIR/$PFX-$SFX_MARKS.old"
205 # ...to create a new merged one
206 cat "$GIT_DIR/$PFX-$SFX_MARKS.old" "$GIT_DIR/$PFX-$SFX_MARKS.tmp" \
207 |
uniq > "$GIT_DIR/$PFX-$SFX_MARKS"
209 # save SHA1s of current heads for incremental imports
210 # and connectivity (plus sanity checking)
211 for head in `git branch | sed 's#^..##'` ; do
212 id
="`git rev-parse refs/heads/$head`"
214 done > "$GIT_DIR/$PFX-$SFX_HEADS"
216 # check diff with color:
217 # ( for i in `find . -type f | grep -v '\.git'` ; do diff -u $i $REPO/$i ; done | cdiff ) | less -r