TFS vs. Git…or is it TFS with Git?

Maybe you ended up on this post because you searched for ‘Git vs. TFS’. I hope so.
I have seen some debate going on for some time now in twitter about Git versus TFS (here are some examples):

image

If that’s the case I think you’re looking at it from the wrong angle, so to say. It really a matter of centralized vs. distributed version control.
Here’s how Microsoft actually explains it when you choose version control while creating a new project in Team Foundation Service:

image

Team Foundation Version Control (TFVC) uses a single, centralized server repository to track and version files. Local changes are always checked in to the central server where other developers can get the latest changes.

Git is a Distributed Version Control System (DVCS) that uses a local repository to track and version files. Changes are shared with other developers by pushing and pulling changes through a remote, shared repository.

The S in TFS does not stand for Source Control, it stands for server, that’s very important to understand.
Git on the other hand does not have a server concept, it has (optionally) one or many shared repositories.


One might actually wonder why Microsoft has made such an effort, believe me it is, to incorporate Git into TFS when they already have a great version control system in place (TF Version Control or TFVC for short)?
I think the answer is actually pretty simple (if we put aside the need for MS to stay up-to-date):
TFS is not a version control system, it is an ALM (application lifecycle management) product that uses a version control component. Git is nowadays a very popular such a version control component so why shouldn’t we be allowed to use it in TFS?

With that introduction I’ll get on to business which is the following.

What this post will cover (its purpose):

  • Introduction to Git from the perspective of a TFVC developer. Basic concepts in Git, the things you should know about to put it simple.
  • My point is not to show that Git is superior to TFVC, it’s just different and I hope to highlight the big differences.
  • Understanding branching, merging and HEAD in Git and why they are such important concepts.

Offline != Distributed

A common misconception about Git is that the big difference from TFVC is the great offline support…I hear that a lot.
TFVC also has great offline support (at least from version 2012).

A distributed VCS is much more than offline support. I would actually go so far as to say that a DVCS does not offer online support…think about that for moment.
In a DVCS, like Git, all users have a ‘complete copy’ of the entire repository. It also means that you have ‘full control’ of your own repository.
This might seem a bit confusing but it will become clearer once you start working with branches, promise.

In TFVC if you are offline and try to create a new branch you will get prompted with this error:

image

That’s because creating a branch is server operation in TFVC. You will also need permission (on the server) to create branches.
When you’re offline using TFVC you can only add/delete/update files and so on.

If you try the same thing using Git it will not be an issue. All commits are always made to your local repository. Let me say that again, all commits are always made to your local repository. And…you have full control of your local repository.
That is probably what’s misleading to some people.
Again you could say that Git is never online and always offline…well kind of anyway?!

Push and Pull?

But wait a minute…if everything is local/offline how can we collaborate on a big project with many developers that need to share code.

Well, all commits are made to the local repository. When you are ready to publish your work (share it with your team) you’d issue a push to a shared repository.
That means that you will push your changes (commits) from your local branch to the shared version of that branch (in a shared repository).
You can also pull changes from the shared repository to your local repository. In Git it is also possible to pull down changes but not merge them into your code, that’s called a fetch.
It’s worth noticing that Git can have more than one shared repository, thus it’s not a central server we’re talking about here. If you do have a shared repository that no one works in (like a shared network folder or something) that repository is said to be bare.
Since everyone will have a complete copy of the repository chances are pretty high that someone will have a ‘backup’ if something happens. (it’s distributed risk so to say)


Snapshots vs. Revisions

The biggest difference with Git compared almost any other centralized VCS is the snapshot concept.
In a  centralized VCS all changes are revisions and changes will result in deltas.

In Git all changes (commits) instead result in a snapshot that reflects how the repository looked at the time of the commit.
Let’s see an example:

image

If we look at the ‘feature 001 done’ commit/snapshot above this is what we see:

  1. The actual changes which in this example would only be an updated program.cs file.
  2. All other files where unchanged thus there will be a pointer to a parent commit (in this case the ‘Intial Load’ commit which added all those files). This is for efficiency.

So in order for Git to show us the complete state of the repository it only has to walk the trail and apply each commit from the bottom up, so to say.


Branching

In Git a branch is nothing more than a pointer to a commit (or a snapshot).  Coming from a VCS that uses branches as copies of the parent that it originated from this can be a bit confusing.
It can also be a bit confusing when you look at the Git history….you never really see any clear signs of branches. They are just so natural in Git.

Endjin has very good way of describing the difference as:

My favourite way of describing the difference between the TFS and Git branching models is as follows, in TFS – branching is essentially like the TV Show Fringe in that you have to deal with parallel worlds crossing between those world is a difficult process with severe health risks to the person “crossing over”, whereas with Git is more like Doctor Who: branching is essentially dealing with time streams where you can easily go forwards, backwards and even sideways.

