├── README.markdown ├── git-sync-with-svn.sh ├── install └── git-repository-from-svn.sh ├── report-error.sh ├── server-hooks ├── post-receive └── pre-receive └── sync-client-hooks └── always-reject /README.markdown: -------------------------------------------------------------------------------- 1 | # _git_ SVN Sync 2 | 3 | This repository is intended to provide synchronization between a 4 | running SVN repository and _git_, so that we can get away from 5 | subversion while the build jobs are ported. 6 | 7 | ## Workflow 8 | 9 | The idea is to use pure _git_ exclusively. The subversion repository is 10 | up to date and used to build artifacts and jars, but nobody is 11 | expected to write to it except the _git_ sync client. 12 | 13 | Therefore _git_ would be used both at client and server side. This is an 14 | improvement over using git-svn because it allows to commit branches to 15 | the server, and avoids rewriting history when commiting to svn, among 16 | other things. 17 | 18 | ## Technical view 19 | 20 | For every project in subversion, two _git_ repositories are created, the 21 | server and the sync client. 22 | 23 | ### _git_ Server 24 | 25 | It is a normal bare repository, which supports every git 26 | operation. Every developer clones this repository and uses it 27 | exclusively for the project. 28 | 29 | When someone pushes changes to the master branch, a hook is run which 30 | uses the sync client to bring the changes to subversion. 31 | 32 | ### _git_ Sync client 33 | 34 | This is a repository which is a clone of the _git_ server. When the 35 | post-receive hook at the server is activated, the following happens at 36 | this client: 37 | 38 | * Changes are pulled from the server to the master branch. 39 | * The master branch is merged into a svn sync branch. 40 | * The changes are sent to subversion via git-svn. 41 | 42 | This repository is not intended for developers to use. It rejects 43 | every push and commit, and should only automatically sync with the 44 | server. 45 | 46 | ### Maintaining consistency 47 | 48 | The _git_ server and subversion should be in the same state at every 49 | time. To guarantee this, the following conditions are required: 50 | 51 | * Only the _git_ sync client should ever send changes to 52 | subversion. The write access to svn should be restricted to the 53 | remote _git_ user. 54 | * Nobody except the build jobs in jenkins uses subversion directly 55 | anymore. Developers interact only with the _git_ server. 56 | * The _git_ sync client is never modified. It only pulls changes from 57 | the _git_ server (only fast-forward allowed). 58 | 59 | The consistency is assured via hooks that are installed at the server 60 | and sync client. Access to subversion has to be configured separately. 61 | 62 | ### Reporting 63 | 64 | If something does not work correctly, a mail will be sent specifying 65 | the project which had the problem and the registered error 66 | 67 | ## Setup 68 | 69 | ### Initial setup 70 | 71 | The machine where the repositories are installed needs the following 72 | environment variables (defined in its ~/.bashrc): 73 | 74 | * **GIT_SCRIPTS**: directory where the _git_ sync scripts are located 75 | * **GIT_BASE**: directory where the _git_ repositories are stored. 76 | * **GIT_SVN_SYNC_BASE**: directory where the sync repositories are stored. 77 | * **GIT_SVN_SYNC_BRANCH**: name of the branch that is synchronized 78 | with subversion. 79 | 80 | This repository should be cloned in the directory **GIT_SCRIPTS**. 81 | 82 | ### SVN User 83 | 84 | Git needs to have write access to subversion. 85 | 86 | ### Git config 87 | 88 | For the git user that will sync with svn 89 | 90 | git config --global user.email "the@email" 91 | git config --global user.name "Git User" 92 | 93 | ### New project 94 | 95 | Each project in subversion can be initialized with the 96 | install/git-repository-from-svn.sh script. It makes sure that the 97 | initial setup is carried and that the hooks are activated. 98 | 99 | 100 | -------------------------------------------------------------------------------- /git-sync-with-svn.sh: -------------------------------------------------------------------------------- 1 | # -*- mode: Shell-script-*- 2 | #!/usr/bin/bash 3 | # 4 | # Author: Mario Fernandez 5 | # 6 | # Syncs git repository with subversion, using an extra git client. 7 | # 8 | # The client is a clone of the git repo. It has two branches: 9 | # - master: It is sync'ed with the git repo. Should always 10 | # fast-forward. 11 | # - GIT_SVN_SYNC_BRANCH: Sync'ed with SVN (via git-svn). Noone else 12 | # can write to svn. 13 | # 14 | # The changes from the git repo are pulled into master, and then 15 | # merged to the svn sync branch. This branch is then synchronized with 16 | # subversion. 17 | # 18 | # Required environment variabless: 19 | # - GIT_SCRIPTS: directory where the git sync scripts are located 20 | # - GIT_SVN_SYNC_BASE: directory where the sync repositories are 21 | # stored. 22 | # - GIT_SVN_SYNC_BRANCH: name of the branch that is synchronized with 23 | # subversion. 24 | # 25 | # Usage: git-sync-with-svn.sh project_name 26 | 27 | destination=receiver@host.com 28 | project=${1?No project provided} 29 | location=${GIT_SVN_SYNC_BASE}/${project} 30 | 31 | if [ ! -d $location ] ; then 32 | echo "The folder where the synchronization repository is supposed to be does not exist" 33 | exit 1 34 | fi 35 | 36 | unset GIT_DIR 37 | cd $location 38 | 39 | report () { 40 | echo $1 41 | sh ${GIT_SCRIPTS}/report-error.sh $destination "$project" "$1" 42 | } 43 | 44 | # Get changes from git repository 45 | echo "Getting changes from git repository" 46 | git checkout master || { report "Could not switch to master" ; exit 1; } 47 | 48 | if [ -n "$(git status --porcelain)" ] ; then 49 | echo "Workspace is dirty. Clean it up (i.e with git reset --hard HEAD) before continuing" 50 | exit 1 51 | fi 52 | 53 | git pull --ff-only origin master || { report "Could not pull changes from git repository" ; exit 1; } 54 | 55 | # Synchronize with SVN 56 | echo "Synchronizing with SVN" 57 | git checkout ${GIT_SVN_SYNC_BRANCH} || { report "Could not switch to sync branch" ; exit 1; } 58 | # In case of conflicts, take the master, as we are sure that this is 59 | # the correct branch 60 | git merge -Xtheirs master || { report "Could not merge changes into sync branch" ; exit 1; } 61 | git svn dcommit || { report "Could not send changes to svn repository" ; exit 1; } 62 | -------------------------------------------------------------------------------- /install/git-repository-from-svn.sh: -------------------------------------------------------------------------------- 1 | # -*- mode: Shell-script-*- 2 | #!/usr/bin/bash 3 | # 4 | # Author: Mario Fernandez 5 | # 6 | # Initializes a git repository that is synchronized with an existing 7 | # svn repository. 8 | # 9 | # Required environment variabless: 10 | # - GIT_SCRIPTS: directory where the git sync scripts are located 11 | # - GIT_BASE: directory where the git repositories are 12 | # stored. 13 | # - GIT_SVN_SYNC_BASE: directory where the sync repositories are 14 | # stored. 15 | # - GIT_SVN_SYNC_BRANCH: name of the branch that is synchronized with 16 | # subversion. 17 | # 18 | # Usage: git-repository-from-svn.sh project svn_url 19 | 20 | if [ -z "${GIT_SCRIPTS}" ] || [ -z "${GIT_BASE}" ] || [ -z "${GIT_SVN_SYNC_BASE}" ] || [ -z "${GIT_SVN_SYNC_BRANCH}" ] ; then 21 | echo "The following variables are required for the synchronization to work: GIT_SCRIPTS GIT_SVN_SYNC_BASE GIT_SVN_SYNC_BRANCH" 22 | exit 1 23 | fi 24 | 25 | project=${1?No project name provided} 26 | svn_url=${2?No svn url provided} 27 | location=${GIT_BASE}/${project}.git 28 | client=${GIT_SVN_SYNC_BASE}/${project} 29 | 30 | if [ -d $location ] ; then 31 | echo "The folder for the git server already exists" 32 | exit 1 33 | fi 34 | 35 | if [ -d $client ] ; then 36 | echo "The folder for the git sync client already exists" 37 | exit 1 38 | fi 39 | 40 | # Git Server 41 | git init --bare ${location} || { echo "Could not initialize git server at ${location}" ; exit 1; } 42 | 43 | # Sync client 44 | git svn clone ${svn_url} ${client} || { echo "Could not clone svn repository at ${svn_url} in ${client}" ; exit 1; } 45 | 46 | cd ${client} 47 | git remote add origin ${location} || { echo "Could not set up server as remote from sync" ; exit 1; } 48 | git push origin master || { echo "Could not sync client with server" ; exit 1; } 49 | git branch ${GIT_SVN_SYNC_BRANCH} || { echo "Could not create svn sync branch" ; exit 1; } 50 | 51 | # Set up hooks 52 | for hook in pre-receive post-receive ; do 53 | ln -s ${GIT_SCRIPTS}/server-hooks/${hook} ${location}/hooks 54 | done 55 | 56 | for hook in pre-receive pre-commit ; do 57 | ln -s ${GIT_SCRIPTS}/sync-client-hooks/always-reject ${client}/.git/hooks/${hook} 58 | done 59 | -------------------------------------------------------------------------------- /report-error.sh: -------------------------------------------------------------------------------- 1 | # -*- mode: Shell-script-*- 2 | #!/usr/bin/bash 3 | # 4 | # Author: Mario Fernandez 5 | # 6 | # Sends an email with the error message obtained from syncing a repository. 7 | 8 | destination=${1?No destination provided} 9 | project=${2?No project provided} 10 | message=${3?No message provided} 11 | 12 | cat > /tmp/git-sync-failure <