Versioncontrol

git

Tagging

With a tag you can give a commit a human readable code for better describing what this specific commit represent. For example, a commit can mean that a certain milestone has been reached or that a version is meant as release for a customer.

List all local tags:

$git tag

List local tags that have the pattern 'v1.2.3':

$git tag -l v1.2.3

Create a local tag <name>:

$git tag -a <name> -m <comment>

Tag the commit <hash> with tag <name> :

$git tag -a <name> <hash>

Show mit the description of tag <name> :

$git show <name>

Create lightweight tag: A lightweight tag is the commit checksum stored in a file. No further information is stored.

$git tag <name> 

Share your tags: By default the tags are not pushed to a remote site. To push a certain tag to origin use

$git push origin <tagname> 

To push all your local tags to origin:
$git push origin --tags 

Binary Search for a commit where an error does not occur

Start a binary search by
 $git bisect start
The current version is assumed to contain the error that you want to eliminate. This is indicated by
 $git bisect bad
Afterwards you name a commit that for sure does not contain this error by
 $git bisect good abcd4711
After this command git checks out a commit in the middle of the good and the bad commit. You are assumed to test if the error is contained in this commit, for example by
./configure && make && make install; ./my-app
Error
If the error is contained you indicate this by
 $git bisect bad 
if not you define
 $git bisect good
Afterwards, git continues by checking out a new commit where you have to check if the error is contained. The process ends if git checks out the first commit where the error is contained. With
 $git bisect reset
you end the binary search.

Test last commit where a bug did not occur

 $git log
 commit abcd
 commit efgh
 $git checkout efgh
 $git branch
 * (no branch)
 * master
 $make clean;make
 success -> this version works well
 $git checkout master
 HEAD is now abcd

Good explanation of git

Well, I'm a former svn user too, and now use git for all my projects.

When using git, you should change the way of thinking from client-server architecture that used in svn. In svn, every change need connection with server. Using git, your repo is in the working directory. You don't need connection to every repo action.

Only use git push and git pull to synchronize between repo. Think of it like using rsync or any backup solution, to make two place have exactly same content. Just like you connect external backup harddisk, then make the content in it same with the content in your main. That's the usage of git pull and git push.

If you just want to go back and forth the history, do it using git checkout. See the revision id using git pull. If you using linux, use gitk to see the revision tree. In windows, tortoise git can display it using revision graph.

To get back to latest revision, use git checkout master. Before doing any command, make yourself always do git status. This command will display anything you need to know about current repo condition, and what action that you need to do to make it right. Before do git pull and git push, it's better to make sure that git status result is contain text working directory clean.

If you need to revert a file to it's previous revision, you can do it with git merge. Before doing it to file, test it first with git diff. Ex: git diff rev1:rev2 filename. It will print out any different between two revision. Change in rev1 will replaced by change in rev2. So to do revert, rev2 will be the older than rev1. After you satisfy with the diff result, do it with git merge, just replace diff with merge, all other parameter stay the same.

I hope this help you. The main key is to see that your work dir is your repo. Understand this will make you can use git to it's full capability. Good luck.

Undo last commit

 $ git status
 commit asdf
 ...
 commit qwer
 ...
 $ git reset --hard qwer
 HEAD is now qwer.

Branching with git

Briefly:

 git branch experimental
adds branch experimental
 git branch
shows you all branches and marks the current with a asterisk
 git checkout experimental
 (edit file)
 git commit -a
 git checkout master
makes a change to a file but you do not see it in master branch

Then edit same file in master branch and your branches have diverged. To merge the changes:

 git merge experimental
 git diff
if nothing comes up, you can be happy otherwise you have to merge by hand the shown positions.

Deletion of branches:

 git branch -d experimental
ensures local changes are already in the current branch
 git branch -D experimental
throw away despite any local changes

If you want to share your tags with other, push it to the remote repository:

 git push --tags
the option --tags is necessary, by default only changes to master branch are being pushed.

Getting message during pull operation

 If you often merge with the same branch, you may want to
 configure the following variables in your configuration file:

    branch.master.remote = <nickname>
    branch.master.merge = <remote-ref>
    remote.<nickname>.url = <url>
    remote.<nickname>.fetch = <refspec>

You can do this:

 git config branch.master.remote origin
 git config branch.master.merge refs/heads/master

git version differences

 git show c2d8ea11b4e6aeb605aeef35fad261846d142ff6 file.txt

Shows the differences between this commit and the one before.

recover accidentally deleted files:

 git ls-files -d
shows files that were deleted
 git ls-files -d | xargs git checkout --
recover these files

init new repository

 git init 
