Adhere to PEP 394
[fast-export.git] / hg-fast-export.sh
blob531b3c5787b588bdce7ba864d34d9b71bf7167f5
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:-python2}
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
59 --filter-contents <cmd> Pipe contents of each exported file through <cmd>
60 with <file-path> <hg-hash> <is-binary> as arguments
62 case "$1" in
63 -h|--help)
64 echo "usage: $(basename "$0") $USAGE"
65 echo ""
66 echo "$LONG_USAGE"
67 exit 0
68 esac
70 IS_BARE=$(git rev-parse --is-bare-repository) \
71 || (echo "Could not find git repo" ; exit 1)
72 if test "z$IS_BARE" != ztrue; then
73 # This is not a bare repo, cd to the toplevel
74 TOPLEVEL=$(git rev-parse --show-toplevel) \
75 || (echo "Could not find git repo toplevel" ; exit 1)
76 cd "$TOPLEVEL" || exit 1
78 GIT_DIR=$(git rev-parse --git-dir) || (echo "Could not find git repo" ; exit 1)
81 IGNORECASEWARN=""
82 IGNORECASE=`git config core.ignoreCase`
83 if [ "true" = "$IGNORECASE" ]; then
84 IGNORECASEWARN="true"
85 fi;
88 while case "$#" in 0) break ;; esac
90 case "$1" in
91 -r|--r|--re|--rep|--repo)
92 shift
93 REPO="$1"
95 --q|--qu|--qui|--quie|--quiet)
96 GFI_OPTS="$GFI_OPTS --quiet"
98 --force)
99 # pass --force to git-fast-import and hg-fast-export.py
100 GFI_OPTS="$GFI_OPTS --force"
101 IGNORECASEWARN="";
102 break
105 # pass any other options down to hg2git.py
106 break
109 break
111 esac
112 shift
113 done
115 if [ ! -z "$IGNORECASEWARN" ]; then
116 echo "Error: The option core.ignoreCase is set to true in the git"
117 echo "repository. This will produce empty changesets for renames that just"
118 echo "change the case of the file name."
119 echo "Use --force to skip this check or change the option with"
120 echo "git config core.ignoreCase false"
121 exit 1
124 # Make a backup copy of each state file
125 for i in $SFX_STATE $SFX_MARKS $SFX_MAPPING $SFX_HEADS ; do
126 if [ -f "$GIT_DIR/$PFX-$i" ] ; then
127 cp "$GIT_DIR/$PFX-$i" "$GIT_DIR/$PFX-$i~"
129 done
131 # for convenience: get default repo from state file
132 if [ x"$REPO" = x -a -f "$GIT_DIR/$PFX-$SFX_STATE" ] ; then
133 REPO="`grep '^:repo ' "$GIT_DIR/$PFX-$SFX_STATE" | cut -d ' ' -f 2`"
134 echo "Using last hg repository \"$REPO\""
137 if [ -z "$REPO" ]; then
138 echo "no repo given, use -r flag"
139 exit 1
142 # make sure we have a marks cache
143 if [ ! -f "$GIT_DIR/$PFX-$SFX_MARKS" ] ; then
144 touch "$GIT_DIR/$PFX-$SFX_MARKS"
147 # cleanup on exit
148 trap 'rm -f "$GIT_DIR/$PFX-$SFX_MARKS.old" "$GIT_DIR/$PFX-$SFX_MARKS.tmp"' 0
150 _err1=
151 _err2=
152 exec 3>&1
153 { read -r _err1 || :; read -r _err2 || :; } <<-EOT
155 exec 4>&3 3>&1 1>&4 4>&-
157 _e1=0
158 GIT_DIR="$GIT_DIR" "$PYTHON" "$ROOT/hg-fast-export.py" \
159 --repo "$REPO" \
160 --marks "$GIT_DIR/$PFX-$SFX_MARKS" \
161 --mapping "$GIT_DIR/$PFX-$SFX_MAPPING" \
162 --heads "$GIT_DIR/$PFX-$SFX_HEADS" \
163 --status "$GIT_DIR/$PFX-$SFX_STATE" \
164 "$@" 3>&- || _e1=$?
165 echo $_e1 >&3
166 } | \
168 _e2=0
169 git fast-import $GFI_OPTS --export-marks="$GIT_DIR/$PFX-$SFX_MARKS.tmp" 3>&- || _e2=$?
170 echo $_e2 >&3
174 exec 3>&-
175 [ "$_err1" = 0 -a "$_err2" = 0 ] || exit 1
177 # move recent marks cache out of the way...
178 if [ -f "$GIT_DIR/$PFX-$SFX_MARKS" ] ; then
179 mv "$GIT_DIR/$PFX-$SFX_MARKS" "$GIT_DIR/$PFX-$SFX_MARKS.old"
180 else
181 touch "$GIT_DIR/$PFX-$SFX_MARKS.old"
184 # ...to create a new merged one
185 cat "$GIT_DIR/$PFX-$SFX_MARKS.old" "$GIT_DIR/$PFX-$SFX_MARKS.tmp" \
186 | uniq > "$GIT_DIR/$PFX-$SFX_MARKS"
188 # save SHA1s of current heads for incremental imports
189 # and connectivity (plus sanity checking)
190 for head in `git branch | sed 's#^..##'` ; do
191 id="`git rev-parse refs/heads/$head`"
192 echo ":$head $id"
193 done > "$GIT_DIR/$PFX-$SFX_HEADS"
195 # check diff with color:
196 # ( for i in `find . -type f | grep -v '\.git'` ; do diff -u $i $REPO/$i ; done | cdiff ) | less -r