
For many years in a row, only SVN was used as a version control system for a large number of projects. But the moment came when the number of developers on one of the projects increased markedly, the project was already launched, and you need to actively develop several features in parallel, and fix existing bugs online. A single trunk in SVN does not allow this, and the organization of branches in it also turns the life of developers into hell. Therefore, it was decided to move this project from SVN to Git.
1. Server for central repository
Despite the fact that Git is a distributed system, this does not eliminate the need for a central repository, with which all developers will eventually synchronize, and also from which both test builds will be deployed and production will be produced. Therefore, we need first of all a server. Since the project is commercial, then somehow you don’t really want to store the sources on foreign servers, so you need to raise your server to store git repositories. The server itself runs on Gentoo, so we need to put all the necessary software on it.
Here the choice is not particularly great - gitosis or gitolite. Since gitosis has not been developed for several years, the choice fell on gitolite.
1.1. Install gitolite
We put gitolite 3.03 on the server:
$ emerge gitolite
This creates a user git, which will own all future repositories.
')
1.2. Primary setup
Now we need to generate an rsa key for access to the admin repository (gitolite stores all settings in the git repository) and store the public key in a publicly accessible place:
$ ssh-keygen -t rsa $ cp ~/.ssh/id_rsa.pub /tmp/admin.pub
After that, you can actually initialize gitolite:
$ su git $ cd $ mkdir -p bin $ gitolite/install -ln $ gitolite setup -pk /tmp/admin.pub
1.3. Creating a repository for the project
The server is installed, we return to our user and we clone our repository with configs:
$ cd $ git clone git@server:gitolite-admin.git
Hereinafter server is the hostname of the server where gitolite is installed and the repositories are stored.
Open the gitolite-admin / conf / gitolite.conf file that appears and add to the end a description of the repository for our project (with only one user so far):
repo project RW+ = javer
After that we save our changes. Being in gitolite-admin, we execute:
$ git add . $ git commit -am "Repository for project added" $ git push origin master
gitolite automatically initializes all repositories that are described in the config and do not exist yet.
Everything, gitolite is installed and initially configured, the repository for our project is created, you can move on.
2. Import project from SVN
Directly convert SVN repository to Git by using the command
$ git svn clone
To do this, git must be compiled with perl support.
2.1. Determining the starting revision
Our Project Project is located in the SVN repository along with many other projects. Since the revision numbers are through to the entire repository, we find in the svn log the first commit, which concerns our project, and we remember. This is necessary to speed up the import, so that all revisions, starting with the first, are not scanned. In our case, this is revision 19815, so an option is added to the command above:
-r19815:HEAD
2.2. Matching SVN users with Git users
Next, we need to match SVN users with future Git users so that they are successfully replaced upon import. To do this, somewhere we create a authors file of approximately the following content:
javer = javer <javer@domain.tld> developer1 = developer1 <developer1@domain.tld> ...
Where user@domain.tld is the git user's e-mail (in git, each user is identified by name and email).
Accordingly, an option is added to the import command:
--authors-file=/path/to/authors
2.3. Eliminate unnecessary files
We go further. In our project there were random commits of large binary files that we don’t need in the new repository. When importing, they can be excluded with the option:
--ignore-paths="\.(avi|mov)$"
2.4. Additional options
We also need a user in SVN, on behalf of which the repository will be accessed:
--username javer
Add another option - no-metadata, which is needed so that in the commit log in each comment there are no additions like:
git-svn-id: svn://svn.domain.tld/repo/project/trunk@19815 e13dc095-444b-fa4e-8f24-06838a8318a5
In the SVN repository of our project, useful information was stored only on the trunk, a few branches contained a temporary code, which at one time, through incredible efforts, was still loaded with the trunk, so we don’t need them anymore.
2.5. Cloning a project from the SVN repository
Putting it all together and running:
$ cd $ mkdir project && cd project $ git svn clone -r19815:HEAD --authors-file=/path/to/authors --ignore-paths="\.(avi|mov)$" --username javer --no-metadata svn://svn.domain.tld/repo/project/trunk .
Where svn: //svn.domain.tld/repo/project/trunk is the address of the trunk of our project in the SVN repository.
The cloning process begins, the duration of which depends on the number of commits and their volume. In our case, there were about 4.5 thousand commits, and it took about two hours to clone them.
2.6. Exclude more unnecessary files and directories
Upon completion of the cloning in our project directory, we get a complete clone of the project with the entire commit history. After cloning, it may suddenly appear that we have also declined some directory that we do not need in the new repository, for example, because we will allocate it into a separate repository. Delete the directory and all references to it in history can be as follows:
$ git filter-branch --tree-filter 'rm -rf unneeded_directory' -f HEAD
This process is also quite long, since each commit is reviewed separately, and in our case it took about 1 second for each commit.
2.7. Remove empty commits
As a result of all previous actions, we received our cloned project with the entire history of commits, among which there are now empty commits, that is, commits without a single modified file. They appeared as a result of excluding some files through the ignore-paths option, or because of the subsequent filtering through tree-filter. To remove such empty commits do:
$ git filter-branch --commit-filter 'git_commit_non_empty_tree "$@"' HEAD
This operation takes about the same time as tree-filter.
2.8. Empty directories and svn: ignore
Next, we need to convert the former svn: ignore into the new .gitignore. This is done like this:
$ git svn create-ignore
Do not forget that git does not store information about directories, only about files, so in all empty directories you need to create an empty .gitignore file, then commit all these files:
$ git add . $ git commit -am "Added .gitignore"
2.9. Removing mention of SVN
Since our project moves from SVN to Git for good, we delete all references to SVN:
$ git branch -rd git-svn $ git config --remove-section svn-remote.svn $ git config --remove-section svn $ rm -rf .git/svn
2.10. svn: externals
In our project, some symfony plug-ins, both custom and public, were connected via svn: externals. Since there is no such mechanism in git, we will use submodules for this. With public plugins easier:
$ git submodule add git://github.com/propelorm/sfPropelORMPlugin.git plugins/sfPropelORMPlugin $ git submodule add git://github.com/n1k0/npAssetsOptimizerPlugin.git plugins/npAssetsOptimizerPlugin
It is a bit more difficult with your plugins - for them you need to create separate repositories as described above, and then also connect to our project in the same way:
$ git submodule add git@server:customPlugin.git plugins/customPlugin
After connecting the submodules, they must be cloned into the project directory:
$ git submodule update --init --recursive $ git commit -am "Added submodules: sfPropelORMPlugin, npAssetsOptimizerPlugin, customPlugin"
2.11. Sending a local copy of the project to the server
Before sending our project to the server to speed up this operation, we optimize it:
$ git gc
We connect our new repository to the project:
$ git remote add origin git@server:project.git
And finally, upload the local copy of the project to the server:
$ git push origin master
2.12. Submodules update in the future
Since, unlike svn: externals, each submodule points to a specific commit, with a simple update of the local copy via
$ git pull
the contents of the submodules will not be updated. Their update is as follows:
$ git submodule update
In case there were changes:
$ git submodule foreach git pull $ git commit -am "Updated submodules"
3. Setting repository access rights
3.1. User keys
Since access to the remote git repository is done via ssh, now each developer must generate an rsa key on his machine.
3.1.1. Linux / Unix
In the case of Linux / Unix or Git bash under Windows, this is done like this:
$ ssh-keygen -t rsa
After that, the received public key ~ / .ssh / id_rsa.pub is transferred to the repository admin.
3.1.2. Windows
In the case of Windows, you can also use puttygen, which can be downloaded here:
puttygen .
Run puttygen, click Generate, drag the mouse over the window until the key is generated, then indicate what the key is in the comment field, enter the password to access the key if necessary. After that, copy the contents of the Public key field, save to the file user.pub and transfer to the repository admin.
Then we press the Save private key and save this key in a secluded place for further use, for example, in TortoiseGit.
Also in the Conversions menu, select the Export OpenSSH key and save it to a file called C: \ Users \ USERNAME \ .ssh \ id_rsa, where USERNAME is your username in the system. We will need this key when using git from the command line.
3.2. Setting access rights
The user’s public keys obtained in the previous step are placed in the admin repository in the ~ / gitolite-admin / keydir / directory in files named USERNAME.pub, where USERNAME is the user name.
Since gitolite has quite wide customization capabilities, we use them to configure access rights to the repository of our project. To do this, edit the file ~ / gitolite-admin / conf / gitolite.conf and bring it to the form:
@owners = javer
@project_developers = user1 user2 user3
@deploy = root@production
repo project
- master$ = @project_developers
- refs/tags = @project_developers
RW+ = @project_developers @owners
R = @deploy
By this we give full access to the owners user group. For the project_developers group - also full access with the ability to create its own branches, with the exception of writing to the master branch and creating tags. For the deploy group, which is used for production deployment, we allow read-only access.
In the end, do not forget to save all changes:
$ git add . $ git commit -am "New users for project: user1, user2, user3..." $ git push origin master
4. Install and configure on the developer machines
The server part is completely ready, now it remains to install and configure the git-client on the developers' machines.
4.1. Linux / Unix
Everything is simple - install git with the help of your favorite package manager.
After installation, do not forget to specify your name and e-mail, the same that were used when importing from SVN:
$ git config --global user.name "javer" $ git config --global user.email "user@domain.tld"
4.2. Windows
There are several different clients here, so far I have stopped at TortoiseGit.
Before installing it, you must first install
msysgit , preferably the latest version, despite the Beta inscription. During installation, when I am asked to integrate into the system, I advise you to select the Git Bash and Command prompt option so that you can run git from both Git bash and the command line.
After that we install
TortoiseGit . I recommend installing the latest stable version, but not nightly-build.
Now we go into the TortoiseGit settings (right click on any directory and TortoiseGit-> Settings), we find the Git section there and on the right in the User Info block we enter our name and e-mail.
5. Relocation completed. Getting Started
That's all, the process of moving from SVN to Git is complete.
Each developer clones his project to the machine and starts working with it.
I would advise developers to read these articles: