Change syntax of mapping files
[fast-export.git] / hg-fast-export.sh
blob7c36a50a00f816c58abdae780c897cb9ecd2239d
1 #!/bin/sh
3 # Copyright (c) 2007, 2008 Rocco Rutte <pdmef@gmx.net> and others.
4 # License: MIT <http://www.opensource.org/licenses/mit-license.php>
6 READLINK="readlink"
7 if command -v greadlink > /dev/null; then
8 READLINK="greadlink" # Prefer greadlink over readlink
9 fi
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."
16 exit 1
18 else
19 ROOT="$(dirname "$($READLINK -f "$(which "$0")")")"
22 REPO=""
23 PFX="hg2git"
24 SFX_MAPPING="mapping"
25 SFX_MARKS="marks"
26 SFX_HEADS="heads"
27 SFX_STATE="state"
28 GFI_OPTS=""
29 PYTHON=${PYTHON:-python}
31 USAGE="[--quiet] [-r <repo>] [--force] [-m <max>] [-s] [--hgtags] [-A <file>] [-B <file>] [-T <file>] [-M <name>] [-o <name>] [--hg-hash] [-e <encoding>]"
32 LONG_USAGE="Import hg repository <repo> up to either tip or <max>
33 If <repo> is omitted, use last hg repository as obtained from state file,
34 GIT_DIR/$PFX-$SFX_STATE by default.
36 Note: The argument order matters.
38 Options:
39 --quiet Passed to git-fast-import(1)
40 -r <repo> Mercurial repository to import
41 --force Ignore validation errors when converting, and pass --force
42 to git-fast-import(1)
43 -m <max> Maximum revision to import
44 -s Enable parsing Signed-off-by lines
45 --hgtags Enable exporting .hgtags files
46 -A <file> Read author map from file
47 (Same as in git-svnimport(1) and git-cvsimport(1))
48 -B <file> Read branch map from file
49 -T <file> Read tags map from file
50 -M <name> Set the default branch name (defaults to 'master')
51 -o <name> Use <name> as branch namespace to track upstream (eg 'origin')
52 --hg-hash Annotate commits with the hg hash as git notes in the
53 hg namespace.
54 -e <encoding> Assume commit and author strings retrieved from
55 Mercurial are encoded in <encoding>
56 --fe <filename_encoding> Assume filenames from Mercurial are encoded
57 in <filename_encoding>
58 --mappings-are-raw Assume mappings are raw <key>=<value> lines
60 case "$1" in
61 -h|--help)
62 echo "usage: $(basename "$0") $USAGE"
63 echo ""
64 echo "$LONG_USAGE"
65 exit 0
66 esac
68 IS_BARE=$(git rev-parse --is-bare-repository) \
69 || (echo "Could not find git repo" ; exit 1)
70 if test "z$IS_BARE" != ztrue; then
71 # This is not a bare repo, cd to the toplevel
72 TOPLEVEL=$(git rev-parse --show-toplevel) \
73 || (echo "Could not find git repo toplevel" ; exit 1)
74 cd "$TOPLEVEL" || exit 1
76 GIT_DIR=$(git rev-parse --git-dir) || (echo "Could not find git repo" ; exit 1)
79 IGNORECASEWARN=""
80 IGNORECASE=`git config core.ignoreCase`
81 if [ "true" = "$IGNORECASE" ]; then
82 IGNORECASEWARN="true"
83 fi;
86 while case "$#" in 0) break ;; esac
88 case "$1" in
89 -r|--r|--re|--rep|--repo)
90 shift
91 REPO="$1"
93 --q|--qu|--qui|--quie|--quiet)
94 GFI_OPTS="$GFI_OPTS --quiet"
96 --force)
97 # pass --force to git-fast-import and hg-fast-export.py
98 GFI_OPTS="$GFI_OPTS --force"
99 IGNORECASEWARN="";
100 break
103 # pass any other options down to hg2git.py
104 break
107 break
109 esac
110 shift
111 done
113 if [ ! -z "$IGNORECASEWARN" ]; then
114 echo "Error: The option core.ignoreCase is set to true in the git"
115 echo "repository. This will produce empty changesets for renames that just"
116 echo "change the case of the file name."
117 echo "Use --force to skip this check or change the option with"
118 echo "git config core.ignoreCase false"
119 exit 1
122 # Make a backup copy of each state file
123 for i in $SFX_STATE $SFX_MARKS $SFX_MAPPING $SFX_HEADS ; do
124 if [ -f "$GIT_DIR/$PFX-$i" ] ; then
125 cp "$GIT_DIR/$PFX-$i" "$GIT_DIR/$PFX-$i~"
127 done
129 # for convenience: get default repo from state file
130 if [ x"$REPO" = x -a -f "$GIT_DIR/$PFX-$SFX_STATE" ] ; then
131 REPO="`grep '^:repo ' "$GIT_DIR/$PFX-$SFX_STATE" | cut -d ' ' -f 2`"
132 echo "Using last hg repository \"$REPO\""
135 if [ -z "$REPO" ]; then
136 echo "no repo given, use -r flag"
137 exit 1
140 # make sure we have a marks cache
141 if [ ! -f "$GIT_DIR/$PFX-$SFX_MARKS" ] ; then
142 touch "$GIT_DIR/$PFX-$SFX_MARKS"
145 # cleanup on exit
146 trap 'rm -f "$GIT_DIR/$PFX-$SFX_MARKS.old" "$GIT_DIR/$PFX-$SFX_MARKS.tmp"' 0
148 _err1=
149 _err2=
150 exec 3>&1
151 { read -r _err1 || :; read -r _err2 || :; } <<-EOT
153 exec 4>&3 3>&1 1>&4 4>&-
155 _e1=0
156 GIT_DIR="$GIT_DIR" $PYTHON "$ROOT/hg-fast-export.py" \
157 --repo "$REPO" \
158 --marks "$GIT_DIR/$PFX-$SFX_MARKS" \
159 --mapping "$GIT_DIR/$PFX-$SFX_MAPPING" \
160 --heads "$GIT_DIR/$PFX-$SFX_HEADS" \
161 --status "$GIT_DIR/$PFX-$SFX_STATE" \
162 "$@" 3>&- || _e1=$?
163 echo $_e1 >&3
164 } | \
166 _e2=0
167 git fast-import $GFI_OPTS --export-marks="$GIT_DIR/$PFX-$SFX_MARKS.tmp" 3>&- || _e2=$?
168 echo $_e2 >&3
172 exec 3>&-
173 [ "$_err1" = 0 -a "$_err2" = 0 ] || exit 1
175 # move recent marks cache out of the way...
176 if [ -f "$GIT_DIR/$PFX-$SFX_MARKS" ] ; then
177 mv "$GIT_DIR/$PFX-$SFX_MARKS" "$GIT_DIR/$PFX-$SFX_MARKS.old"
178 else
179 touch "$GIT_DIR/$PFX-$SFX_MARKS.old"
182 # ...to create a new merged one
183 cat "$GIT_DIR/$PFX-$SFX_MARKS.old" "$GIT_DIR/$PFX-$SFX_MARKS.tmp" \
184 | uniq > "$GIT_DIR/$PFX-$SFX_MARKS"
186 # save SHA1s of current heads for incremental imports
187 # and connectivity (plus sanity checking)
188 for head in `git branch | sed 's#^..##'` ; do
189 id="`git rev-parse refs/heads/$head`"
190 echo ":$head $id"
191 done > "$GIT_DIR/$PFX-$SFX_HEADS"
193 # check diff with color:
194 # ( for i in `find . -type f | grep -v '\.git'` ; do diff -u $i $REPO/$i ; done | cdiff ) | less -r