{"id":4183,"date":"2012-10-16T14:47:37","date_gmt":"2012-10-16T14:47:37","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2012\/10\/16\/locking-and-git-tf-and-danger\/"},"modified":"2019-04-11T14:04:40","modified_gmt":"2019-04-11T22:04:40","slug":"locking-and-git-tf-and-danger","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/devops\/locking-and-git-tf-and-danger\/","title":{"rendered":"Locking and git-tf and&#8230; danger?"},"content":{"rendered":"<p>(The other one of <a href=\"http:\/\/blogs.msdn.com\/b\/ethomson\/\">Edward\u2019s posts<\/a>)\u00a0<\/p>\n<p>&#42;****************************<\/p>\n<p>If you haven&#8217;t yet seen or heard about the new git-tf tool from Microsoft, this blog post probably won&#8217;t make any sense.\u00a0 So&#8230;\u00a0 go check it out over at <a href=\"http:\/\/gittf.codeplex.com\/\">gittf.codeplex.com<\/a>.\u00a0 It&#8217;s okay, I&#8217;ll wait.<\/p>\n<p>Okay, got it?\u00a0 Yeah, I know, it&#8217;s cool, right?\u00a0 Well, it is, but like any software project, there are a few problems.\u00a0 One of them is in the whole <code>git-tf checkin<\/code> process and how it needs to take a lock on your tree before it can continue.\u00a0 I mean, locks are annoying, right?\u00a0 If git-tf requires a lock to do a checkin, then that&#8217;s going to fail if somebody else has already taken a lock somewhere in that folder.\u00a0 And, of course, the default in TFS is to take a lock on binaries, so if you&#8217;ve got some of those in your tree then git-tf is going to complain all the time when you try to checkin.<\/p>\n<p>It&#8217;s even worse when you run into this the first time and decide that we can&#8217;t have been so obnoxious as <em>force<\/em> you to take a lock.\u00a0 Surely those developers put in some no lock option, maybe even called <code>--no-lock<\/code>, that will avoid locking.\u00a0 And we did!\u00a0 And with our appropriately scary warning in the checkin help:<\/p>\n<pre>--no-lock Does not take a lock on the server path before committing (dangerous)<\/pre>\n<p>&#8230;you can see why this is a problem.\u00a0 I mean, it&#8217;s <strong><em>dangerous?!<\/em><\/strong>\u00a0 Who would want to use that!?<\/p>\n<p>Okay, let&#8217;s back up and explain why we decide to take this lock.<\/p>\n<p>Team Foundation Server&#8217;s version control model has good concurrency.\u00a0 Let&#8217;s assume that you and I are both working on the latest version and we both edit some files.\u00a0 If we both hit the checkin button at the same time, this is a classic race condition, but one that&#8217;s harmless.\u00a0 Our checkins get serialized and &#8211; assuming we haven&#8217;t edited any of the same files to produce a conflict &#8211; it really doesn&#8217;t matter all that much which one of us wins this race and which one loses.\u00a0 Both of our changesets got checked in and the next time we do a get latest, we get the other person&#8217;s changes, too.\u00a0 Things get a little bit more complicated if we edit the same file, but not much.\u00a0 The winner of this race gets their changes checked in &#8211; the loser has to resolve a conflict and then checkin again.\u00a0 This is pretty classic version control behavior and a well-understood problem.<\/p>\n<p>git, of course, also has good concurrency.\u00a0 Let&#8217;s assume that you and I are both on HEAD and we both edit some files.\u00a0 If we both were to commit to our local git repository, now we both have new commits that share a common parent.\u00a0 At some point, we&#8217;ll need to merge this branch in the graph, but this is no big deal.\u00a0 Again, a race condition that doesn&#8217;t matter.<\/p>\n<p>git-tf, on the other hand, can&#8217;t cope well with this race condition.\u00a0 (It might be a bit much to have called it <em>dangerous<\/em>, but that little word scared you enough to read this blog post, so I think we&#8217;ll stick with that term for a little while longer.)\u00a0 Here&#8217;s how git-tf checkin works, in a nutshell:<\/p>\n<ol>\n<li>Finds the latest TFS changeset that you&#8217;ve fetched and merged into your graph.\u00a0 This is the &#8220;high water mark&#8221;. <\/li>\n<li>Takes a lock on the TFS path you&#8217;re bridging.\u00a0 Unless, of course, you&#8217;re living dangerously and using that crazy <code>--no-lock<\/code> flag. <\/li>\n<li>Ensures that this high water mark is actually the latest TFS changeset.\u00a0 If not, you will be told to fetch that changeset and merge. <\/li>\n<li>Pends the changes to TFS that are representative of the changes in your git commit and checks them in. <\/li>\n<li>Updates the aforementioned &#8220;high water mark&#8221; to the changeset that I just checked in.<\/li>\n<\/ol>\n<p>Let&#8217;s take another look at this race condition once git-tf gets in the picture.\u00a0 Imagine that I&#8217;m using git-tf and you&#8217;re using some other TFS client like Visual Studio or the TFS plug-in for Eclipse.\u00a0 The latest version is changeset 3, and I&#8217;ve made a git commit on top of that.\u00a0 My git repository looks like this:<\/p>\n<p><img decoding=\"async\" border=\"0\" alt=\"\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2012\/10\/4377.locking-1.png\" \/><\/p>\n<p>I&#8217;m ready to git-tf checkin these changes, and I&#8217;ll do so without a lock.\u00a0 Meanwhile, you&#8217;ve also made some changes against TFS and you&#8217;re going to check in at the same time.\u00a0 If you happen to sneak your changeset in between steps 3 and 4 (above), then I&#8217;ve updated my high-water mark to <em>my<\/em> changeset&#8230;\u00a0 but I never got <em>your<\/em> changeset.<\/p>\n<p>In a perfect world, I would pull your changeset down as a git commit such that it has a parent of 3, and my git commit <code>4fac65...<\/code> has your changeset as a parent.\u00a0 This keeps the linear model of TFS changesets that git-tf strives so hard for.\u00a0 Except that if I do that, my commit can&#8217;t be <code>4fac65...<\/code> anymore, it gets a completely new ID because those are computed based on their parents.\u00a0 Ouch.<\/p>\n<p>The way it is, I&#8217;ll never even see your changes until there&#8217;s a new changeset and I can fetch that, since git-tf&#8217;s high water mark already includes the latest changeset on the server.\u00a0 So it turns out that not locking can be dangerous after all.<\/p>\n<p>Of course, most people don&#8217;t have <em>that<\/em> much churn in their code tree that this is an issue.\u00a0 So you could just check the history in TFS to make sure that nobody else snuck with a new changeset in those few seconds.\u00a0 And if they did, of course, you could just stick a new dummy changeset in TFS so that you could pull the latest version that has the other changes, too.\u00a0 But this isn&#8217;t exactly an ideal workflow.<\/p>\n<p>So the question of course becomes:\u00a0 can we avoid taking a lock, but stay out of danger?\u00a0 We think so.\u00a0 We spun up <a href=\"http:\/\/gittf.codeplex.com\/discussions\/393372\">a conversation over on our codeplex site<\/a> about this &#8211; so if you&#8217;re interested in this topic, we&#8217;d love your feedback.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>(The other one of Edward\u2019s posts)\u00a0 &#42;**************************** If you haven&#8217;t yet seen or heard about the new git-tf tool from Microsoft, this blog post probably won&#8217;t make any sense.\u00a0 So&#8230;\u00a0 go check it out over at gittf.codeplex.com.\u00a0 It&#8217;s okay, I&#8217;ll wait. Okay, got it?\u00a0 Yeah, I know, it&#8217;s cool, right?\u00a0 Well, it is, but like [&hellip;]<\/p>\n","protected":false},"author":81,"featured_media":45953,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4183","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"acf":[],"blog_post_summary":"<p>(The other one of Edward\u2019s posts)\u00a0 &#42;**************************** If you haven&#8217;t yet seen or heard about the new git-tf tool from Microsoft, this blog post probably won&#8217;t make any sense.\u00a0 So&#8230;\u00a0 go check it out over at gittf.codeplex.com.\u00a0 It&#8217;s okay, I&#8217;ll wait. Okay, got it?\u00a0 Yeah, I know, it&#8217;s cool, right?\u00a0 Well, it is, but like [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/4183","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/users\/81"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/comments?post=4183"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/4183\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media\/45953"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media?parent=4183"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/categories?post=4183"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/tags?post=4183"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}