Skip to content

Instantly share code, notes, and snippets.

@semarie
Created January 12, 2021 18:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save semarie/9c5f40f5dacc49b65b3f9e62fef80ed6 to your computer and use it in GitHub Desktop.
Save semarie/9c5f40f5dacc49b65b3f9e62fef80ed6 to your computer and use it in GitHub Desktop.
mercurial: create a monorepository from repository with subrepositories
#!/bin/sh
set -eu
HG="hg --config subrepos.allowed=True"
if [ $# -ne 2 ] ; then
echo "usage: $0 source-repository destdir"
fi
SDIR=`readlink -f "${1}"`
DDIR="${2}"
# ensure SDIR is a mercurial repository with subrepositories
if [ ! -d "${SDIR}/.hg" -a -e "${SDIR}/.hgsub" ]; then
echo "error: invalid source-repository: ${SDIR}"
exit 1
fi
# ensure DDIR is not existent
if [ -d "${DDIR}" ]; then
echo "error: destdir already exists: ${DDIR}"
exit 1
fi
# create destdir
mkdir -p "${DDIR}"
DDIR=`readlink -f "${DDIR}"`
cd "${DDIR}" && ${HG} init
# PREPARE PHASE
# for each branches of SDIR
cd "${SDIR}" && ${HG} branches -T '{branch} {node}\n' | while read branch_name branch_id ; do
# update to the branch
echo "[+] updating to branch '${branch_name}' id=${branch_id}"
cd "${SDIR}" && ${HG} update -C -r "${branch_id}"
# for each subrepositories
sed -ne 's/^\([^ ]*\) =.*/\1/p' <"${SDIR}/.hgsub" | while read subdir ; do
echo "[+] prepare merge: ${subdir}"
cd "${SDIR}/${subdir}"
# purpose is to make changes which will avoid merge conflicts
# tags rename: XXX -> ${subdir}-XXX
if [ -r ".hgtags" ]; then
sed -i -e "s, , ${subdir}-," ".hgtags"
fi
# create a subdirectory
# rename is done in 2 steps
RENAME=`mktemp -d rename.XXXXXXXXXX` || exit 1
# rename step1
${HG} rename * "${RENAME}"
for f in .drone.yml .flake8 .bower_allow_root.sh ; do
[ -e "${f}" ] && ${HG} rename "${f}" "${RENAME}"
done
# rename step2
${HG} rename "${RENAME}" "${subdir}"
# commit changes
${HG} commit -m "subrepos-flatten: prepare merge: ${branch_name} (${branch_id}) - ${subdir}"
# merge subdir inside DDIR
echo "[+] merging: ${subdir}"
cd ${DDIR} && ${HG} pull -f "${SDIR}/${subdir}"
done
# commit changes at toplevel
#cd "${SDIR}" && ${HG} commit -m "subrepos-flatten: prepare merge: ${branch_name} (${branch_id})"
done
# MERGE PHASE
# for each branches of SDIR
cd "${SDIR}" && ${HG} branches -T '{branch}\n' | while read branch_name ; do
# update to the branch
echo "[+] updating to branch '${branch_name}'"
cd "${DDIR}" && ${HG} update -C -r "${branch_name}"
# merge heads while not only one heads per branch
while [ $(hg heads -T '{node}\n' . | wc -l) -ne 1 ]; do
# update to commit0
hg heads -T '{node}\n' . | head -1 | xargs ${HG} update -C -r
# merge with commitN
if ! hg heads -T '{node}\n' . | tail -1 | xargs ${HG} merge -r ; then
# merge tags (keeping both)
if [ -f .hgtags ]; then
sed -i \
-e '/^<<<<<<< working copy/d' \
-e '/^=======/d' \
-e '/^>>>>>>> merge rev/d' \
.hgtags
hg resolv --mark .hgtags
fi
fi
hg commit -m "subrepos-flatten: merge: ${branch_name}"
done
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment