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 python3 python
; 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 "${PYTHON}" -c 'import sys; exit(sys.version_info.major==3 and sys.version_info.minor >= 7)'
51 echo "Could not find an interpreter for a supported Python version (>= 3.7)" \
52 "Please use the 'PYTHON' environment variable to specify the interpreter to use."
56 USAGE
="[--quiet] [-r <repo>] [--force] [--ignore-unnamed-heads] [-m <max>] [-s] [--hgtags] [-A <file>] [-B <file>] [-T <file>] [-M <name>] [-o <name>] [--hg-hash] [-e <encoding>]"
57 LONG_USAGE
="Import hg repository <repo> up to either tip or <max>
58 If <repo> is omitted, use last hg repository as obtained from state file,
59 GIT_DIR/$PFX-$SFX_STATE by default.
61 Note: The argument order matters.
64 --quiet Passed to git-fast-import(1)
65 -r <repo> Mercurial repository to import
66 --force Ignore validation errors when converting, and pass --force
68 -m <max> Maximum revision to import
69 -s Enable parsing Signed-off-by lines
70 --hgtags Enable exporting .hgtags files
71 -A <file> Read author map from file
72 (Same as in git-svnimport(1) and git-cvsimport(1))
73 -B <file> Read branch map from file
74 -T <file> Read tags map from file
75 -M <name> Set the default branch name (defaults to 'master')
76 -n Do not perform built-in (broken in many cases) sanitizing
78 -o <name> Use <name> as branch namespace to track upstream (eg 'origin')
79 --hg-hash Annotate commits with the hg hash as git notes in the
81 -e <encoding> Assume commit and author strings retrieved from
82 Mercurial are encoded in <encoding>
83 --fe <filename_encoding> Assume filenames from Mercurial are encoded
84 in <filename_encoding>
85 --mappings-are-raw Assume mappings are raw <key>=<value> lines
86 --filter-contents <cmd> Pipe contents of each exported file through <cmd>
87 with <file-path> <hg-hash> <is-binary> as arguments
88 --plugin <plugin=init> Add a plugin with the given init string (repeatable)
89 --plugin-path <plugin-path> Add an additional plugin lookup path
93 echo "usage: $(basename "$0") $USAGE"
100 echo -n "Using Python: "
101 "${PYTHON}" --version
102 echo -n "Using Mercurial: "
107 IS_BARE
=$
(git rev-parse
--is-bare-repository) \
108 ||
(echo "Could not find git repo" ; exit 1)
109 if test "z$IS_BARE" != ztrue
; then
110 # This is not a bare repo, cd to the toplevel
111 TOPLEVEL
=$
(git rev-parse
--show-toplevel) \
112 ||
(echo "Could not find git repo toplevel" ; exit 1)
113 cd "$TOPLEVEL" ||
exit 1
115 GIT_DIR
=$
(git rev-parse
--git-dir) ||
(echo "Could not find git repo" ; exit 1)
119 IGNORECASE
=`git config core.ignoreCase`
120 if [ "true" = "$IGNORECASE" ]; then
121 IGNORECASEWARN
="true"
125 while case "$#" in 0) break ;; esac
128 -r|
--r|
--re|
--rep|
--repo)
132 --q|
--qu|
--qui|
--quie|
--quiet)
133 GFI_OPTS
="$GFI_OPTS --quiet"
136 # pass --force to git-fast-import and hg-fast-export.py
137 GFI_OPTS
="$GFI_OPTS --force"
142 # pass any other options down to hg2git.py
152 if [ ! -z "$IGNORECASEWARN" ]; then
153 echo "Error: The option core.ignoreCase is set to true in the git"
154 echo "repository. This will produce empty changesets for renames that just"
155 echo "change the case of the file name."
156 echo "Use --force to skip this check or change the option with"
157 echo "git config core.ignoreCase false"
161 # Make a backup copy of each state file
162 for i
in $SFX_STATE $SFX_MARKS $SFX_MAPPING $SFX_HEADS ; do
163 if [ -f "$GIT_DIR/$PFX-$i" ] ; then
164 cp "$GIT_DIR/$PFX-$i" "$GIT_DIR/$PFX-$i~"
168 # for convenience: get default repo from state file
169 if [ x
"$REPO" = x
-a -f "$GIT_DIR/$PFX-$SFX_STATE" ] ; then
170 REPO
="`grep '^:repo ' "$GIT_DIR/$PFX-$SFX_STATE" | cut -d ' ' -f 2`"
171 echo "Using last hg repository \"$REPO\""
174 if [ -z "$REPO" ]; then
175 echo "no repo given, use -r flag"
179 # make sure we have a marks cache
180 if [ ! -f "$GIT_DIR/$PFX-$SFX_MARKS" ] ; then
181 touch "$GIT_DIR/$PFX-$SFX_MARKS"
185 trap 'rm -f "$GIT_DIR/$PFX-$SFX_MARKS.old" "$GIT_DIR/$PFX-$SFX_MARKS.tmp"' 0
190 { read -r _err1 ||
:; read -r _err2 ||
:; } <<-EOT
192 exec 4>&3 3>&1 1>&4 4>&-
195 GIT_DIR="$GIT_DIR" "$PYTHON" "$ROOT/hg-fast-export.py" \
197 --marks "$GIT_DIR/$PFX-$SFX_MARKS" \
198 --mapping "$GIT_DIR/$PFX-$SFX_MAPPING" \
199 --heads "$GIT_DIR/$PFX-$SFX_HEADS" \
200 --status "$GIT_DIR/$PFX-$SFX_STATE" \
206 git fast-import $GFI_OPTS --export-marks="$GIT_DIR/$PFX-$SFX_MARKS.tmp" 3>&- || _e2=$?
212 [ "$_err1" = 0 -a "$_err2" = 0 ] ||
exit 1
214 # move recent marks cache out of the way...
215 if [ -f "$GIT_DIR/$PFX-$SFX_MARKS" ] ; then
216 mv "$GIT_DIR/$PFX-$SFX_MARKS" "$GIT_DIR/$PFX-$SFX_MARKS.old"
218 touch "$GIT_DIR/$PFX-$SFX_MARKS.old"
221 # ...to create a new merged one
222 cat "$GIT_DIR/$PFX-$SFX_MARKS.old" "$GIT_DIR/$PFX-$SFX_MARKS.tmp" \
223 |
uniq > "$GIT_DIR/$PFX-$SFX_MARKS"
225 # save SHA1s of current heads for incremental imports
226 # and connectivity (plus sanity checking)
227 for head in `git branch | sed 's#^..##'` ; do
228 id
="`git rev-parse refs/heads/$head`"
230 done > "$GIT_DIR/$PFX-$SFX_HEADS"
232 # check diff with color:
233 # ( for i in `find . -type f | grep -v '\.git'` ; do diff -u $i $REPO/$i ; done | cdiff ) | less -r