Skip to content

Commit 4c12f40

Browse files
author
Mario Fernandez
committed
Initial commit with the scripts to synchronize git with svn
This contains multiple scripts: - A script to synchronize an existing git repository with subversion via a git synch client - hooks for the git server to trigger the sync after a push - a hook for the client to reject every manual change - A script to create a new git server repository, along with the git synch client, starting from an existing subversion repository.
0 parents  commit 4c12f40

File tree

7 files changed

+285
-0
lines changed

7 files changed

+285
-0
lines changed

Diff for: README.markdown

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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+

Diff for: git-sync-with-svn.sh

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
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; }

Diff for: install/git-repository-from-svn.sh

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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

Diff for: report-error.sh

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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 <<EOF
13+
The project $project could not be correctly synchronized. The output of the script was:
14+
15+
$message
16+
EOF
17+
18+
subject="Git-SVN failed for project $project"
19+
mail -s "$subject" $destination < /tmp/git-sync-failure

Diff for: server-hooks/post-receive

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# -*- mode: Shell-script-*-
2+
#!/usr/bin/bash
3+
#
4+
# This hook is intended to be installed for a git server. It calls a
5+
# script that synchronizes every change with subversion.
6+
#
7+
# Required environment variables:
8+
# - GIT_SCRIPTS: directory where the git sync scripts are located
9+
#
10+
# Author: Mario Fernandez
11+
12+
master="refs/heads/master"
13+
14+
while read oldrev newrev refname
15+
do
16+
if [ "$master" == "$refname" ] ; then
17+
sh ${GIT_SCRIPTS}/git-sync-with-svn.sh $(basename $PWD .git)
18+
fi
19+
done

Diff for: server-hooks/pre-receive

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# -*- mode: Shell-script-*-
2+
#!/usr/bin/bash
3+
#
4+
# This hook is intended to be installed for a git server. It calls a
5+
# script that synchronizes every change with subversion.
6+
#
7+
# Required environment variables:
8+
# - GIT_SCRIPTS: directory where the git sync scripts are located
9+
#
10+
# Author: Mario Fernandez
11+
12+
if [ -z "${GIT_SCRIPTS}" ] || [ -z "${GIT_SVN_SYNC_BASE}" ] || [ -z "${GIT_SVN_SYNC_BRANCH}" ] ; then
13+
echo "The following variables are required for the synchronization to work: GIT_SCRIPTS GIT_SVN_SYNC_BASE GIT_SVN_SYNC_BRANCH"
14+
exit 1
15+
fi
16+
17+
while read oldrev newrev refname
18+
do
19+
if [ "$refname" == "${GIT_SVN_SYNC_BRANCH}" ] ; then
20+
echo "It is not allowed to push a branch named ${GIT_SVN_SYNC_BRANCH} to avoid conflicts when syncing with subversion"
21+
exit 1
22+
fi
23+
done

Diff for: sync-client-hooks/always-reject

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# -*- mode: Shell-script-*-
2+
#!/usr/bin/bash
3+
#
4+
# Author: Mario Fernandez
5+
echo "The synchronization client does not accept manual modifications"
6+
exit 1

0 commit comments

Comments
 (0)