You are here: Foswiki>Software Web>SvnGit (18 Dec 2018, PetrKubanek)Edit Attach

svn to git cheat sheet

Please consider using ssh keys for git. To use SSH keys, see this article. Consult with SH if you need more help - modern Linux (and Mac/Windows?) environments provide secure wallet where unlocked ssh keys are kept, so you don't have to retype SSH private key password.

Public/Private keypair in Centos 7

  • run seahorse (from terminal) or Applications/Utilities/Passwords and Keys
  • Click Plus (big "+")
  • Select Secure Shell Key
  • Click Continue
  • add description
  • Click Just Create Key
  • enter (twice) password. Must have at least 5 characters

Once you are done, you will find public part of the key in ~/.ssh/ Copy content of this file to Github settings page and you are done


  • ssh-keygen (for the command line inclined)

Keys on Mac, Windows

Please see for details.

Setting up git

You need to tell git who you are and what's your email, so it can produce proper log entries. To do that, run: %CODE{ lang="bash" }% git config --global "My Name" git config --global %ENDCODE%

from console/terminal. This is a one-time action on a given machine - you don't need to repeat the exercise. Replace options with the one matching your GitHub account (email is what is used for user identification).

It's higly encouraged to add some colors with:

%CODE{ lang="bash" }% git config --global color.ui auto %ENDCODE%

Cheat sheet

You can specify git URL (used in a clone,..) starting with or https://<username> For the, you will need to set up public/private key pair (see above).

svn git comments
svn co (checkout) git clone
svn up (update) git pull
svn add git add
svn diff git diff
svn ci (commit) git commit && git push or
git commit
git push
svn log git log
svn blame git blame
svn sw (switch) ^/branches/2018A git fetch --all && git checkout 2018A
git checkout origin/2018A
git fetch --all is needed only if the branch isn't in your local repository, e.g. was created after clone
svn merge ^/trunk git merge master
svn merge -c 12345 ^/trunk git cherry-pick <sha-has> see Gitrevisions for ways how to spell revisions
rm filename && svn up git checkout -- filename

Differences between SVN and GIT:

  • git uses two stages commit. The git commit command (preceded by git add for new files) tells GIT to commit locally file. No changes are done on a remote end (e.g. GitHub). The local commits are propagated (pushed) to remote end with git push
    • this allows you to develop, commit your work locally once you are happy, stage commits, and then push back to remote end once you are happy with the result
    • moreover, that allows you to push to multiple remote ends (design feature of GIT for kernel developers)
  • git commit without argument will commit all changed files (which were *git add*ed or were pulled from the repository). It is always better to provide a list of files to commit. Tabulator completion will give you the list of files you can commit.
  • git pull command will complain if you make some local change. You have two options:
    • run git pull --rebase to automerge remote end, without creating an extra entry in git log
    • run git stash, followed by git pull, and git stash pop - that will put your diff into "stash", which is temporary storage for diffs, and then pop it from stash list (= will apply again the changes you made).

