Local branching is very easy with Git, but with Subversion (SVN) some magic is needed to manage complex local working directories. When working on more than one feature or bug within one SVN branch, the changes can quickly become hard to manage and keep separate. If the change ends up being in the same file as another feature’s change, a real problem occurs when trying to commit the code separately. There are options to make sure changes don’t encroach on each other, but none of them are as simple and lightweight as local branching with Git. Since SVN does not have the concept of a pull request, code reviews might be done pre-commit, forcing the developer to keep local changes in a working directory until the review is complete and changes can be committed. In this situation, the following solutions for managing multiple local changesets might come in handy.
Solutions for managing multiple changes in Subversion
- Create a separate SVN branch
- Copy/paste working directory
- Manage multiple
- Git & SVN in the same working directory
The first and best option would be to create another SVN branch in the centralized repository to work in. Then, when the work is complete
svn merge --reintegrate into the main branch. This is the most manageable way to deal with multiple changes, but requires your team to allow any developer to create and manage their own branches separate from the trunk. This can be done by allowing developers to create and manage branches in a folder named after them, like
/svn/branches/kevin, or in a branches folder related to what they are working on like
Copy an existing branch
If creating a new branch is a feasible option then one can be created with
svn copy http://svn/trunk http://svn/branches/kevin/feature1 -m "create branch for feature1"
A branch can also be created from your working directory via
svn copy . http://svn/branches/kevin/feature1 -m "create branch for feature1"
With TortoiseSVN, you can create a branch from a working directory via
Branch/Tag..., or you can copy another branch in your SVN repository from the
Repository Browser by holding
Ctrl while dragging a branch folder to a new location.
Those who already manage branches in SVN would obviously be aware of this, but developers that don’t have the responsibility of managing branching and merging would need to know this moving forward.
Merge & Reintegrate
When work is complete in the feature branch, merge any revisions that are not present in the feature branch from the trunk, then reintegrate back into the trunk.
> svn switch http://svn/branches/kevin/feature1 > svn merge http://svn/trunk > svn commit -m "merge trunk into kevin/feature1" > svn switch http://svn/trunk > svn merge --reintegrate http://svn/branches/kevin/feature1 > svn commit -m "merge feature1 back into trunk"
This process can also be done easily with TortoiseSVN via
Tortoise SVN →
Reintegrate a branch. For more information on reintegrating branches, refer to the SVN Book.
If code reviews are done pre-commit, this solution would be a way to improve the code review process to act more like a Git pull request, by moving code reviews after the commit into the feature branch, but before the branch is reintegrated.
Copy/pasting a clean working directory to a new directory before working on a feature can be manageable, but is often too bulky of a process for large code bases.
- Don’t have to worry about creating “unnecessary” branches that you would probably delete or never look at again
- Having a clean working directory always at hand allows for quick merging, branching, reverting, etc. (you should always have a clean working copies of branches anyways)
- Paste action could take a long time
- Renaming folders to keep track of what you’re working on becomes a must and can be a pain when you have to kill all processes with handles in the directory to be renamed
- Doesn’t give you the kind of sandbox that creating a separate branch would
In a single working directory, files with local modifications can be grouped under different names by using SVN changelists. SVN changelists are ideal for simple features that will not end up having changes in the same file as another feature’s changes. To create a SVN changelist from a group of files use
> svn changelist my-first-changelist module1.js module2.js A [my-first-changelist] module1.js A [my-first-changelist] module2.js > svn status --- Changelist 'my-first-changelist': M module1.js M module2.js
This can also be done with TortoiseSVN via
Check for modifications, selecting the files you want to add to a changelist, and selecting
Move to changelist →
<new changelist>. At that point the files will be grouped under the new changelist’s name.
This is not really a good option, but it is an option nonetheless.
When finished working on a feature in a working directory (or before switching focus to work on something else), create a
.patch file containing all the current modifications and then revert the working directory. Then when you want to work on the feature contained in the
.patch file, just create another
.patch file with any modifications in the current directory, revert the working directory, and apply the
.patch file so you can continue working on any changes.
git init in any folder will create a local Git repository in that directory. This allows for easy management of local branches, and if you are new to Git or are looking to switch from SVN to Git at some point, this is a good way to get your feet wet. Some might view this as more work than it’s worth, but if you are up for it, the following is my workflow when managing a Git repository inside a SVN working directory.
If you are new to Git, here is a great guide to get you started.
Create a new Git repository
Start with a clean SVN working directory, then initialize and empty Git repo in the working directory.
> git init
Now you will see a
.git folder alongside your
.svn folder. Two source controls in one directory!
Create a branch
Create a branch for a feature you will work on and then checkout that branch.
> git branch feature1 > git checkout feature1
The create and checkout can also be done with one command.
> git checkout -b feature1
You can commit you local changes in a Git branch as often as you want to keep track of your change history.
> git add . > git commit -m "committing some changes"
Then after working in that branch for a while, you might start working on another feature and end up with multiple branches. Though, at some point you will want to update from SVN.
Before updating from SVN, commit any changes to the current Git branch, then (1) checkout the
master branch, (2) update from SVN, and (3) commit the updates to the
master Git branch.
> git checkout master > svn up > git commit -m "svn update"
Push SVN update to Git branches
At this point the updates from SVN are only in the
master branch, and not in the
feature1 branch, so we will need to
feature1 branch to have a new base of
master’s most recent commit. If you are unfamiliar with
git rebase, there is a great visualization here.
> git checkout feature1 > git rebase master
You will then want to rebase all other Git branches to
master as well, or else whenever you checkout a different Git branch SVN will show changes where it expected the files from the SVN update to have been changed.
If you are used to handling merge conflicts with TortoiseSVN, then you might want to use TortioseGit when rebasing as it can alleviate the stress of not knowing how to handle rebase conflicts via the Git bash.
Committing changes to SVN
After rebasing our feature branch we can safely merge our Git branch into
master and then commit to the central SVN repository.
> git checkout master > git merge feature1 > svn commit -m "feature1 to svn"
feature1 Git branch can now be deleted since it is completed.
- Take the time to configure a
.gitignorefile so that any build artifacts will be ignored by Git. Common
.gitignorefiles can be found here.
- Consider adding any Git related items to the SVN repository’s ignore list, so that you do not accidentally commit them to SVN.
Drawbacks to using Git in an SVN directory
- Extra work
- Required knowledge of Git
- All Git branches must be rebased after an SVN update, so that pre-commit code reviews that require a later update would not show changes from the SVN update
More information on using Git & SVN together
- A great tutorial on how to use Git in an SVN working directory
- SubGit is a tool to help gently migrate from SVN to Git by creating a bidirectional Subversion to Git replication
- git-svn is a way to interface directly with a SVN repository via git (manual)
Git’s cheap local branching is the easiest way to deal with multiple changes locally, but when SVN is the version control of choice, other methods like SVN branching, copy/pasting working directories, using
svn changelist, using
.patch files, and/or integrating a Git repository in a SVN working directory should be part of the workflow to correctly handle a complex working directory. Pre-commit code reviews can spoil a workflow when working in SVN without the option of creating a branch for each code reviewable changeset. Giving developers the option to create their own SVN branches is definitely worth it, even if only to remove the pain of having to deal with multiple changesets via the other options mentioned.