= 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 == * https://www.colordiff.org/colordiff-1.0.19.tar.gz * apt install colordiff {{{#!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 . }}} http://svnbook.red-bean.com/en/1.8/svn.branchmerge.basicmerging.html#svn.branchmerge.basicmerging.undo {{{#!highlight bash # All you need to do is to specify a reverse difference. (You can do this by specifying --revision 392:391, or by an equivalent --change -392.) #svn merge ^/calc/trunk . -c-392 svn merge ^/calc/trunk . --revision 392:391 svn st svn diff svn commit -m "Undoing erroneous change committed in r392." #### cd branch svn revert . -R # undo local changes svn up . svn log | less # see version svn merge . --revision HEAD: svn commit -m "Reverted to revision xyz" }}} == 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. == testrepo2 , sync merge and 2 URL merge == {{{ #!highlight bash #!/bin/sh # as root rm -rf /tmp/svnserver/testrepo2 mkdir -p /tmp/svnserver/testrepo2 svnserve -d -r /tmp/svnserver svnadmin create --fs-type fsfs /tmp/svnserver/testrepo2 cd /tmp/svnserver/testrepo2 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 exit # as normal user BASE_SVN_REPO=svn://localhost/testrepo2 CREDENTIALS="--username harry --password 1234" cd /tmp rm -rf testrepo2 svn checkout $BASE_SVN_REPO cd testrepo2 mkdir branches tags trunk svn add branches/ tags/ trunk/ svn status svn commit -m "Created branches tags trunk" $CREDENTIALS # Committed revision 1. # if error appears with txn-current-lock': Permission denied, run the svnserve as root ... svn up . BASE=/tmp/testrepo2 cd $BASE/trunk echo -e "t1" > dummy.txt svn add dummy.txt svn commit -m "Created dummy1.txt in trunk" $CREDENTIALS #Committed revision 2 svn up . echo -e "t2\n" >> dummy.txt svn commit -m "Added t2 to dummy1.txt in trunk" $CREDENTIALS # Committed revision 3. svn up . #create feature branch fb1 svn copy $BASE_SVN_REPO/trunk $BASE_SVN_REPO/branches/fb1 $CREDENTIALS -m "Created fb1" # Committed revision 4. cd $BASE/trunk echo -e "t3\n" >> dummy.txt svn commit -m "Added t3 to dummy1.txt in trunk" $CREDENTIALS # Committed revision 5. svn up . cd $BASE svn up . cd $BASE/branches/fb1 echo -e "fb1_1" >> dummy.txt svn commit -m "Added fb1_1 to dummy1.txt in fb1" $CREDENTIALS #Committed revision 6 svn up . cd $BASE/trunk echo -e "t4\n" >> dummy.txt svn commit -m "Added t4 to dummy.txt in trunk" $CREDENTIALS # Committed revision 7 svn up . # create feature branch fb2 svn copy $BASE_SVN_REPO/trunk $BASE_SVN_REPO/branches/fb2 $CREDENTIALS -m "Created branch fb2" # Committed revision 8 svn up . cd $BASE/branches/fb1 echo -e "fb1_2\n" >> dummy.txt svn commit -m "Added fb1_2 to dummy.txt in fb1" $CREDENTIALS # Committed revision 9 svn up . cd $BASE/trunk echo -e "t5\n" >> dummy.txt svn commit -m "Added t5 to dummy.txt in trunk" $CREDENTIALS # Committed revision 10 svn up . cd $BASE svn up . cd $BASE/branches/fb2 echo -e "fb2_1\n" >> dummy.txt svn commit -m "Added fb2_1 to dummy.txt in fb2" $CREDENTIALS # Committed revision 11 svn up . cd $BASE/trunk echo -e "t6\n" >> dummy.txt svn commit -m "Added t6 to dummy.txt in trunk" $CREDENTIALS # Committed revision 12 svn up . cd $BASE/branches/fb2 echo -e "fb2_2\n" >> dummy.txt svn commit -m "Added fb2_2 to dummy.txt in fb2" $CREDENTIALS # Committed revision 13 svn up . cd $BASE/trunk echo -e "t7\n" >> dummy.txt svn commit -m "Added t7 to dummy.txt in trunk" $CREDENTIALS # Committed revision 14 svn up . # Sync merge from trunk to fb1 cd $BASE/branches/fb1/ svn up . # will get t3 to t6 revisions ]3:12] -> 5,7,10,12 svn merge $BASE_SVN_REPO/trunk -r3:12 $CREDENTIALS --accept postpone # Conflict discovered in file 'dummy.txt'. postpone vi dummy.txt svn resolve --accept working dummy.txt svn status svn commit -m "sync merge from trunk to fb1" $CREDENTIALS # Committed revision 15. svn up . # Sync merge from trunk to fb2 cd $BASE/branches/fb2/ svn up . # will get t5 to t7 revisions ]7:14] -> revisions 10,12,14 svn merge $BASE_SVN_REPO/trunk -r7:14 $CREDENTIALS --accept postpone # Conflict discovered in file 'dummy.txt'. postpone vi dummy.txt svn resolve --accept working dummy.txt svn status svn commit -m "sync merge from trunk to fb2" $CREDENTIALS # Committed revision 16. svn up . # test 2-URL merge, put changes made into feature branch fb1 into feature branch fb2 # the feature branches must be synchronized with the parent branch before doing this cd $BASE svn up . cd $BASE/branches/fb2/ svn up . svn diff $BASE_SVN_REPO/trunk@12 $BASE_SVN_REPO/branches/fb1@HEAD # shows added fb1_1 and fb1_2 in branch fb1 when compared to trunk in the revisin used to sync svn merge $BASE_SVN_REPO/trunk@12 $BASE_SVN_REPO/branches/fb1@HEAD --accept postpone svn commit -m "2-URL merge with diff between trunk and fb1 to fb2" $CREDENTIALS # Committed revision 17. svn up . svn diff $BASE_SVN_REPO/trunk $BASE_SVN_REPO/branches/fb1@HEAD # fb1 has entries for fb1 and is missing t7 svn diff $BASE_SVN_REPO/trunk $BASE_SVN_REPO/branches/fb2@HEAD # fb2 branch has added entries for fb1 and fb2 when compared to trunk # integrate feature branch fb2 in trunk cd $BASE/trunk/ svn up . svn merge $BASE_SVN_REPO/branches/fb2 $CREDENTIALS --accept postpone cat dummy.txt svn status svn commit -m "Got changes into trunk from feature branch fb2 (reintegrate)" $CREDENTIALS # Committed revision 18. svn up . }}} Before the 2-Url merge feature branches must be synchronized with their parent branch. Mergeinfo might not allow the application of revisions 10 and 12 to fb2 if done after the 2-URL merge. {{attachment:testrepo2RevisionGraph.png}} == External item (link) == {{{ cd /home/user/container_folder echo -e "folder https://example.org/folder\n" > ~/svn_externals.txt svn propset svn:externals -F ~/svn_externals.txt . svn up . svn proplist svn propget svn:externals }}} == Update to revision == {{{ svn up -r }}} == Go to previous revision == {{{#!highlight bash svn merge -r HEAD: . }}}