GIT advantages

  • fast (particularly log browsing/history browsing), as you have a complete copy of the repository. Compare the speed of svn diff -r 12345 with what gitg GUI provides
  • you can play locally before sending all to master
  • stash command to get out your changes as diff and make your copy clean (without any changes) to later re-apply with stash pop command
  • you can start local branches and after you are happy, merge to master - you don't spoil master with your progress, but can still commit after achieving part of the fix
  • rebasing (SVN doesn't have anything like that)

Git philosophy

Being a distributed version control system, Git must obey a bit different (and sometimes odd) rules on how to carry development. Understanding those algorithms will help a bit understanding what's going on.

When you clone a repository, you do not only hold the history of changes (the current files plus all changes applied to them from the point the files were created), but also metadata (who committed changes, tags, ..) and, more importantly, git hashes. Git hashes (the concept of hashes is beyond scope of this document, see Cryptographic hash function on Wikipedia) computed from commit metadata and previous commit (=history) allows hashes to be used to verify the integrity of the Git (and history of commits). Git can quickly compare (using a hash) if two heads (=commits) are the same, the feature used when pulling/merging requests to a server.

Git is a sort of distributed ledger. Your ledger has entries secured by unique hashcodes, which depends on previous activity (as hashcode is calculated from your latest commits, combined with what was already committed. You have to keep synchronizing your local repository with others (which is in our case greatly simplified by having the central repository on GitHub). The commands to list what your local copy knows about others (what others know about your copy is irrelevant) are listed below.

The oddities are described on this and those web pages - but please bear in mind this is pre-GitHub (which allow for a kind of centralized development and bring in pull request) and does not dive into other source versioning systems problems. Except for pull request, the major upgrade from SVN is in rebasing - SVN does not allow for that.

Description of how the branching can be used is in there.

Git kung-fu

Following paragraphs provides some command useful in everyday git use.

Git Rebasing

You are probably familiar with merging branches. Git introduces another option to join branches - rebasing. In order to know how and when to use it, you must understand how it works and what it does. Rebasing works similar to merge, allowing to join development from two branches. Usually, you call git rebase <destination_branch> from your origin branch, so the command knows about two branches (the one you are into and the one you are rebasing to). There is Git documentation on the topic, but to make things quicker, rebasing work in following steps:

  1. find a common ancestor between your branch and branch you are rebasing to (since everything in Git repository starts from a single branch, there must be such ancestor)
  2. removes from your history all changes between your branch and the common ancestor
  3. switch into the destination branch (the branch you are rebasing to)
  4. replay on top of the destination branch changes performed in your local branch (reapply what was done in your origin branch)

After rebasing, your origin branch head is put on top of the destination branch. You can then merge (with ff) to move destination branch top to be equal to the origin branch and delete (git branch -d <origin>) the origin branch.

Git reset

Git reset is the almost omnipotent command, having three main uses:

%CODE{ lang="bash" }% # reverts files staged for commit (added with git add) git reset # removes entries from ledger (git log) up to a given point; changes to files are kept, see git diff after performing reset # the last entry git reset HEAD~1 # the last 3 git reset HEAD~3 # down to a given hash git reset af3443f213abcdf # hard, overwrite changes (THIS ONE IS DANGEROUS) git reset --hard # hard to latest state at given branch (THIS IS DANGEROUS AS WELL) git reset --hard upstream 2018A %ENDCODE%

Restoring files

If you hit a dead end during your development, or you are only adding temporary log entries to see how is the algorithm working or where can be a problem and would like to get rid of your temporary changes, use git checkout --:

%CODE{ lang="bash" }% # restore changes to Main.cpp (OVERWRITE YOUR LOCAL CHANGES) git checkout -- Main.cpp %ENDCODE%

Git and references

You local git clone keeps entries describing where the code is kept, so git pull and git push commands works without providing details where to look on:

%CODE{ lang="bash" }% # show remote (aliases) git remote -v show origin (fetch) origin (push)

# shows branches and their remote tracking (where pull/push without target argument will look), * (star) marks the current branch (use git checkout to switch branches) git branch -vv 2018A 9da53f1 [origin/2018A] Merge pull request #20 from pkubanek/2018A * IT3949 353fc50 [origin/IT3949] start TTL thread master 1e18a29 [origin/master] Merge pull request #14 from krsummers/master %ENDCODE%

The above is the expected configuration. Push and pull without a target will be directed to LBTO/tcs GitHub repository.

Example - disentangling two changes

On shared home drives, in /home/pkubanek/git-ex1-tcs, is stored a Git snapshot. While working on Time To Limit issues (IT3949), it was discovered that C++11 standard usage will bring a lot of benefits to the code. Changes were made to accommodate for the C++11 standard.

Now those are included in changes for IT3949, which isn't good. Separating those into a different branch would be great. You might reproduce the first steps by cp -ra /home/pkubanek/git-ex1-tcs /tmp/tcs && cd /tmp/tcs and working in /tmp/tcs. Please don't try to push anything.

%CODE{lang="sh"}% # while on IT3949 branch [tcs]$ git add tcs/core/Configuration.cpp tcs/core/Configuration.hpp pcs/TimeToLimit.cpp pcs/TimeToLimit.hpp pcs/PCS.cpp pcs/pcsgui/pcsgui.cpp pcs/etc/pcs.conf pcs/PCS.hpp pcs/test/ [tcs]$ git commit IT3949 dc1edb6] TTL events times are configurable 12 files changed, 202 insertions(+), 56 deletions(-) create mode 100755 pcs/test/3949/left_LUCI create mode 100644 pcs/test/3949/stars_rot.dat create mode 100644 pcs/test/3949/test.dat [tcs]$ git checkout master M Makefile M aos/aosupervisor/AONanWrapper.hpp M dds/DDS.hpp M dds/Main.cpp M ecs/Main.cpp M env/Main.cpp M iif/commands/RotateCommon.hpp M mcs/Main.cpp M oss/Main.cpp M pcs/Main.cpp M pmc/Main.cpp M psf/Main.cpp M psf/PSF.hpp M psf/PSFSecondaryMirror.hpp M psf/PrimaryMirror.hpp Switched to branch 'master' [tcs]$ git checkout -b C++11 M Makefile M aos/aosupervisor/AONanWrapper.hpp M dds/DDS.hpp M dds/Main.cpp M ecs/Main.cpp M env/Main.cpp M iif/commands/RotateCommon.hpp M mcs/Main.cpp M oss/Main.cpp M pcs/Main.cpp M pmc/Main.cpp M psf/Main.cpp M psf/PSF.hpp M psf/PSFSecondaryMirror.hpp M psf/PrimaryMirror.hpp Switched to a new branch 'C++11 # change in Configuration.cpp is needed [tcs]$ vim tcs/core/Configuration.cpp [tcs]$ git diff tcs/core/Configuration.cpp diff --git a/tcs/core/Configuration.cpp b/tcs/core/Configuration.cpp index 6a43bab..500c989 100644
a/tcs/core/Configuration.cpp +++ b/tcs/core/Configuration.cpp @@ -124,7 +124,7 @@ public: set< string > const & getFormattedLines() const { return *lines_; }

private: - shared_ptr< set< string > > lines_; + tr1::shared_ptr< set< string > > lines_; }; # make sure the branch compiles [tcs]$ make clean && make -j8 # commit (and push -u to create C++11 branch, but don't try to push for you) [tcs]$ git commit . [C++11 b51fb03] C++11 compilation 16 files changed, 51 insertions(+), 50 deletions(-) # [tcs]$ git push -u origin C++11 # Counting objects: 63, done. # Delta compression using up to 8 threads. # Compressing objects: 100% (32/32), done. # Writing objects: 100% (32/32), 2.54 KiB | 0 bytes/s, done. # Total 32 (delta 31), reused 0 (delta 0) # remote: Resolving deltas: 100% (31/31), completed with 31 local objects. # To # * [new branch] C++11 -> C++11 # Branch C++11 set up to track remote branch C++11 from origin. %ENDCODE%

After that, a pull request from C++11 to master is made (create pull request on GitHub). After approval, those steps needs to follow (you cannot reproduce those on your setup, as those were already done):

%CODE{lang="sh"}% [tcs]$ git checkout master Switched to branch 'master' %ENDCODE%


  • gitg - install with sudo yum install gitg
  • gitk and git-gui - old timer tcl-tk (unrivalled last time I checked but that was a long time ago. MB)
  • More guis..

About GIT

Converting SVN to GIT

First, store as users.txt the following text:

cbiddick = Chris Biddick <>
cjb = Chris Biddick <>
ksummers = Kelleee Summers <>
pgrenz = Paul Grenz <>
pkubanek = Petr Kubanek <>
shooper = Stephen Hooper <>
tedgin = Tony Edgin <>
(no author) = No Author <>
delapena = Michele De La Pena <>
mdelapena = Michele De La Pena <>
shooper = Stephen Hooper <>
svnadmin = SVN admin <>
dlt = David Terrett <>
dterret = David Terrett <>
dterrett = David Terrett <>
jeff = Jeff Neubauer <>
lbtscm = SVN admin <>
tsergant = Tom Sargent <>
tsargent = Tom Sargent <>
trowitzsch = Jan Trowitzsch <>
briegel = Florian Briegel <>
borelli = José Borelli <>
jborelli = José Borelli <>
ccox = Chris Cox <>
leibold = Torsten Leibold <>
felix = Felix Krämer <>
tmh = Thomas Hahn <>
thahn = Thomas Hahn <>
tgolota = Taras Golota <>

The best is to follow instructions from

%CODE{lang="sh"}% git svn clone --no-metadata --authors-files=users.txt --stdlayout /tmp/temp # convert svn:ignore to .gitignore cd /tmp/temp git svn show-ignore -i trunk > .gitignore # edit .gitignore and clean it git add .gitignore git commit -m 'Convert svn:ignore to .gitignore.' git init --bare /tmp/new-bare.git cd /tmp/new-bare.git git symbolic-ref HEAD refs/head/trunk # push repository to a bare git repository cd /tmp/temp git remote add bare /tmp/new-bare.git git config remote.bare.push 'refs/remotes/*:refs/heads/*' git push bare # rename trunk branch to master cd /tmp/new-bare.git git branch -m trunk master # clean up branches and tags git for-each-ref --format='%(refname)' refs/heads/tags | cut -d / -f 4 | while read ref do git tag "$ref" "refs/heads/tags/$ref"; git branch -D "tags/$ref"; done %ENDCODE%

When this is done (sometimes the process fails and needs to be restarted, rm -rf ${DIR} and try again), you can run the following to populate GitHub repository from your local git created from SVN. Be aware that push -f will overwrite GitHub repository - use the command with caution!!:

%CODE{lang="sh"}% cd /tmp/new-bare.git git remote add origin # repository shall be created, it's up to you which name you agree on git push -f # think twice; this will force overwrite LBTO/ on GitHub! %ENDCODE%

If you need to convert only a directory from SVN repository, you can do that using for clone:

%CODE{lang="sh"}% DIR= && git svn clone https://svn/repos/ --trunk="trunk/${DIR}" --branches="branches/*/${DIR}" --authors-file=users.txt --no-metadata -s ${DIR} %ENDCODE%

where you can fill <directory> with SVN directory you want to convert (or leave it blank) and <repo> with SVN repository name. If you remove --no-metadata. git log will not include reference to SVN commits IDs.

-- %USERSIG{PetrKubanek - 2018-03-14}%
Topic revision: r16 - 18 Dec 2018, PetrKubanek
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Foswiki? Send feedback