creates .git directory in the current folder which stores the complete information
 git add filename
 git commit -m 'comment'
 gitk

The following creates a remote repository:

 ssh remoteserver.com
 mkdir /var/git/myapp && cd /var/git/myapp
 git --bare init
 Initialized empty Git repository
 exit

on local site:

 cd ~/workspace/git/myapp
 git remote add origin ssh://remoteserver.com/var/git/myapp
 git push origin master 

git push origin master
is important and only necessary the first time you push from local to remote repository

This was found here.

Another user can clone the origin branch from the remote host by

    git clone ssh://user2@remoteserver.com:/var/git/myapp

subversion

Creating a repository

  svnadmin create /home/user/svn/repo1

What happens from revision 23 to 42?

 svn diff --diff-cmd=kdiff3 -r 23:42
svn prints which files have been changed since revision 23.
 svn log -r23 -v
If you just want to know what files have been edited or added.

Merge Conflicts

You get four files in case of a conflict:

 # file.c
 # file.c.r123
 # file.c.r234
 # file.c.working

Revision 123 is where the versions went different paths and 'working' is your current version. You can merge these three file and copy the result to file.c. Don't forget to copy the version over the version of file.c. Otherwise you have all the versions in file.c with '<<<<', '=====' and '>>>>>' strings divided.

A useful tool is kdiff3. With this you can see all three different versions and write into the original file. By calling

  kdiff3 file.c.r123 file.c.r234 file.c.working -o file.c

you define .r123 as base version and the other two as the conflicting ones. The writes are going to file.c..

Global exclude of file extension

  global-ignores = *.o *.aux *.log *.dvi

gives each line of source with information about author and revision

  svn blame source.c
  svn ann   source.c

change attributes from files that are contained in repository

  $svn propdel svn:executable source.hpp
  property 'svn:executable' deleted from 'source.hpp'.
Deletes the executable bit from source.hpp which was set because it was copied from a windows system.

Advanced svn techniques

Using external editor for commits
 editor-cmd = "editor"
replace "editor" with your prefered editor
Using your prefered diff tool
 diff-tool-cmd = "svn_diff"
svn_diff is a script that diverts the 6th and 7th parameter further to gvimdiff or whatever editor else.

Or you can use

 svn diff -r 123:132 asdf.txt --diff-cmd=echo

to see what the wrapper needs to do with the stream from svn.

 svn diff -r 123:132 asdf.txt --diff-cmd=gvimdiff
svn export

to export an arbitrary version of some project without subversion information (.svn folders)

svn basics

 svnadmin create /repository

 svn import path2project/file file://path2repository -m 'comment'
 svn checkout file://path2repository where2place
 svn co svn+ssh://servername/repository where2place
 svn add filename
 svn commit -m ''
 svn delete filename
 svn move oldname newname
 svn update # gets changes from repository

 # examine your changes
 svn status
 svn diff
 svn revert

 # examine local changes
 svn diff

 # comparing working copy to repository
 svn diff --revision 3 foo.c

 # comparing repository to repository 
 svn diff --revision 2:3 foo.c

If you want to examine an earlier version of a file and not cecessarily the differences between two files, you can use svn cat:

 svn cat --revision 2 foo.c

 # logs
 svn log --revision 5:19 
shows logs 5 through 19 in chronological order
 svn log -r 19:5
shows logs 5 through 19 in reverse order
 svn log -r 8
shows log for revision 8
  1. merge others' changes
 svn merge
 svn resolved

 svn status --verbose
 svn status --show-updates --verbose

 svn diff > patchfile
  1. make the changes which you have made accidentally
 svn revert foo.c
  1. resolving conflicts
 svn commit -m ''
 svn: commit failed ... foo.c remains in conflict

Then you can run

 svn resolved foo.c

to inform svn that you have resolved the conflict with this file.

Merging

you made the changes

 <<<< .mine
 blabla
 ====

Someone's changes are here

 ====
 blub
 >>>>>> .r23

If you want to change the server where the repository lies you only have to copy (secure with scp over openssh) the whole repository folder to the new server and there you start the svn daemon with:

 svnserve -d
this opens a port on 3690

If you want only secure connections to the server you can write a rule with iptables:

 $IPTABLES -A INPUT -p tcp --destination-port 22 -j ACCEPT
 $IPTABLES -A INPUT -p tcp --destination-port 3690 -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT
 $IPTABLES -A INPUT -p tcp --destination-port 3690 -j DROP

then the local connections to 3690 will be permitted the rest not. From outside only tcp on port 22 (ssh) is allowed.

Examining History