In Git, when you create a branch all you really will do is create a pointer to a commit. Nothing is moved, copied, nothing.

image

Compare the image above (TFVC on the right and Git on the left) after working a while with some branches. TFVC gets quite littered with copies of your source control and you have to introduce some maintenance task that cleans up the branches. (remember, they reside on the server)
Git only has one copy of the source code though and branches are usually only handled locally, you normally never push your local branches anywhere for sharing.

In a TFVC project with many branches you will also have to remember to open the file/s you want to edit from inside the correct folder (can be a bit tricky to remember). In Git, that will never be an issue.

A branch starts by referencing the newest commit, which is usually the latest commit from the source branch, and when you continue to create a new commit in a branch, the branch reference (pointer) is updated to reflect that commit instead.

HEAD

With that said, let’s briefly talk about another important Git concept…HEAD.
How does Git keep track of which branch you’re actually working in? It keeps a special pointer called HEAD.

HEAD is just a reference to the latest commit in the branch you’re currently working on.
Think of it like a DVD (or something) where you can choose different chapters and move back and forward as you please.

So when you switch (checkout in Git-terms) branch all you do is change chapter in the DVD menu (…)


Merging

In Git a merge is…wait for it…a commit. But a special type of commit that has multiple parents. Git will, by itself, decide the best way to perform a merge which also makes it a lot easier. (sometimes this just means a fast-forward merge)
Let’s look at an example:

image

The merge commit (tagged with v1.0.1) has two parents; the hotfix 1.0.1 and one of the previous merge commits (tagged with v1.0.0).

Conflicts

image

All merge conflicts are handled inside the merge commit as you can see from the merge commit above which caused a conflict.
No changes are made in the parent commits, history is preserved. (compare this to other VC systems where a merge is basically a squash of two branches…and thus scary)


But Git is a command-line tool, right?

Well, it used to be. And sometimes you have to resort to using the command-line but that’s even true with TFVC sometimes.

With that said we nowadays have support in Visual Studio for Git. It’s not as complete as the tools for TFVC…yet. However there’s another tool that I want to shed some light at, SourceTree (from Atlassian):

image

I use SourceTree a complement to Visual Studio…I usually do commits and merge conflict things in VS and all the rest in SourceTree.

But Git has no security, right?

Well, I’m no expert in this area but if you have access to the Git repository (you have cloned it) you have full control over your local version.

However it’s pretty easy to setup separate read and write permissions, and Git supports more than one protocol.
Numerous services exist for that very purpose, like (most of them offer a bit more than just permissions though):


Summary

First here’s a kind of a glossary for a TFVC person coming into Git (the concepts kind of match):

TFVC Git
Check-In Commit + Push
Get Latest Version Pull
‘Map Local Path’ Clone
Shelve Stash (only local though)
Label Tag
‘Compare Local to Server’ Fetch

note: I have only mentioned the concepts that have sort of an equal term in TFVC. Git has many more though and some are the same (conceptually at least as branch and merge for example).

The biggest differences are (from my point of view):

  1. The miniature file system (snapshot concept) that Git has.
  2. You have full control over your own repository. Sync to others once you are ready to.
  3. Branches do not create anything else than a pointer to a commit.
  4. All commits are local operations.
  5. Merges are non-destructive.

Lastly, my experience is that Git works better for ‘continues delivery type of development’. It’s just easier to develop things in isolation and integrate often and in smaller portions (feature branching).
TFVC works better when you work with sprints, a ‘one branch per sprint strategy’ that lives over a longer period of time.

