{"id":13850750,"url":"https://github.com/mrts/git-svn-bridge","last_synced_at":"2026-03-09T11:03:04.875Z","repository":{"id":4292383,"uuid":"5422799","full_name":"mrts/git-svn-bridge","owner":"mrts","description":"Instructions, scripts and utility programs for synchronizing/mirroring changes between git and Subversion","archived":false,"fork":false,"pushed_at":"2018-04-05T14:06:23.000Z","size":104,"stargazers_count":124,"open_issues_count":1,"forks_count":32,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-04-30T07:36:29.474Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrts.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-08-15T06:26:06.000Z","updated_at":"2025-02-07T12:11:23.000Z","dependencies_parsed_at":"2022-08-06T16:00:48.048Z","dependency_job_id":null,"html_url":"https://github.com/mrts/git-svn-bridge","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mrts/git-svn-bridge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrts%2Fgit-svn-bridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrts%2Fgit-svn-bridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrts%2Fgit-svn-bridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrts%2Fgit-svn-bridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrts","download_url":"https://codeload.github.com/mrts/git-svn-bridge/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrts%2Fgit-svn-bridge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30291844,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T02:57:19.223Z","status":"ssl_error","status_checked_at":"2026-03-09T02:56:26.373Z","response_time":61,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T21:00:17.631Z","updated_at":"2026-03-09T11:03:04.856Z","avatar_url":"https://github.com/mrts.png","language":"C#","funding_links":[],"categories":["C# #"],"sub_categories":[],"readme":"*git*-*Subversion* bridge\n=========================\n\nIt should be quite obvious to GitHub users why our team likes *git* - we\nbranch, diff, merge and rebase heavily, work offline, stash, amend commits and\ndo other *git*-specific things that make *git* so fun and useful.\n\nHowever, our corporate standard is *Subversion*. It is simple and\nreliable, the history is immutable and the central repository lives in the\nsecure datacenter. Project managers and salespeople can use *TortoiseSVN* to\naccess the project repository as well, keeping project documents neatly\norganized alongside source repositories; administrators have easy tools for\nmanaging authorization and authentication etc. Everyone is generally happy with\nit.\n\nTo reap the best of both worlds, we have setup a *git*-*Subversion*\nbridge that synchronizes changes between our team *git* repository and\nthe corporate *Subversion* repository. The obvious requirement is that\nour *git* usage has to be transparent to other *Subversion* users, not\ninterfere with their work or damage the corporate repository.\n\nThe setup looks like this:\n\n![image](https://raw.github.com/mrts/git-svn-bridge/master/doc/git-Subversion_bridge.png)\n\nWe have used this setup in production for more than a year (albeit in a\nsomewhat simpler incarnation), so we have sorted out most of the problem points\nand are content with it. It may also work for you in a similar situation.\n\nThis document gives an overview of the setup.\n\nIf you have administrator access to the *Subversion* repository (we\ndon't), be sure to check out [SubGit](http://subgit.com/). It may or may\nnot make the setup simpler.\n\nOverview and caveats\n--------------------\n\n-   Each update of *master* in the central *git* repository will trigger\n    synchronization with *Subversion*. Additionally, there is a *cron* job that\n    runs the synchronization every *n* minutes (so that the repository is\n    updated even if there are no commits at *git* side). Concurrent\n    synchronization is properly guarded with a lock in the bundled\n    synchronization script.\n\n-   There is no exchange of branches between *git* and *Subversion*. The\n    *git* side tracks the trunk or any other main *Subversion* branch.\n    Branching happens at *git* side with short-lived task branches that\n    need not to be shared with *Subversion* users. Separate *git*\n    repositories are used for tracking other long-lived *Subversion*\n    branches.\n\n-   As *Subversion* history is linear, *git* merge commits will be squashed\n    into a single commit (see examples below). For us this is no problem as,\n    in the spirit of continuous integration, we consider the task branches to\n    be lightweight, ephemeral \"units of work\" that can go to mainline in a\n    single chunk and as the branch history is retained in *git*.\n\n-   To properly set author information in commits between *git* and\n    *Subversion*, *Subversion* user passwords need to be available to\n    the synchronization script. A fairly secure program,\n    `git-svn-auth-manager`, that keeps passwords in an encrypted\n    *SQLite* database is bundled and the synchronization script uses\n    that by default (see description below).\n\n-   *git* history is duplicated as commits first go up to and then come\n    back down again with a `git-svn-id` from *Subversion*. Although this\n    may sound confusing it has not been a big problem in practice (see\n    examples below; note that `--no-ff` is used to record the merges).\n    *Subversion* history remains clean.\n\n-   Rewriting history on *master* will probably mess up the\n    *git*-*Subversion* synchronization so it is disabled with the update\n    hook in the central *git* repository (we haven't tried though, this\n    just seems a sane precaution).\n\n-   If the project is Windows-only then the *git* bridge repo must be\n    configured to retain Windows line endings. (*TODO: describe how.*)\n\n### Subversion's view on history\n\nSquashed branch merge commit to *master* from *git* (see `dave.sh` below):\n\n    $ svn log trunk@r9 -l 1\n    ------------------------------------------------------------------------\n    r9 | dave | 2012-08-26 13:22:39 +0300 (Sun, 26 Aug 2012) | 10 lines\n    \n    2012-08-26 13:22:36 +0300 | Merge branch 'payment-support'\n     [Dave]\n    2012-08-26 13:22:36 +0300 | Add storage encryption for payments\n     [Dave]\n    2012-08-26 13:22:36 +0300 | Implement credit card payments\n     [Dave]\n    2012-08-26 13:22:36 +0300 | Implement PayPal payments\n     [Dave]\n    2012-08-26 13:22:36 +0300 | Add payment processing interface\n     [Dave]\n    ------------------------------------------------------------------------\n\nSingle commit to *master* from *git* (see `carol.sh` below):\n\n    $ svn log trunk@r8 -l 1\n    ------------------------------------------------------------------------\n    r8 | carol | 2012-08-26 13:22:36 +0300 (Sun, 26 Aug 2012) | 2 lines\n    \n    2012-08-26 13:22:35 +0300 | Use template filters to represent amounts in localized format\n     [Carol]\n    ------------------------------------------------------------------------\n\n### Git's view on history\n\nSingle commit before synchronization:\n\n    $ git log a165c -1\n    commit a165c9857eebb168e44b22278950cd930259394c\n    Author: Carol \u003ccarol@company.com\u003e\n    Date:   Sun Aug 26 13:22:35 2012 +0300\n    \n        Use template filters to represent amounts in localized format\n\nAfter synchronization, it will be duplicated with another commit that has come\ndown from *Subversion*:\n\n    $ git log\n    ...\n    commit 10fb01c123851b02f2105c98cb7c9adc47a1bb39\n    Merge: fc656d9 a165c98\n    Author: Carol \u003ccarol@company.com\u003e\n    Date:   Sun Aug 26 13:22:36 2012 +0300\n    \n        2012-08-26 13:22:35 +0300 | Use template filters to represent amounts in localized format\n         [Carol]\n        \n        git-svn-id: svn://localhost/trunk@8 49763079-ba47-4a7b-95a0-4af80b88d9d8\n    ...\n    commit a165c9857eebb168e44b22278950cd930259394c\n    Author: Carol \u003ccarol@company.com\u003e\n    Date:   Sun Aug 26 13:22:35 2012 +0300\n    \n        Use template filters to represent amounts in localized format\n    ...\n\nFor each branch merge, an additional squashed merge commit will come down from\n*Subversion* as shown in the previous section.\n\nSetup\n-----\n\nThe following walkthrough is provided both for documentation and for\nhands-on testing. All of this can be run in one go with the [test\nscript](http://github.com/mrts/git-svn-bridge/blob/master/test/run-test.sh).\nAfter you have prepared the envrionment, new bridge repositories for other\n*Subversion* branches can be set up with the [branch setup script](http://github.com/mrts/git-svn-bridge/blob/master/scripts/setup-svn-branch-git-bridge.sh).\n\nStart by creating the bridge user (*use your actual email address instead of\nYOUREMAIL@gmail.com, it is used later during setup and testing*):\n\n    $ sudo adduser git-svn-bridge\n    $ sudo su git-svn-bridge\n    $ set -u\n    $ YOUR_EMAIL=YOUREMAIL@gmail.com\n    $ git config --global user.name \"Git-SVN Bridge (GIT SIDE)\"\n    $ git config --global user.email \"$YOUR_EMAIL\"\n    $ cd\n    $ mkdir {bin,git,svn,test}\n\n### Subversion\n\nAssure that *Subversion* caches passwords (*only last git-svn-auth-manager\nreset user password will be cached; let me know if this does not meet your\nsecurity requirements, there are ways around this*):\n\n    $ echo 'store-plaintext-passwords = yes' \u003e\u003e ~/.subversion/servers\n\nCreate the *Subversion* repository (*in real life you would simply use the\nexisting central Subversion repository*):\n\n    $ cd ~/svn\n    $ svnadmin create svn-repo\n    $ svn co file://`pwd`/svn-repo svn-checkout\n    Checked out revision 0.\n\nCommit a test revision to *Subversion*:\n\n    $ cd svn-checkout\n    $ mkdir -p trunk/src\n    $ echo 'int main() { return 0; }' \u003e trunk/src/main.cpp\n    $ svn add trunk\n    A         trunk\n    A         trunk/src\n    A         trunk/src/main.cpp\n    $ svn ci -m \"First commit.\"\n    Adding         trunk\n    Adding         trunk/src\n    Adding         trunk/src/main.cpp\n    Transmitting file data .\n    Committed revision 1.\n\nSetup `svnserve` to serve the repository:\n\n    $ cd ~/svn\n\n    $ SVNSERVE_PIDFILE=\"$HOME/svn/svnserve.pid\"\n    $ SVNSERVE_LOGFILE=\"$HOME/svn/svnserve.log\"\n    $ SVNSERVE_CONFFILE=\"$HOME/svn/svnserve.conf\"\n    $ SVNSERVE_USERSFILE=\"$HOME/svn/svnserve.users\"\n    \n    $ \u003e\u003e $SVNSERVE_LOGFILE\n    \n    $ cat \u003e \"$SVNSERVE_CONFFILE\" \u003c\u003c EOT\n    [general]\n    realm = git-SVN test\n    anon-access = none\n    password-db = $SVNSERVE_USERSFILE\n    EOT\n    \n    $ cat \u003e \"$SVNSERVE_USERSFILE\" \u003c\u003c EOT\n    [users]\n    git-svn-bridge = git-svn-bridge\n    alice = alice\n    bob = bob\n    carol = carol\n    dave = dave\n    EOT\n    \n    $ TAB=\"`printf '\\t'`\"\n    \n    $ cat \u003e ~/svn/Makefile \u003c\u003c EOT\n    svnserve-start:\n    ${TAB}svnserve -d \\\\\n    ${TAB}${TAB}--pid-file \"$SVNSERVE_PIDFILE\" \\\\\n    ${TAB}${TAB}--log-file \"$SVNSERVE_LOGFILE\" \\\\\n    ${TAB}${TAB}--config-file \"$SVNSERVE_CONFFILE\" \\\\\n    ${TAB}${TAB}-r ~/svn/svn-repo\n    \n    svnserve-stop:\n    ${TAB}kill \\`cat \"$SVNSERVE_PIDFILE\"\\`\n    EOT\n\nStart `svnserve`:\n\n    $ make svnserve-start\n\n### Git\n\nSetup the central repository that *git* users will use:\n\n    $ cd ~/git\n    $ git init --bare git-central-repo-trunk.git\n    Initialized empty Git repository in /home/git-svn-bridge/git/git-central-repo-trunk.git/\n    $ cd git-central-repo-trunk.git\n    $ git remote add svn-bridge ../git-svn-bridge-trunk\n\nSetup the *git*-*Subversion* bridge repository:\n\n    $ cd ~/git\n    $ SVN_REPO_URL=\"svn://localhost/trunk\"\n    $ git svn init --prefix=svn/ $SVN_REPO_URL git-svn-bridge-trunk\n    Initialized empty Git repository in /home/git-svn-bridge/git/git-svn-bridge-trunk/.git/\n\nFetch changes from *Subversion*:\n\n    $ cd git-svn-bridge-trunk\n    $ AUTHORS='/tmp/git-svn-bridge-authors'\n    $ echo \"git-svn-bridge = Git SVN Bridge \u003c${YOUR_EMAIL}\u003e\" \u003e $AUTHORS\n    $ git svn fetch --authors-file=\"$AUTHORS\" --log-window-size 10000\n    Authentication realm: \u003csvn://localhost:3690\u003e git-SVN test\n    Password for 'git-svn-bridge': git-svn-bridge\n       A   src/main.cpp\n    r1 = 061725282bdccf7f4a8efa66ee34b195ca7070fc (refs/remotes/svn/git-svn)\n    Checked out HEAD:\n      file:///home/git-svn-bridge/svn/svn-repo/trunk r1\n\nVerify that the result is OK:\n\n    $ git branch -a -v\n    * master              0617252 First commit.\n      remotes/svn/git-svn 0617252 First commit.\n\nAdd the central repository as a remote to the bridge repository and push\nchanges from *Subversion* to the central repository:\n\n    $ git remote add git-central-repo ../git-central-repo-trunk.git\n    $ git push --all git-central-repo\n    Counting objects: 4, done.\n    Writing objects: 100% (4/4), 332 bytes, done.\n    Total 4 (delta 0), reused 0 (delta 0)\n    Unpacking objects: 100% (4/4), done.\n    To ../git-central-repo-trunk.git\n     * [new branch]      master -\u003e master\n\nClone the central repository and verify that the *Subversion* test\ncommit is there:\n\n    $ cd ~/git\n    $ git clone git-central-repo-trunk.git git-central-repo-clone\n    Cloning into 'git-central-repo-clone'...\n    done.\n\n    $ cd git-central-repo-clone\n    $ git log\n    commit 061725282bdccf7f4a8efa66ee34b195ca7070fc\n    Author: git-svn-bridge \u003cgit-svn-bridge\u003e\n    Date:   Wed Aug 15 11:38:57 2012 +0000\n\n       First commit.\n\n       git-svn-id: file:///home/git-svn-bridge/svn/svn-repo/trunk@1 b4f7b086-5416-...\n\nCreate the *git* hook that blocks non-fast-forward commits in the\ncentral repository:\n\n    $ cd ~/git/git-central-repo-trunk.git\n    $ cat \u003e hooks/update \u003c\u003c 'EOT'\n    #!/bin/bash\n    set -u\n    refname=$1\n    shaold=$2\n    shanew=$3\n\n    # we are only interested in commits to master\n    [[ \"$refname\" = \"refs/heads/master\" ]] || exit 0\n\n    # don't allow non-fast-forward commits\n    if [[ $(git merge-base \"$shanew\" \"$shaold\") != \"$shaold\" ]]; then\n        echo \"Non-fast-forward commits to master are not allowed\"\n        exit 1\n    fi\n    EOT\n\n    $ chmod 755 hooks/update\n\nCreate the *git* hook that triggers synchronization:\n\n    $ cat \u003e hooks/post-update \u003c\u003c 'EOT'\n    #!/bin/bash\n\n    # trigger synchronization only on commit to master\n    for arg in \"$@\"; do\n        if [[ \"$arg\" = \"refs/heads/master\" ]]; then\n            /home/git-svn-bridge/bin/synchronize-git-svn.sh GIT_HOOK\n            exit $?\n        fi\n    done\n    EOT\n\n    $ chmod 755 hooks/post-update\n\n    $ cat \u003e ~/bin/synchronize-git-svn.sh \u003c\u003c 'EOT'\n    # test script to verify that the git hook works properly\n    echo \"Commit from $1 to master\" \u003e /tmp/test-synchronize-git-svn\n    exit 1 # test that error exit does not abort the update\n    EOT\n\n    $ chmod 755 ~/bin/synchronize-git-svn.sh\n\nTest that the hook works:\n\n    $ cd ~/git/git-central-repo-clone\n    $ echo \"void do_nothing() { }\" \u003e\u003e src/main.cpp\n\n    $ git commit -am \"Update main.cpp\"\n    [master 2c833e2] Update main.cpp\n     1 file changed, 1 insertion(+)\n\n    $ git push\n    Counting objects: 7, done.\n    Writing objects: 100% (4/4), 341 bytes, done.\n    Total 4 (delta 0), reused 0 (delta 0)\n    Unpacking objects: 100% (4/4), done.\n    To /home/git-svn-bridge/git/git-central-repo-trunk.git\n       5b73892..2c833e2  master -\u003e master\n\n    $ cat /tmp/test-synchronize-git-svn\n    Commit from GIT_HOOK to master\n\nVerify that non-fast-forward commits to *master* are not allowed:\n\n    $ echo \"void do_nothing() { }\" \u003e\u003e src/main.cpp\n    $ git add src/\n    $ git commit --amend\n    [master d2f9a16] Update main.cpp\n     1 file changed, 2 insertions(+)\n\n    $ git push --force\n    Counting objects: 7, done.\n    Compressing objects: 100% (2/2), done.\n    Writing objects: 100% (4/4), 345 bytes, done.\n    Total 4 (delta 0), reused 0 (delta 0)\n    Unpacking objects: 100% (4/4), done.\n    remote: Non-fast-forward commits to master are not allowed\n    remote: error: hook declined to update refs/heads/master\n    To /home/git-svn-bridge/git/git-central-repo-trunk.git\n     ! [remote rejected] master -\u003e master (hook declined)\n    error: failed to push some refs to '/home/git-svn-bridge/git/git-central-repo-trunk.git'\n\n    $ git reset --hard origin/master\n\nSo far, so good. Let's wire in the real synchronization utilities now.\n\n### Synchronization utilities\n\nReal synchronization relies on\n\n-   the [synchronization\n    script](https://github.com/mrts/git-svn-bridge/blob/master/scripts/synchronize-git-svn.sh)\n    that controls the actual synchronization\n\n-   `git-svn-auth-manager`, a utility that manages *Subversion*\n    authentication and commit author mapping between *git* and\n    *Subversion* (**note that this is the sweet spot of the solution**);\n    it is described in more detail in a [separate\n    README](https://github.com/mrts/git-svn-bridge/blob/master/git-svn-auth-manager/README.rst).\n\nStart by cloning this repository:\n\n    $ cd ~/git\n    $ git clone --recursive git://github.com/mrts/git-svn-bridge.git github-git-svn-bridge-utils\n\n|**Warning to Ubuntu 16.04 users**|\n|---------------------------------|\n|The versions of *Mono* and *Git* provided in Ubuntu 16.04 cause problems as described below, please use [latest *Mono*](http://www.mono-project.com/docs/getting-started/install/linux/#debian-ubuntu-and-derivatives) and [*Git*](https://launchpad.net/~git-core/+archive/ubuntu/ppa) if you run into problems.|\n\n#### git-svn-auth-manager\n\nInstall required libraries and tools:\n\n    $ sudo apt-get install build-essential mono-devel libssl-dev tcl\n\nChange the encryption key:\n\n    $ cd github-git-svn-bridge-utils/git-svn-auth-manager\n    $ ENCRYPTION_KEY=`tr -dc '[:alnum:]' \u003c /dev/urandom | head -c 16`\n    $ sed -i \"s/CHANGETHIS/$ENCRYPTION_KEY/\" src/EncryptedUserRepository.cs\n    $ git diff src\n    ...\n    -               private const string ENCRYPTION_KEY = \"CHANGETHIS\";\n    +               private const string ENCRYPTION_KEY = \"TNwwmT2Wc3xVTole\";\n    ...\n\nThis is generally not necessary, but if you have an old database lying\naround from previous runs, it should be removed now as the encryption\nkey has changed (**careful with your actual user information**):\n\n    $ make mrproper\n    ...\n    rm -f ~/.config/git-svn-auth-manager/userinfo.db\n    ...\n\nBuild and install `git-svn-auth-manager`:\n\n    $ make install\n    ...\n    install -m 711 -D bin/git-svn-auth-manager ~/bin/git-svn-auth-manager\n\nVerify that it works:\n\n    $ ~/bin/git-svn-auth-manager\n    git-svn-auth-manager: too few, too many or invalid arguments\n\n    Helper utility for running a git-SVN bridge.\n    Manages SVN authentication for git and user mapping between git and SVN.\n\n    Usage:\n        either with a single non-option argument to output user\n        name and email suitable for `git --authors-prog`:\n\n            git-svn-auth-manager SVN_USERNAME\n\n        or with a single option to add users or change passwords:\n\n            git-svn-auth-manager OPTION=SVN_USERNAME\n\n        or with a single option and single non-option argument to reset\n        SVN authentication cache:\n\n            git-svn-auth-manager --reset-auth-for=EMAIL SVN_URL\n\n    Options:\n          --help, -h             Show help\n          --add-user, -a=VALUE   Add user information to the database\n          --change-passwd-for, -p=VALUE\n                                 Change user's password in the database\n          --reset-auth-for, -r=VALUE\n                                 Reset SVN auth cache with user's credentials;\n                                   option argument is user's email; SVN URL\n                                   required as non-option argument\n\n|**Note**|\n|--------|\n|If `~/bin/git-svn-auth-manager` crashes, then this is caused by *Mono* problems, please update *Mono* as described above|\n\nSecure the key - as encryption key is embedded in\n`git-svn-auth-manager`, it needs to be owned by root and be made\nexecute-only (`make install` *took care of the execute-only part already,\nbut let's be extra safe and explicit here*):\n\n    $ sudo chown root: ~/bin/git-svn-auth-manager\n    $ sudo chmod 711 ~/bin/git-svn-auth-manager\n    $ ls -l ~/bin/git-svn-auth-manager\n    -rwx--x--x 1 root root 697208 Aug 23 17:38 git-svn-auth-manager\n\nAdd the *git-svn-bridge* user for testing (*as before, use your actual email\naddress instead of YOUREMAIL@gmail.com and 'git-svn-bridge' as password*):\n\n    $ ~/bin/git-svn-auth-manager -a git-svn-bridge\n    Adding/overwriting SVN user git-svn-bridge\n    SVN password: git-svn-bridge\n    SVN password (confirm): git-svn-bridge\n    Email: YOUREMAIL@gmail.com\n    Name: Git-SVN Bridge\n\nVerify that the database is really encrypted:\n\n    $ echo .dump | sqlite3 ~/.config/git-svn-auth-manager/userinfo.db\n    PRAGMA foreign_keys=OFF;\n    BEGIN TRANSACTION;\n    /**** ERROR: (26) file is encrypted or is not a database *****/\n    ROLLBACK; -- due to errors\n\nCreate configuration files and enable email notifications to users for\n*Subversion* authentication failures (*substitute YOURGMAILPASSWORD with\nreal GMail password, the credentials will be used to authenticate\nGMail SMTP connections*):\n\n    $ make install_config\n    ...\n    install -m 600 -D config-just-enough ~/.config/git-svn-auth-manager/config\n    $ GITSVNAUTHMGRCONF=\"$HOME/.config/git-svn-auth-manager/config\"\n    $ sed -i \"s/username@gmail.com/${YOUR_EMAIL}/\" \"$GITSVNAUTHMGRCONF\"\n    $ sed -i 's/userpassword/YOURGMAILPASSWORD/' \"$GITSVNAUTHMGRCONF\"\n\n    $ cat \"$GITSVNAUTHMGRCONF\"\n    \u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n    \u003cconfiguration\u003e\n      \u003cappSettings\u003e\n        \u003cadd key=\"mail_sending_enabled\" value=\"true\" /\u003e\n        \u003cadd key=\"smtp_username\" value=\"YOUREMAIL@gmail.com\" /\u003e\n        \u003cadd key=\"smtp_password\" value=\"YOURGMAILPASSWORD\" /\u003e\n      \u003c/appSettings\u003e\n    \u003c/configuration\u003e\n\nTest that email sending works (the invalid SVN repository URL triggers\nan error that will cause the email to be sent):\n\n    $ ~/bin/git-svn-auth-manager -r ${YOUR_EMAIL} non-existing-path\n    git-svn-auth-manager: error email sent\n    git-svn-auth-manager: System.ApplicationException: Error executing `svn info --username \"git-svn-bridge\" --password \"*****\" \"non-existing-path\"`:\n    svn: 'non-existing-path' is not a working copy\n\nVerify that the error email arrives to your mailbox. It should look like [this\nsample](https://github.com/mrts/git-svn-bridge/blob/master/git-svn-auth-manager/mail-sample.txt).\n\n#### synchronize-git-svn.sh\n\nStart by copying the script and sample configuration to `~/bin`:\n\n    $ cd ~/bin\n    $ cp ../git/github-git-svn-bridge-utils/scripts/synchronize-git-svn.sh .\n    $ cp ../git/github-git-svn-bridge-utils/scripts/synchronize-git-svn.sh.config .\n\nAnd test it all:\n\n    $ ./synchronize-git-svn.sh\n\n    $ cd ~/git/git-central-repo-clone\n    $ git pull --rebase\n    $ echo \"void more_do_nothing() { }\" \u003e\u003e src/main.cpp\n    $ git commit -am \"Add more_do_nothing() to main.cpp\"\n    [master 0c6e72a] Add more_do_nothing() to main.cpp\n     1 file changed, 1 insertion(+)\n    $ git push\n    Counting objects: 7, done.\n    Compressing objects: 100% (2/2), done.\n    Writing objects: 100% (4/4), 374 bytes, done.\n    Total 4 (delta 0), reused 0 (delta 0)\n    Unpacking objects: 100% (4/4), done.\n    To /home/git-svn-bridge/git/git-central-repo-trunk.git\n       001c5c9..0c6e72a  master -\u003e master\n\n|**Note**|\n|--------|\n|If you see *Not a git repository* errors during push, then this is caused by problems with some versions of *Git*, please update *Git* as described above|\n\nWe are done with the setup now and will proceed with semi-realistic\nvirtual developer testing in the next section.\n\nTest synchronization\n--------------------\n\nThe scenario:\n\n-   Alice commits to *trunk* in *Subversion*\n\n-   Bob commits to *trunk* in *Subversion*\n\n-   Carol commits a number of changes directly to *master* and pushes in *git*\n    (triggers synchronization with the update hook)\n\n-   Dave works on the task branch *payment-support*, merges it to *master* and\n    pushes in *git* (triggers synchronization with the update hook)\n\n-   Finally, *cron* triggers synchronization explicitly.\n\nLet's setup the stage:\n\n    $ cd ~/test\n    $ mkdir {alice,bob,carol,dave}\n\n    $ for name in alice bob; do\n        echo \"Use '$name' as password and '$name@company.com' as email\"\n        ~/bin/git-svn-auth-manager -a $name\n        pushd $name\n        svn --username $name --password $name co $SVN_REPO_URL\n        popd\n    done\n\n    $ for name in carol dave; do\n        echo \"Use '$name' as password and '$name@company.com' as email\"\n        ~/bin/git-svn-auth-manager -a $name\n        pushd $name\n        git clone ~/git/git-central-repo-trunk.git git-trunk\n        cd git-trunk\n        git config user.name `~/bin/git-svn-auth-manager $name | sed 's/ \u003c.*//'`\n        git config user.email `~/bin/git-svn-auth-manager $name | sed 's/.*\u003c\\(.*\\)\u003e/\\1/'`\n        popd\n    done\n\n    $ cat \u003e alice.sh \u003c\u003c 'EOT'\n    #!/bin/bash\n    pushd alice/trunk\n    echo 'void alice() { }' \u003e\u003e src/alice.cpp\n    svn --username alice --password alice up\n    svn add src/alice.cpp\n    svn --username alice --password alice ci -m \"Protect the global cache with a mutex\"\n    popd\n    EOT\n\n    $ cat \u003e bob.sh \u003c\u003c 'EOT'\n    #!/bin/bash\n    pushd bob/trunk\n    echo 'void bob() { }' \u003e\u003e src/bob.cpp\n    svn --username bob --password bob up\n    svn add src/bob.cpp\n    svn --username bob --password bob ci -m \"Cache rendered templates\"\n    echo 'void bob2() { }' \u003e\u003e src/bob.cpp\n    svn --username bob --password bob up\n    svn --username bob --password bob ci -m \"Add tags to articles\"\n    popd\n    EOT\n\n    $ cat \u003e carol.sh \u003c\u003c 'EOT'\n    #!/bin/bash\n    pushd carol/git-trunk\n    echo 'void carol1() { }' \u003e\u003e src/carol.cpp\n    git add src/carol.cpp\n    git commit -m \"Add template tag library\"\n    echo 'void carol2() { }' \u003e\u003e src/carol.cpp\n    git commit -am \"Use template tag library for localized date format\"\n    git pull --rebase\n    git push\n    echo 'void carol3() { }' \u003e\u003e src/carol.cpp\n    git commit -am \"Use template filters to represent amounts in localized format\"\n    git pull --rebase\n    git push\n    popd\n    EOT\n\n    $ cat \u003e dave.sh \u003c\u003c 'EOT'\n    #!/bin/bash\n    # dave is working on a task branch\n    pushd dave/git-trunk\n    git checkout -b payment-support\n    echo 'void dave1() { }' \u003e\u003e src/dave.cpp\n    git add src/dave.cpp\n    git commit -m \"Add payment processing interface\"\n    echo 'void dave2() { }' \u003e\u003e src/dave.cpp\n    git commit -am \"Implement PayPal payments\"\n    echo 'void dave3() { }' \u003e\u003e src/dave.cpp\n    git commit -am \"Implement credit card payments\"\n    git fetch\n    git rebase origin/master\n    echo 'void dave4() { }' \u003e\u003e src/dave.cpp\n    git commit -am \"Add storage encryption for payments\"\n    git checkout master\n    git pull --rebase\n    git merge --no-ff payment-support\n    git push\n    popd\n    EOT\n\n    $ cat \u003e cron.sh \u003c\u003c 'EOT'\n    #!/bin/bash\n    ~/bin/synchronize-git-svn.sh CRON\n    EOT\n\n    $ chmod 755 *.sh\n\n    $ cat \u003e Makefile \u003c\u003c 'EOT'\n    all: alice bob carol dave cron\n    .PHONY: all alice bob carol dave cron\n\n    EOT\n\n    $ for name in alice bob carol dave cron; do\n        echo -e \"${name}:\\n\\t./${name}.sh\\n\" \u003e\u003e Makefile\n    done\n\nAnd now we let our imaginary developers loose to the source control land:\n\n    make\n\nOr, to test that mutual exclusion works, run the scripts in parallel:\n\n    make -j 5\n\nFinally, shut down ``svnserve``:\n\n    make -f ~/svn/Makefile svnserve-stop\n\nVerify that all went well (you should see clean history according to the\nexamples in the *Overview* section):\n\n    $ cd ~/svn/svn-checkout\n    $ svn up\n    $ svn log\n\n    $ cd ~/git/git-central-repo-clone\n    $ git pull --rebase\n    $ git log\n\nTest setting up repos for other branches\n----------------------------------------\n\n    $ make -f ~/svn/Makefile svnserve-start\n\n    $ cd ~/svn/svn-checkout\n    $ svn mkdir branches\n    $ svn cp trunk branches/1.x\n    $ svn ci -m \"Branch trunk to 1.x\"\n\n    $ cd ~/git\n    $ ./github-git-svn-bridge-utils/scripts/setup-svn-branch-git-bridge.sh\n    $ git clone central-repo-1.x.git central-repo-1.x-clone\n    $ cd central-repo-1.x-clone\n    $ git log\n    commit 095e7a01f102f79224df4283a67c4624986679a1\n    Author: git-svn-bridge@company.com \u003cgit-svn-bridge@company.com\u003e\n    Date:   Sun Aug 26 18:38:34 2012 +0000\n\n        Branch trunk to 1.x\n\n        git-svn-id: svn://localhost/branches/1.x@10 1db59d55-421c-46dd...\n\n    $ make -f ~/svn/Makefile svnserve-stop\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrts%2Fgit-svn-bridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrts%2Fgit-svn-bridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrts%2Fgit-svn-bridge/lists"}