DEV Community

Nor
Nor

Posted on

How to rsync a git project to a svn folder?

#!/bin/bash

PROJ_ROOT_DIR="$(dirname "$(dirname "$(readlink -f "$0")")")"
echo "Project directory: $PROJ_ROOT_DIR"

PROJ_ROOT_DIR_PARENT="$(dirname "$PROJ_ROOT_DIR")"

TIMESTAMP=$(date +%Y%m%d_%H%M_%S_%3N)

cd "$PROJ_ROOT_DIR"

# ########
echo ">>> $(date +%Y%m%d_%H%M_%S_%3N) start pack to svn code "

BACKUP_OLD_SVN_CODE_DIR="$PROJ_ROOT_DIR_PARENT/_backup/old_svn_code/$TIMESTAMP"
mkdir -p "$BACKUP_OLD_SVN_CODE_DIR"

SVN_DIR="$PROJ_ROOT_DIR_PARENT/_svn/test_rsync"

####################################

# #### @method[git archive]:

if false; then
  GIT_TEMP_DIR=$(mktemp -d)
  git archive HEAD | tar -x -C "$GIT_TEMP_DIR/"

  rsync -aivhP \
    --delete \
    --backup --backup-dir="$BACKUP_OLD_SVN_CODE_DIR" \
    --exclude='.svn/' \
    "$GIT_TEMP_DIR/" \
    "$SVN_DIR/"

  rm -rf "$GIT_TEMP_DIR"
fi

# @pros:
# - use git archive, reliable and deterministic for git user.
# @cons:
# - local source code **file modification time are all changed**.
# - zip and unzip is slow.
# - need tmp folder.
# - re-copy every single file every time (because file modification time is changed).
# @note:
# - you cannot **only** update the file modification time afterwards,
#   `rsync -rt --existing ./ "$PROJ_ROOT_DIR/rsync_out/"` will not work, it will update the whole file, slow.

# #### @method[rsync + gitignore]:

if false; then
  rsync -aivhP \
    --delete-after \
    --backup --backup-dir="$BACKUP_OLD_SVN_CODE_DIR" \
    --include='**.gitignore' \
    --exclude='/.git/' \
    --filter=':- .gitignore' \
    --filter='protect /.svn/' \
    . "$SVN_DIR/"
fi

# @pros:
# - directly uses rsync, no git involved, only .gitignore is needed.
# @cons:
# - **unable to recognize negation** , eg: the `!imp.log` after `*.log` will still be ignored.
# - if a file is added to .gitignore **later**, it will **not be deleted** from the svn code, cuz its ignored now.

# #### @method[rsync + git ls-files]:

if false; then
  git ls-files -zc | rsync -aivhP --delete --backup --backup-dir="$BACKUP_OLD_SVN_CODE_DIR" \
    --from0 --files-from=- \
    --filter='protect /.svn/' \
    . "$SVN_DIR/"
fi

# @pros:
# - use git ls-files instead of telling rsync to parse gitignore
# @cons:
# - **unable to do deletion**
# - base on the current local file in the project, not the git committed HEAD.
# @note:
# - tried `--delete-excluded --exclude='*' --delete-missing-args`, just wont work.

# #### @method[rsync + git ls-files + tmp + link-dest]:
# @recommend:

TMP_GIT_PROJ_SOURCE_CODE_DIR="$PROJ_ROOT_DIR_PARENT/_tmp/git_proj_source_code/$TIMESTAMP"
mkdir -p "$TMP_GIT_PROJ_SOURCE_CODE_DIR/"

git ls-files -c

git ls-files -zc |
  rsync -aivhP \
    --from0 --files-from=- \
    --link-dest="$SVN_DIR/" \
    "./" "$TMP_GIT_PROJ_SOURCE_CODE_DIR/"

rsync -aivhP \
  --delete \
  --backup --backup-dir="$BACKUP_OLD_SVN_CODE_DIR" \
  --filter='protect /.svn/' \
  --link-dest="$TMP_GIT_PROJ_SOURCE_CODE_DIR/" \
  "$TMP_GIT_PROJ_SOURCE_CODE_DIR/" "$SVN_DIR/"

rm -r "${TMP_GIT_PROJ_SOURCE_CODE_DIR:?}/"

# @pros:
# - use git ls-files, reliable.
# - solve most of those problems above.
# - fast, utilize rsync and link-dest with hard link.
# @cons:
# - base on the current local file in the project, not the git committed HEAD.
# - need tmp folder.
# - complex, still not single line rsync command.

####################################

# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# @warning:
# - I did test the code before, but made minor modification later without testing again.

# @comment,sum:
# - the whole problem was due to:
#   - rsync has poor support for delete with files-from.
#   - rsync has poor support for gitignore.
# - if those problems were solved, we could have use simpler single line rsync command.

# project parent dir structure:
#   
#   _backup
#   _backup\old_svn_code
#   _backup\old_svn_code\20250728_1231_10_755
#   _backup\old_svn_code\20250728_1237_35_271
#   
#   _svn
#   _svn\test_rsync
#   _svn\test_rsync\bb
#   _svn\test_rsync\cc
#   _svn\test_rsync\scripts
#   _svn\test_rsync\.gitignore
#   
#   _tmp
#   _tmp\git_proj_source_code
#   
#   test_rsync
#   test_rsync\.git
#   test_rsync\bb
#   test_rsync\bb\b1.log
#   test_rsync\bb\b1.txt
#   test_rsync\bb\b2.log
#   test_rsync\bb\b2.txt
#   test_rsync\bb\imp.log
#   test_rsync\cc
#   test_rsync\cc\c1.txt
#   test_rsync\cc\c2.txt
#   test_rsync\scripts
#   test_rsync\scripts\proj_pack_and_sync.sh
#   test_rsync\.gitignore
#   test_rsync\test_rsync.code-workspace

# @reference:
#   rsync --delete --files-from=list / dest/ does not delete unwanted files - Stack Overflow
#   https://stackoverflow.com/questions/1813907/rsync-delete-files-from-list-dest-does-not-delete-unwanted-files?rq=4
#
#   git - rsync exclude according to .gitignore & .hgignore & svn:ignore like --filter=:C - Stack Overflow
#   https://stackoverflow.com/questions/13713101/rsync-exclude-according-to-gitignore-hgignore-svnignore-like-filter-c

Enter fullscreen mode Exit fullscreen mode

img of project parent dir structure

Top comments (0)