, ,

  1. #1 by Zak Fargo (@zakamus) on April 3, 2014 - 18:29

    Great write up 🙂 Thanks for breaking it down.

  2. #2 by George on April 9, 2014 - 01:15

    technically sounds like a great article. What about the business procepective in more details: wher would you choose TFS vs Git. Git is very trendy these days, but from management prospective I can not see many reasons to go for Git because most of the developers with have a single story / topic/ item / module /bug/ etc to work at one single time – “they have been told” 🙂 am I right?

    • #3 by Johan Leino on April 9, 2014 - 06:41

      Thanks! Is version control a business decision to make really?! I would simply say that git is easier than tfvc…or at least more flexible. I have heard of devs that use git on their own box but when they “push” to the tfs server they switch to tfvc. When you say that devs work on one thing at a time that’s actually a good thing right?! And as I am trying to state…it’s not a matter of git vs tfs…I would say stick to TFS it is a great product…but you might consider to switch from centralized to distributed version control in that same tfs project and git is currently the only other version control implementation supported.

  3. #4 by Sharepoint Samurai on May 29, 2014 - 06:48

    Awesome blog – Exactly what I was looking for!!
    Thank you very much for sharing! I am definitely reblogging and tweeting this post!
    Can you tell me perhaps – In a scenario where I want to support MS’ SharePoint ALM, would you use TFS or GIT and what is the general opinion out there?
    Hybrid models – do they work? (TFS and GIT together)
    Thank you very much!

    • #5 by Johan Leino on May 29, 2014 - 07:14

      In my opinion the reason people use tfvc is of old habits and/or scared of something new. In generally think git is a better source control system despite of ShardPoint or any technology. What do you mean with hybrid? If you are referring to git locally and tfvc on the server then yes, I’ve seen those working but I really don’t see the point of that.

      • #6 by Sharepoint Samurai on May 29, 2014 - 08:16

        Thanks for the answer Johan, really appreciate the kB sharing. I have used GIT before, but only as a Source Control tool, not yet to support a SDLC. Which is what I am looking to do – we have enormeous silos in our company- I feel as SP we should be breaking down these wallls. So I had a session with the team leads(Oh, I’m very new to this company) – Mobile, Java, .Net Custom Dev all use GIT.

        What I couldn’t find out clearly though is less talk about specific technology and how GIT better supports the Dev life cycle they use – A place you clearly have already searched and explored and conquered.

        So my actual question – Which technology (in context of SP – meta tag 🙂 supports the SP ALM the best – TFS or GIT?

        2nd – For better and more cooperation between departments, TFS or GIT or can a Hybrid approach where say Java uses GIT and SP uses TFS work?

        Thanks a mill again for the knowledge sharing – blog and by talking

        Tomas

      • #7 by Johan Leino on May 30, 2014 - 21:36

        Oh, this is like a blog post topic of its own. Maybe I’ll write one of those posts soon… Well anyway the really short answer I’d give you is that git has a much better, and different, approach to branching. That said git support the concept of feature branches in a way I wouldn’t recommend using tfs for. Tfs is better suited for a 2 or 3 branch approach (main/dev/release). I would say that git is more modern and yes thus better suited for how we build software nowadays. So…upgrade to tfs 2013 and use git inside tfs….

  4. #8 by Manohar on July 14, 2014 - 23:49

    article confuses more than answering
    instead of answering in comments, add a main article in a table format — also make points of left, what to use on right
    simple I cant see no reason why Git is better, when my hard disk crashes, all files are lost, esp. when I din’t push yet, do you see a point in having online shelving and central repo? and wy tfs Is better?

    • #9 by Eric Sabine on November 3, 2014 - 18:33

      Regarding your question about when the hard disk fails, I’m sorry but that should specifically be off the table for a discussion like this. I know it’s a serious issue for you, as it is for me and everyone else, but it has nothing to do with using Git for TFS, it’s for a separate strategy discussion about backups. Source code control != backups; Source code control = managing your code’s history of changes.

  5. #10 by Manohar on July 14, 2014 - 23:53

    and, good difference article is at: http://msdn.microsoft.com/en-us/library/ms181368.aspx
    it has double things than explained here to make a strong point

  6. #11 by huoxudong125 on April 30, 2015 - 02:28

    Reblogged this on ITelite.

  7. #12 by jacob1123 on July 15, 2015 - 09:44

    Hi, I just stumbled on your article and you seem to have got the “snapshot” system wrong. Every commit is a full snapshot. Git does not need to look at the parent commit, to be able to ‘show us the complete state of the repository’. The parent is only needed to show the graph.

    • #13 by pmiossec on January 12, 2016 - 10:10

      Indeed, you’re perfectly right!

      >All other files where unchanged thus there will be a pointer to a parent commit.

      That’s not true. The deduplication is made at the “directory object” or “blob object” level.
      You could see it easily by digging in how git store thing and compare 2 following commits using the really simple command ‘git cat-file -p’ from one commit object to a blob object…

      >HEAD is just a reference to the latest commit in the branch you’re currently working on.

      No 😦 HEAD is a reference to what you have checkouted. Most of the time it’s a reference towards a branch, the one you are working on.
      But it only point directly to a commit, when you are in a detached head state (which should happen rarely…).

      You could easily verify it doing ‘cat .git/HEAD’

      And last, in the table comparing, commands, please add ‘stash or branch’ for equivalent of shelve because it’s a bad practice to use stash for storing work other than for very short time other than just because some git commands need clean working folder.

      Please fix your post…

  1. Microsoft: TFVC vs Git – Andy Tsai學習筆記
  2. GitHub for beginners | DotNet Brains

Leave a comment