There are several commands that can provide you with historical data from the repository:

 svn log

    Shows you broad information: log messages attached to revisions, and which paths changed in each revision.
 svn diff

    Shows you the specific details of how a file changed over time.
 svn cat

    This is used to retrieve any file as it existed in a particular revision number and display it on your screen.
 svn list

    Displays the files in a directory for any given revision.

 svn log

 svn log --revision 5:19    # shows logs 5 through 19 in chronological order
 svn log -r 19:5            # shows logs 5 through 19 in reverse order
 svn log foo.c
 svn log -r 8 -v
 svn diff --revision 3 rules.txt 

If you want to examine an earlier version of a file and not necessarily the differences between two files, you can use svn cat:

 svn cat --revision 2 rules.txt 
 svn cat --revision 2 rules.txt > rules.txt.v2

In addition to all of the above commands, you can use svn update and svn checkout with the --revision switch to take an entire working copy “back in time”

 svn checkout --revision 1729 # Checks out a new working copy at r1729
 svn update --revision 1729 # Updates an existing working copy to r1729

Sometimes an administrator might change the “base location” of your repository—in other words, the contents of the repository doesn't change, but the main URL used to reach the root of the repository does. For example, the hostname may change, the URL scheme may change, or any part of the URL which leads to the repository itself may change. Rather than check out a new working copy, you can have the svn switch command “rewrite” the beginnings of all the URLs in your working copy. Use the --relocate option to do the substitution. No file contents are changed, nor is the repository contacted. It's similar to running a Perl script over your working copy .svn/ directories which runs s/OldRoot/NewRoot/.

 cd /repository-path
 svn switch --relocate  file:///tmp/repos file:///tmp/newlocation .
 svn diff --revision PREV:COMMITTED foo.c
shows the last change committed to foo.c
 svn log --revision HEAD
shows log message for the latest repository commit
 svn diff --revision HEAD
compares your working file with local mods to the latest version in the repository.
 svn diff --revision BASE:HEAD foo.c
compares your pristine foo.c (no local mods) with the latest version in the repository
 svn log --revision BASE:HEAD
shows all commit logs since you last updated
 svn update --revision PREV foo.c
rewinds the last change on foo.c which leads to decreasing the foo.c's working revision

Revision Dates

 svn checkout --revision {2008-08-01}
 svn checkout --revision {15:30}
 svn checkout --revision {15:30:23.2000000}
 svn checkout --revision {"2008-08-01 15:30"}
 svn checkout --revision {"2008-01-01 15:30 +0230}
 svn checkout --revision {2008-01-01T15:30Z}
 svn checkout --revision {20080202T1530-0500}

 svn log --revision {2002-11-11}:{2002-12-01}
finds all revisions between both dates
 svn log --revision {2002-01-01}:4711
finds all revisions between date and revision number.

Branches with svn

Assume that you have prj23 as project folder and you have some big steps to do with your project. Until you finish the changes you want that the other guys who are working with the same project do not note something of the changes. For that reason you can establish a new branch. This new branch should be created in the folder ./mybranch:

 svn copy prj23 mybranch
 svn status
 A + mybranch
 svn commit -m ""

The character '+' shows that this folder is only a copy and not a complete new folder.

Merging branches again to one branch

Assume you have a original version and two branches of project prj23. Lets name these branch1 and branch2. Then some guys will edit many changes. Then you want the changes from branch1 merge into the branch2. Just go to the folder where the two branches folder lie and type:

 svn log -v 
to get the oldest revision where branch1 was created. Lets call it 303.
 svn merge --revision 303:342 branch1 branch2
342 is the newest revision of branch1.

Afterwards you have the changes which were made to branch1 also in branch2.

undoing changes

If you commit something to revision 303 and later you recognize that the changes were totally wrong. They have never been committed. So you can make a merge back:

 svn merge -r 303:302 prj23

creating releases

You have reached a specific development status and want to hold this status as release 1.0:

 svn copy prj23 releases/prj23-1.0 -m "release 1.0"

Afterwards be sure not to commiting to these folders because it is the same as a branch and the commits will change the release to a newer state. But this is usally not what you want.

mercurial

To diff your work file with the recent version in repository use:

  hg cat <filename> | vim - -c  ":vert diffsplit <filename>"

cvs

 CVSROOT=/path2archive
 cd $CVSROOT; cvs init
 cd source
 cvs import -m 'bla' projectname user alpha vendor release
 cd workingfolder
 cvs checkout projectname
 cd workingfolder/projectname
 # make some changes
 cvs update
 cvs -Q diff -c
 cvs commit -m 'asdf'
 cvs status main.c
 cvs edit main.c
 cvs watch main.c
 mkdir test 
 cvs add test
 touch test/a.c
 cvs add test/a.c
 cvs commit -m ''