Make hg-fst-export.sh callable via a symbolic link
[fast-export.git] / hg-fast-export.sh
blob1117cbdd0de9f3b5f35fcdc7b5baf4cd07590c2b
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
10 ROOT="$(dirname "$($READLINK -f "$(which "$0")")")"
11 REPO=""
12 PFX="hg2git"
13 SFX_MAPPING="mapping"
14 SFX_MARKS="marks"
15 SFX_HEADS="heads"
16 SFX_STATE="state"
17 GFI_OPTS=""
18 PYTHON=${PYTHON:-python}
20 USAGE="[--quiet] [-r <repo>] [--force] [-m <max>] [-s] [--hgtags] [-A <file>] [-B <file>] [-T <file>] [-M <name>] [-o <name>] [--hg-hash] [-e <encoding>]"
21 LONG_USAGE="Import hg repository <repo> up to either tip or <max>
22 If <repo> is omitted, use last hg repository as obtained from state file,
23 GIT_DIR/$PFX-$SFX_STATE by default.
25 Note: The argument order matters.
27 Options:
28 --quiet Passed to git-fast-import(1)
29 -r <repo> Mercurial repository to import
30 --force Ignore validation errors when converting, and pass --force
31 to git-fast-import(1)
32 -m <max> Maximum revision to import
33 -s Enable parsing Signed-off-by lines
34 --hgtags Enable exporting .hgtags files
35 -A <file> Read author map from file
36 (Same as in git-svnimport(1) and git-cvsimport(1))
37 -B <file> Read branch map from file
38 -T <file> Read tags map from file
39 -M <name> Set the default branch name (defaults to 'master')
40 -o <name> Use <name> as branch namespace to track upstream (eg 'origin')
41 --hg-hash Annotate commits with the hg hash as git notes in the
42 hg namespace.
43 -e <encoding> Assume commit and author strings retrieved from
44 Mercurial are encoded in <encoding>
45 --fe <filename_encoding> Assume filenames from Mercurial are encoded
46 in <filename_encoding>
48 case "$1" in
49 -h|--help)
50 echo "usage: $(basename "$0") $USAGE"
51 echo ""
52 echo "$LONG_USAGE"
53 exit 0
54 esac
56 IS_BARE=$(git rev-parse --is-bare-repository) \
57 || (echo "Could not find git repo" ; exit 1)
58 if test "z$IS_BARE" != ztrue; then
59 # This is not a bare repo, cd to the toplevel
60 TOPLEVEL=$(git rev-parse --show-toplevel) \
61 || (echo "Could not find git repo toplevel" ; exit 1)
62 cd $TOPLEVEL || exit 1
64 GIT_DIR=$(git rev-parse --git-dir) || (echo "Could not find git repo" ; exit 1)
67 IGNORECASEWARN=""
68 IGNORECASE=`git config core.ignoreCase`
69 if [ "true" = "$IGNORECASE" ]; then
70 IGNORECASEWARN="true"
71 fi;
74 while case "$#" in 0) break ;; esac
76 case "$1" in
77 -r|--r|--re|--rep|--repo)
78 shift
79 REPO="$1"
81 --q|--qu|--qui|--quie|--quiet)
82 GFI_OPTS="$GFI_OPTS --quiet"
84 --force)
85 # pass --force to git-fast-import and hg-fast-export.py
86 GFI_OPTS="$GFI_OPTS --force"
87 IGNORECASEWARN="";
88 break
90 -*)
91 # pass any other options down to hg2git.py
92 break
95 break
97 esac
98 shift
99 done
101 if [ ! -z "$IGNORECASEWARN" ]; then
102 echo "Error: The option core.ignoreCase is set to true in the git"
103 echo "repository. This will produce empty changesets for renames that just"
104 echo "change the case of the file name."
105 echo "Use --force to skip this check or change the option with"
106 echo "git config core.ignoreCase false"
107 exit 1
110 # Make a backup copy of each state file
111 for i in $SFX_STATE $SFX_MARKS $SFX_MAPPING $SFX_HEADS ; do
112 if [ -f "$GIT_DIR/$PFX-$i" ] ; then
113 cp "$GIT_DIR/$PFX-$i" "$GIT_DIR/$PFX-$i~"
115 done
117 # for convenience: get default repo from state file
118 if [ x"$REPO" = x -a -f "$GIT_DIR/$PFX-$SFX_STATE" ] ; then
119 REPO="`grep '^:repo ' "$GIT_DIR/$PFX-$SFX_STATE" | cut -d ' ' -f 2`"
120 echo "Using last hg repository \"$REPO\""
123 if [ -z "$REPO" ]; then
124 echo "no repo given, use -r flag"
125 exit 1
128 # make sure we have a marks cache
129 if [ ! -f "$GIT_DIR/$PFX-$SFX_MARKS" ] ; then
130 touch "$GIT_DIR/$PFX-$SFX_MARKS"
133 # cleanup on exit
134 trap 'rm -f "$GIT_DIR/$PFX-$SFX_MARKS.old" "$GIT_DIR/$PFX-$SFX_MARKS.tmp"' 0
136 _err1=
137 _err2=
138 exec 3>&1
139 { read -r _err1 || :; read -r _err2 || :; } <<-EOT
141 exec 4>&3 3>&1 1>&4 4>&-
143 _e1=0
144 GIT_DIR="$GIT_DIR" $PYTHON "$ROOT/hg-fast-export.py" \
145 --repo "$REPO" \
146 --marks "$GIT_DIR/$PFX-$SFX_MARKS" \
147 --mapping "$GIT_DIR/$PFX-$SFX_MAPPING" \
148 --heads "$GIT_DIR/$PFX-$SFX_HEADS" \
149 --status "$GIT_DIR/$PFX-$SFX_STATE" \
150 "$@" 3>&- || _e1=$?
151 echo $_e1 >&3
152 } | \
154 _e2=0
155 git fast-import $GFI_OPTS --export-marks="$GIT_DIR/$PFX-$SFX_MARKS.tmp" 3>&- || _e2=$?
156 echo $_e2 >&3
160 exec 3>&-
161 [ "$_err1" = 0 -a "$_err2" = 0 ] || exit 1
163 # move recent marks cache out of the way...
164 if [ -f "$GIT_DIR/$PFX-$SFX_MARKS" ] ; then
165 mv "$GIT_DIR/$PFX-$SFX_MARKS" "$GIT_DIR/$PFX-$SFX_MARKS.old"
166 else
167 touch "$GIT_DIR/$PFX-$SFX_MARKS.old"
170 # ...to create a new merged one
171 cat "$GIT_DIR/$PFX-$SFX_MARKS.old" "$GIT_DIR/$PFX-$SFX_MARKS.tmp" \
172 | uniq > "$GIT_DIR/$PFX-$SFX_MARKS"
174 # save SHA1s of current heads for incremental imports
175 # and connectivity (plus sanity checking)
176 for head in `git branch | sed 's#^..##'` ; do
177 id="`git rev-parse refs/heads/$head`"
178 echo ":$head $id"
179 done > "$GIT_DIR/$PFX-$SFX_HEADS"
181 # check diff with color:
182 # ( for i in `find . -type f | grep -v '\.git'` ; do diff -u $i $REPO/$i ; done | cdiff ) | less -r