= Subversion =
Subversion is an open source version control system

https://subversion.apache.org/

== Update ==
{{{
svn update
}}}

== Commit ==
{{{
svn commit -m 'message'
svn protected/* themes/* commit -m 'message'
}}}

== Add unversioned files ==
/usr/bin/svnaddunversioned.sh:
{{{#!highlight bash
#!/bin/sh
svn status | grep ? | awk '//{print $2}' | xargs -i svn add {}

# revert add 
svn revert addedFile
}}}

 * chmod 755 /usr/bin/svnaddunversioned.sh

== Branches ==
http://svnbook.red-bean.com/en/1.7/svn.branchmerge.using.html

{{{
svn copy http://svn.example.com/repos/calc/trunk http://svn.example.com/repos/calc/branches/my-calc-branch -m "Creating a private branch of /calc/trunk."
svn checkout http://svn.example.com/repos/calc/branches/my-calc-branch my-calc-branch 
}}}

== Ignore one folder ==
http://stackoverflow.com/questions/11293539/equivalent-of-gitignore-file-with-subversion

C# example:
 * cd ~/trunkx
 * svn propset svn:ignore "bin" .

== Ignore several files folders ==
http://sdesmedt.wordpress.com/2006/12/10/how-to-make-subversion-ignore-files-and-folders/

svnignore.txt
{{{
obj
bin
}}}

Issue the command to ignore the folders listed inside the file
 * svn propset svn:ignore -F svnignore.txt .
 * svn status --no-ignore # see ignored files
 * svn propedit svn:ignore . # shows ignore list on editor
 * SVN_EDITOR=nano
 * svn propedit svn:ignore . # uses nano
 * svn proplist -v -R # shows all properties recursively

Add to ~/.bashrc
{{{
# export SVN_EDITOR=vi
export SVN_EDITOR=nano
}}}

== Merge ==
 * cd mergeDestination
 * svn merge --accept postpone originFolder -r1234:HEAD #postpone to resolve conflicts later
 * svn status | grep '^C ' # only show files with conflits
 * svn resolve --accept working filex #accepts that working copy of filex does not have conflicts
 * svn update --accept postpone # updates working copy and automatically postpones conflict resolution

== Diff between branches ==
 * svn diff --summarize http://example/svn/repository/branch1 http://example/svn/repository/branch2 

== Commit with message(s) in file ==
 * nano messages.txt
 * svn commit -F messages.txt --username userx

== Files added or modified ==
 {{{ svn status | grep "^A\|^M" }}}

== Cherrypicking ==
 * svn diff -c 1234 ~/calc/trunk # see diff for revision 1234
 * svn merge -c 1234 ~/calc/trunk # merge revision 1234

== Solve conflict ==
 * svn resolved path/file # mark as solved

== Revert working copy ==
 * svn revert --recursive .

== Mark script as executable ==
 * svn propset svn:executable on xyz.sh

== Search logs by username ==
 * svn log --search username

== Get folder without content ==
 * svn ls
 * svn up "folderx" -N

== svnserve ==
The svnserve program is a lightweight server, capable of speaking to clients over TCP/IP using a custom, stateful protocol.
Listens port 3690
http://svnbook.red-bean.com/en/1.7/svn.serverconfig.svnserve.html
 * mkdir -p /tmp/svnserver
 * svnserve -d -r /tmp/svnserver
 * svnadmin create --fs-type fsfs /tmp/svnserver/testrepo
 * cd /tmp
 * svn checkout svn://localhost/testrepo
 * cd testrepo

'''/tmp/svnserver/test/conf/passwd'''
{{{
[users]
harry = 1234
sally = 1234
}}}

'''/tmp/svnserver/test/conf/svnserve.conf'''
{{{
[general]
password-db = passwd
[sasl]
use-sasl = false
}}}
{{{#!highlight bash
touch a
svn add a
svn commit a --username harry --password 1234
svn log
svn up .
svn log
svn ls
mkdir branch tag trunk
svn rm a
svn status
svn add branch/ tag/ trunk/
svn status
svn commit -m "Created branch tag trunk" --username harry --password 1234
}}}

{{{#!highlight bash
#!/bin/sh
mkdir -p /tmp/svnserver/testrepo
svnserve -d -r /tmp/svnserver
svnadmin create --fs-type fsfs /tmp/svnserver/testrepo
cd /tmp/svnserver/testrepo
echo -e "[users]\nharry = 1234\nsally = 1234\n" > conf/passwd
echo -e "[general]\npassword-db = passwd\n[sasl]\nuse-sasl = false\n" > conf/svnserve.conf
BASE_SVN_REPO=svn://localhost/testrepo
CREDENTIALS="--username harry --password 1234"
cd /tmp
svn checkout $BASE_SVN_REPO
cd testrepo 
mkdir branches tag trunk
svn add branches/ tag/ trunk/
svn status
svn commit -m "Created branches tag trunk" $CREDENTIALS
# Committed revision 1.
svn up .
BASE=/tmp/testrepo
cd $BASE/trunk
echo -e "trunk 1" > dummy.txt
svn add dummy.txt
svn commit -m "Created dummy1.txt in trunk" $CREDENTIALS
#Committed revision 2
svn up .
svn copy $BASE_SVN_REPO/trunk $BASE_SVN_REPO/branches/feature_branch1 $CREDENTIALS  -m "created feature branch1"
# Committed revision 3.
cd $BASE
svn up .
cd $BASE/branches/feature_branch1
echo -e "fb1 1" >> dummy.txt
svn commit -m "Changed dummy1.txt in feature_branch1" $CREDENTIALS
#Committed revision 4
svn up .
cd $BASE/trunk
echo -e "\ntrunk 2\n" >> dummy.txt 
svn commit -m "Changed trunk" $CREDENTIALS
svn up .
# Committed revision 5
# Synch from trunk to feature_branch1
cd $BASE/branches/feature_branch1/
svn up .
svn merge $BASE_SVN_REPO/trunk $CREDENTIALS --accept postpone 
# Conflict discovered in file 'dummy.txt'. postpone
vi dummy.txt
svn resolve --accept working dummy.txt
svn status
svn commit -m "synch merge from trunk to feature_branch1" $CREDENTIALS
svn up .
# Committed revision 6.
# create feature branch2 from feature branch1
svn copy $BASE_SVN_REPO/branches/feature_branch1 $BASE_SVN_REPO/branches/feature_branch2 $CREDENTIALS -m "created feature branch2 from feature branch1"
# Committed revision 7.
svn up .
cd $BASE
svn up .
cd $BASE/branches/feature_branch2/
echo -e "\nfb2 1\n" >> dummy.txt
svn commit -m "changed feature branch2" $CREDENTIALS
svn up . 
# Committed revision 8.
cd $BASE/branches/feature_branch1
echo -e "\nfb1 2\n" >> dummy.txt 
svn commit -m "changed feature branch1" $CREDENTIALS
svn up .
# Committed revision 9
# synch feat_branch2 from feat_branch1
cd $BASE/branches/feature_branch2/
svn up .
svn merge $BASE_SVN_REPO/branches/feature_branch1 $CREDENTIALS --accept postpone 
# Conflict discovered in file 'dummy.txt'. postpone
vi dummy.txt
svn resolve --accept working dummy.txt
svn status
svn commit -m "synch merge from feature_branch1 to feature_branch2" $CREDENTIALS
svn up .
# Committed revision 10.
cd $BASE/trunk
echo -e "\ntrunk 3\n" >> dummy.txt 
svn commit -m "Changed trunk" $CREDENTIALS
svn up .
# Committed revision 11.
# synch fb1 with trunk
cd $BASE/branches/feature_branch1
svn merge $BASE_SVN_REPO/trunk $CREDENTIALS --accept postpone 
vi dummy.txt # solve conflicts
svn resolve --accept working dummy.txt
svn commit -m "synch merge from parent trunk to feature branch1" $CREDENTIALS
# Committed revision 12.
svn up .
cd $BASE/trunk/
svn up .
svn merge $BASE_SVN_REPO/branches/feature_branch1 $CREDENTIALS --accept postpone 
svn status
svn commit -m "got changes into trunk from feature branch1 (reintegrate)" $CREDENTIALS
# Committed revision 13.
# terminate feature branch 1
svn rm $BASE_SVN_REPO/branches/feature_branch1 $CREDENTIALS -m "removed feature branch1"
# Committed revision 14.
cd $BASE
svn up .
# add new entry to trunk
cd $BASE/trunk
echo -e "\ntrunk 4\n" >> dummy.txt 
svn commit -m "changed trunk" $CREDENTIALS
#Committed revision 15
svn up . 

svn diff $BASE_SVN_REPO/trunk@13 $BASE_SVN_REPO/trunk@15  $CREDENTIALS 
# added trunk 4
svn diff $BASE_SVN_REPO/trunk@3 $BASE_SVN_REPO/trunk@13  $CREDENTIALS 
# added fb1 1 , trunk 2 , fb1 2 , trunk 3
# the synch from trunk to feature branch 2 should have ....
# trunk1, trunk2, trunk3, trunk4, fb2 1, fb1 1, fb1 2, 7 elements
# merge from integrate revision to head of trunk
cd $BASE/branches/feat_branch2
svn merge $BASE_SVN_REPO/trunk@13 $BASE_SVN_REPO/trunk@HEAD $CREDENTIALS --accept postpone 
# has all the elements

svn merge $BASE_SVN_REPO/trunk@15 $BASE_SVN_REPO/trunk@15 $CREDENTIALS --accept postpone
# only has 5 elements

# from fb1 creation to reintegration 13
svn merge $BASE_SVN_REPO/trunk@3 $BASE_SVN_REPO/trunk@13 $CREDENTIALS --accept postpone 
# has six elements, trunk 4 was added in r15
}}}

== Show svn diff side by side ==
{{{#!highlight bash
svn --diff-cmd "diff" --extensions "-y" diff
svn --diff-cmd "diff" --extensions "-y -W250" diff | colordiff | less -rS
svn --diff-cmd "diff" --extensions "-y -W250 --suppress-common-lines" diff | colordiff | less -rS
}}}

== Revert commited file to previous revision ==
{{{
#1234 previous revision
svn merge -c -1234 test.py
svn commit
svn up .
}}}

== Merge with revision range ==
{{{#!highlight bash
cd ~/tmp
svn co https://feature_branch
cd feature_branch
svn merge https://parent_branch -r start:end . --accept=postpone
# the range of revisions is ]start,end] so only start+1 is applied until end.
# sync merge
}}}

== svn help merge | less ==
Merge types:
 *  'sync' merge, merge from the parent branch to the feature branch is called a 'sync'
 * 'reintegrate' merge, merge from the feature branch to the parent branch is called a 'reintegrate'
 * 'cherry-pick' merge, used to merge specific revisions (or revision ranges) from one branch to another.
 * '2-URL merge', use this merge variant only if the other variants do not apply to your situation, as this variant can be quite complex to master.

=== The 'Feature Branch' Merging Pattern ===
A developer creates a branch and commits a series of changes that implement a new feature. The developer periodically merges all the latest changes from the parent branch so as to keep the development branch up to date with those changes. When the feature is complete, the developer performs a merge from the feature branch to the parent branch to re-integrate the changes.

{{{
         parent --+----------o------o-o-------------o--
                   \            \           \      /
                    \          merge      merge  merge
                     \            \           \  /
         feature      +--o-o-------o----o-o----o-------

}}}

A merge from the parent branch to the feature branch is called a 'sync' or 'catch-up' merge, and a merge from the feature branch to the parent branch is called a 'reintegrate' merge.

=== Sync Merge Example ===
{{{
                                 ............
                                .            .
         trunk  --+------------L--------------R------
                   \                           \
                    \                          |
                     \                         v
         feature      +------------------------o-----
                             r100            r200
}}}

=== Reintegrate Merge Example ===
{{{

                    rW                   rX
         trunk ------+--------------------L------------------o
                      \                    .                 ^
                       \                    .............   /
                        \                                . /
         feature         +--------------------------------R
}}}


=== Cherry-pick Merge Example ===

{{{
            1.x-release  +-----------------------o-----
                        /                        ^
                       /                         |
                      /                          |
         trunk ------+--------------------------LR-----
                                                r50
}}}

=== 2-URL merge example ===
Two source URLs are specified, identifying two trees on the same branch or on different branches. The trees are compared and the difference from SOURCE1@REV1 to SOURCE2@REV2 is applied to the working copy of the target branch at TARGET_WCPATH.

Two features have been developed on separate branches called 'foo' and 'bar'. It has since become clear that 'bar' should be combined with the 'foo' branch for further development before reintegration. Although both feature branches originate from trunk, they are not directly related -- one is not a direct copy of the other. A 2-URL      merge is necessary.

The 'bar' branch has been synced with trunk up to revision 500. (If this revision number is not known, it can be located using the  'svn log' and/or 'svn mergeinfo' commands.)      The difference between trunk@500 and bar@HEAD contains the complete set of changes related to feature 'bar', and no other changes. These changes are applied to the 'foo' branch. 
{{{

                           foo  +-----------------------------------o
                               /                                    ^
                              /                                    /
                             /              r500                  /
         trunk ------+------+-----------------L--------->        /
                      \                        .                /
                       \                        ............   /
                        \                                   . /
                    bar  +-----------------------------------R
}}}

In the diagram above, L marks the left side (trunk@500) and R marks the right side (bar@HEAD) of the merge. The difference between the left and right side is applied to the target working copy path, in this case a working copy of the 'foo' branch.

The exact changes applied by a 2-URL merge can be previewed with svn's diff command, which is a good idea to verify if you do not have the luxury of a clean working copy to merge to.