#!/bin/bash set -euo pipefail fatal() { echo "$@" >&2 exit 1 } main() { local target="$1" # Validate target hg repo if [[ ! -d $target/.hg ]] ; then fatal "${1} not a hg repo" fi # Convert to absolute path { cd "$target" target=$(pwd) } ( cd "$target" if [[ $(hg status | wc -l) -ne 0 ]] ; then fatal "${1}: uncommited files, abandoning" fi if hg id | fgrep -q '+' ; then fatal "${1}: uncommitted changes, abandoning" fi # Create 'master' hg bookmark, if there isn't one already if ! hg bookmark | fgrep master ; then hg bookmark master fi ) # Use mercurial-git plugin to convert to bare repo in /tmp/ local gitdir=$(mktemp -d /tmp/hg2git.XXXXXXXX) ( cd "$gitdir" git init --bare ) ( cd "$target" hg push "$gitdir" ) # Move into place local backupdir="$target.hg-converted-$(date -Iseconds)" mv "$target" "$backupdir" mkdir -p "${target}" mv "$gitdir/" "$target/.git" # Reconstruct working directory ( cd "$target" git config --local --bool core.bare false git checkout master ) # Copy over excluded files from the working directory # (add trailing slash to source path) rsync -avr "${backupdir}/" "$target" --exclude=.git --exclude=.hg ( cd "$target" # Remove hgtags file if [[ -f ./.hgtags ]] ; then git rm ./.hgtags git commit -m "hg-git: remove old .hgtags file" fi # Convert hgignore->gitignore (partial) if [[ -f ./.hgignore ]] ; then git mv .hgignore .gitignore sed -i '/^mode:/d' .gitignore # leave in uncommitted state for further fixups fi ) } main "$@"