Difference between revisions of "Git vs Svn"

From GnuCash
Jump to: navigation, search
(Migration finished; add a rudimentary synopsis)
(Replace uses of master)
 
(One intermediate revision by one other user not shown)
Line 13: Line 13:
 
Quick reminder of how it works in svn: a branch only exists by convention. A directory in the repository is created that is agreed upon to hold "branches", next one master directory (usually called "trunk") which keeps the main branch. Whenever someone wishes to create a branch, a copy of the trunk branch is made into the branch directory. So a branch in svn is just a commit like any other, but in a separate directory commonly agreed upon.
 
Quick reminder of how it works in svn: a branch only exists by convention. A directory in the repository is created that is agreed upon to hold "branches", next one master directory (usually called "trunk") which keeps the main branch. Whenever someone wishes to create a branch, a copy of the trunk branch is made into the branch directory. So a branch in svn is just a commit like any other, but in a separate directory commonly agreed upon.
  
In git this is totally different.
+
In git this is totally different. For starters the primary branch is usually called "master" rather than "trunk".
  
 
Suppose you have this tree of commits in your local repository
 
Suppose you have this tree of commits in your local repository
  
   A - B    (trunk)
+
   A - B    (master)
 
     \
 
     \
 
       C    (feature-x)
 
       C    (feature-x)
  
A is the parent commit, B is a descendant of this commit on the trunk branch. C is a  
+
A is the parent commit, B is a descendant of this commit on the master branch. C is a  
 
descendant of A on the feature-x branch.
 
descendant of A on the feature-x branch.
  
 
Two things are very important to point out here:
 
Two things are very important to point out here:
 
- In git a commit can have multiple parents or children. This is not so in svn where each commit has exactly one parent on zero or one children. That's one of the main reasons svn has to resort to a separate directory to define branches.
 
- In git a commit can have multiple parents or children. This is not so in svn where each commit has exactly one parent on zero or one children. That's one of the main reasons svn has to resort to a separate directory to define branches.
- This is a good moment to explain what branch means in git. The trunk 'branch' is some kind of label that is currently attached to commit B.  
+
- This is a good moment to explain what branch means in git. The master 'branch' is some kind of label that is currently attached to commit B.  
 
The feature-x 'branch' is equally some kind of label attached to commit C
 
The feature-x 'branch' is equally some kind of label attached to commit C
  
When you merge feature-x into trunk in git, you will get this tree:
+
When you merge feature-x into master in git, you will get this tree:
  
   A - B - D (trunk)
+
   A - B - D (master)
 
     \  /
 
     \  /
 
       C    (feature-x)
 
       C    (feature-x)
  
The 'trunk branch' is now a label attached to commit D. All the ancestors of commit D are  
+
The 'master branch' is now a label attached to commit D. All the ancestors of commit D are  
considered part of the trunk branch. But note already how the branch itself is just a label  
+
considered part of the master branch. But note already how the branch itself is just a label  
 
moving from commit to commit as changes are committed.
 
moving from commit to commit as changes are committed.
  
Line 46: Line 46:
 
upstream repo looks like this:
 
upstream repo looks like this:
  
   A - B    (trunk)
+
   A - B    (master)
  
'trunk' is a public branch. Let's push our local trunk changes upstream. After a successful  
+
'master' is a public branch. Let's push our local master changes upstream. After a successful  
 
push, upstream will look like this:
 
push, upstream will look like this:
  
   A - B - D (trunk)
+
   A - B - D (master)
 
     \  /
 
     \  /
 
       C
 
       C
Line 70: Line 70:
 
This section shows only a subset of possible pitfalls.
 
This section shows only a subset of possible pitfalls.
 
;checkout: In git this is a ''branch related'' command, to get a repo use <tt>git clone</tt>.
 
;checkout: In git this is a ''branch related'' command, to get a repo use <tt>git clone</tt>.
;commit: In git this is a ''local command'', use <tt>git push</tt>
+
;commit: In git this is a ''local command'', use <tt>git push</tt> to update the project repo.
 
(Feel free to complete this list.)
 
(Feel free to complete this list.)

Latest revision as of 14:59, 24 March 2017

GnuCash has long been using svn as the primary version control system, but finished the process of migrating to git at the begin of 2014.

Superficially git and svn share the same goal: make writing code more manageable by slicing the changes up in smaller parts (commits) and keep a history of these changes. This is very oversimplified, but sufficient for this page.

When you zoom in some more, you will notice that git and svn use some very different techniques to do so. This page will list some of these differences. The focus will be on differences that matter to GnuCash.

Branches

I know from experience it takes some time to fully grasp git branches when coming from svn. So I'll just add a simplified, explicit example on git branches for others still deeply in the svn mindset (best viewed with a fixed-width font).

Quick reminder of how it works in svn: a branch only exists by convention. A directory in the repository is created that is agreed upon to hold "branches", next one master directory (usually called "trunk") which keeps the main branch. Whenever someone wishes to create a branch, a copy of the trunk branch is made into the branch directory. So a branch in svn is just a commit like any other, but in a separate directory commonly agreed upon.

In git this is totally different. For starters the primary branch is usually called "master" rather than "trunk".

Suppose you have this tree of commits in your local repository

 A - B    (master)
   \
     C    (feature-x)

A is the parent commit, B is a descendant of this commit on the master branch. C is a descendant of A on the feature-x branch.

Two things are very important to point out here: - In git a commit can have multiple parents or children. This is not so in svn where each commit has exactly one parent on zero or one children. That's one of the main reasons svn has to resort to a separate directory to define branches. - This is a good moment to explain what branch means in git. The master 'branch' is some kind of label that is currently attached to commit B. The feature-x 'branch' is equally some kind of label attached to commit C

When you merge feature-x into master in git, you will get this tree:

 A - B - D (master)
   \   /
     C     (feature-x)

The 'master branch' is now a label attached to commit D. All the ancestors of commit D are considered part of the master branch. But note already how the branch itself is just a label moving from commit to commit as changes are committed.

And observe again how commits can have multiple parents and children.

Now this all happened in your local git repository. The upstream git repository doesn't know about any of this yet. At some point you want to push your work upstream. Let's assume for simplicity that commit A and B were already in the upstream repo as well. This means the upstream repo looks like this:

 A - B    (master)

'master' is a public branch. Let's push our local master changes upstream. After a successful push, upstream will look like this:

 A - B - D (master)
   \   /
     C

You might say that's exactly like the local repo, but there's one slight, yet important difference: the *branch* feature-x wasn't pushed upstream (note that I didn't put that name next to the C commit).

The *commits* that were on that branch and are ancestors of commit D are (commit C in our example). These are required to regenerate commit D, so they are pushed upstream as well.

However the *branch* itself is just a name tied to a commit. This name can move to another commit or even be removed without affecting the commits themselves in any way. So unless you explicitly push that branch (name) to the upstream repository it won't appear in there. That allows to have many local branches and yet keep a manageable list of branches in the public repository.

Synopsis

This section shows only a subset of possible pitfalls.

checkout
In git this is a branch related command, to get a repo use git clone.
commit
In git this is a local command, use git push to update the project repo.

(Feel free to complete this list.)