<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Congyi's TFS Version Control Brain Dump</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/congyiw/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/congyiw/feed.xml</link>
    <description />
    <lastBuildDate>Wed, 17 Apr 2019 03:41:26 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Git: Stop changing http.postBuffer...</title>
      <link>https://docs.microsoft.com/archive/blogs/congyiw/git-stop-changing-http-postbuffer</link>
      <pubDate>Thu, 02 Jun 2016 05:01:38 GMT</pubDate>
      <dc:creator><![CDATA[Congyi Wu (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/congyiw/?p=275</guid>
      <description><![CDATA[EDIT (5/26/2017): added "Check if these hotfixes are applicable if your TFS server is running...]]></description>
      <content:encoded><![CDATA[EDIT (5/26/2017): added "Check if these hotfixes are applicable if your TFS server is running Windows 2012 R2 or earlier" section

If you see an <code>RPC failed</code> error during <code>git push</code>, like...

<code>error: RPC failed; result=22, HTTP code = 404
</code>

or

<code>error: RPC failed; result=22, HTTP code = 411
</code>

or

<code>Unable to rewind rpc post data - try increasing http.postBuffer
error: RPC failed; result=56, HTTP code = 0
</code>

... and search for help on <a href="https://stackoverflow.com/questions/2702731/git-fails-when-pushing-commit-to-github">Stack Overflow</a> or <a href="https://social.msdn.microsoft.com/Forums/vstudio/en-US/cdeb11b8-5c79-4563-bf7d-db969e2e951d/tfs-2013-visual-studio-online-git-push-size-limitation?forum=TFService">MSDN forums</a>, you'll see a lot of old recommendations to set <code>http.postBuffer</code>.

<strong>Don't</strong> do it! At least not blindly. Instead:
<!--more-->
<h3>Upgrade Git</h3>
If you're still running a Git client that's version 1.9.5 or older(!) you should really upgrade Git first (we’re up to 2.8+ now). There are a bug fixes (like <a href="https://thread.gmane.org/gmane.comp.version-control.git/235793/focus=235794">this one</a>) in newer versions of Git that should obviate the need to set <code>http.postBuffer</code>.

We had enough support requests from internal users and external customers hitting bugs in older versions of Git that we decided to add a server-side reminder to TFS/VSTS a few sprints ago:
<code>
M:\tmp\foo&gt;git fetch
remote: Microsoft (R) Visual Studio (R) Team Services
remote: We noticed you're using an older version of Git. For a better experience, upgrade to the latest version at https://git-scm.com/downloads
remote: Found 4 objects to send. (6 ms)
Unpacking objects: 100% (4/4), done.
</code>
<h3>Check if these hotfixes are applicable if your TFS server is running Windows 2012 R2 or earlier</h3>
<ul>
  <li><a href="https://support.microsoft.com/en-us/help/3100477/a-large-file-upload-or-a-large-repository-clone-fails-on-vso-in-windows-server-2012-r2">A large file upload or a large repository clone fails on VSO in Windows Server 2012 R2</a></li>
  <li><a href="https://support.microsoft.com/en-us/help/4017691/pushing-large-files-to-team-foundation-server-by-git-client-hangs">Pushing large files to Team Foundation Server by Git client hangs</a></li>
</ul>
<h3>Check if you're using a proxy or load balancer</h3>
If you're using a terrible proxy that's buggy or doesn’t support chunked encoding, you'll see errors for larger pushes. The same thing can happen if you put on-prem TFS behind a misconfigured load balancer. If the same push succeeds when bypassing the proxy, or bypassing the load balancer (e.g. by pushing to localhost from the server itself), then fix your proxy or load balancer instead!
<h3>What if my proxy or load balancer is broken, but I don't have any control over it?</h3>
This is the only scenario that I've seen where setting http.PostBuffer is useful for newer versions of Git.
<h3>Is setting http.postBuffer harmful?</h3>
AFAICT, it's more <em>unnecessary </em> than <em>harmful</em>, but there are a few negative side effects:
<ul>
	<li>Increasing it above the default may increase latency for larger pushes (since the client will buffer the HTTP request into larger chunks).</li>
	<li>If you set it larger than the HTTP chunk size limit for your HTTP server (e.g. <code>maxAllowedContentLength</code> and <code>maxRequestLength</code> in web.config for TFS servers), then all pushes larger than the chunk size limit will start failing.</li>
</ul>
<h3>How do I unset http.postBuffer if I've already set it?</h3>
To check if it's set, run:
<code>
git config --show-origin --get-all http.postBuffer
</code>

You may have to unset it in both your global <code>.gitconfig</code> file:
<code>
git config --global --unset http.postBuffer
</code>
As well as in your repo level <code>.git/config</code> (which overrides the global setting):
<code>
git config --local --unset http.postBuffer
</code>]]></content:encoded>
    </item>
    <item>
      <title>Why does cloning from VSTS return old unreferenced objects?</title>
      <link>https://docs.microsoft.com/archive/blogs/congyiw/why-does-cloning-from-vsts-return-old-unreferenced-objects</link>
      <pubDate>Mon, 14 Dec 2015 17:44:00 GMT</pubDate>
      <dc:creator><![CDATA[Congyi Wu (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/congyiw/2015/12/14/why-does-cloning-from-vsts-return-old-unreferenced-objects/</guid>
      <description><![CDATA[UPDATE (2017-08-09):
We rolled out commit reachability bitmap indexes to VSTS and removed the clone...]]></description>
      <content:encoded><![CDATA[<h3>UPDATE (2017-08-09):</h3>
We rolled out commit reachability bitmap indexes to VSTS and removed the clone cheat mentioned below. <strong>Cloning will no longer download unreachable objects!</strong>. We still don't have true object-level <code>git gc</code> on the server yet, but clone sizes will be smaller now.

TFS on-prem will get these changes in v.Next (not in any TFS 2017 updates, but the next major release). As <a href="https://blogs.msdn.microsoft.com/bharry/2017/08/08/vsts-update-aug-4/">Brian Harry mentioned</a>, we should have a release candidate for v.Next in a few weeks.

We'll probably expand on this in future blog posts, but unlike core Git, we use <a href="https://roaringbitmap.org/">Roaring bitmaps</a> instead of EWAH bitmaps.  <a href="https://lemire.me/en/">Daniel Lemire</a> has some great blog posts and publications on bitmap indexes that we greatly enjoyed and benefited from.
<h3>Original Post:<span> </span></h3>
Note: "core Git" refers to the <a href="https://git-scm.com/">official base Git implementation</a>, as opposed to Visual Studio or GitHub, or VSTS, which may involve non-standard implementations or behavior.

A customer asked:
<blockquote>We removed some unwanted binaries from our repo on visualstudio.com by following the instructions at <a href="https://help.github.com/articles/remove-sensitive-data/">https://help.github.com/articles/remove-sensitive-data/</a>. We force-pushed to master and deleted all our other branches.

After running <code>git gc</code> locally, our local repo is now 5 MB, but git clone from visualstudio.com still returns 100MB. The old unreferenced blobs are still being sent down by the server.

How do we <code>git gc</code> (or some equivalent) on the server as well?</blockquote>
There are two issues here:
<ol>
 	<li>There is no equivalent to <code>git gc</code> on VSTS yet.

Our server preserves the history of every ref/branch update to Git repos, including deleted branches. This is analogous to the "reflog" in core Git. On VSTS, we expose the reflog via the REST API and the Branch Updates (i.e. pushes) tab in Web Access. Similarly to core Git, objects in the reflog are still considered to be referenced and will not be deleted by <code>git gc</code>. Core Git can eventually prune old reflog entries via <code>git prune</code> or <code>git gc</code>, but VSTS does not have that functionality yet.</li>
 	<li>Large fetches are expensive for the server to calculate, so we cheat a little.

Large fetches (and clones) have historically been very expensive in both core Git and VSTS due to the "counting objects" phase. https://githubengineering.com/counting-objects/ has a nice explanation of the problem, as well as how core Git and GitHub have (cleverly) improved the perf w/ bitmap indexes.

Unfortunately, VSTS does not have that perf fix yet. Instead, it cheats a bit and blindly streams back every object that exists on the server if the client has nothing and is asks for all branches and tags (e.g. for git clone). This is generally reasonable, until a user decides to dereference most of the objects in their repo to save space!</li>
</ol>
I suspect that the customer would not have minded the lack of gc in his scenario if we only sent reachable objects during clone.

Until these issues are fixed for VSTS, what workarounds are there?
<ul>
 	<li>Delete the repo from the server (EDIT: or rename it) and re-push it.

This works, but is sub-optimal.  In the new repo, you won't be able to see old pull request details, branch update history, and any links from other areas like builds or work items.</li>
 	<li>Trick the server by not cloning everything at once:
<pre>mkdir newRepo
git init
git remote add origin 
#fetch one branch first
git fetch origin master
#fetch everything else
git fetch origin
</pre>
</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>How to capture a Fiddler trace for Git for Windows</title>
      <link>https://docs.microsoft.com/archive/blogs/congyiw/how-to-capture-a-fiddler-trace-for-git-for-windows</link>
      <pubDate>Fri, 19 Dec 2014 21:27:00 GMT</pubDate>
      <dc:creator><![CDATA[Congyi Wu (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/congyiw/2014/12/19/how-to-capture-a-fiddler-trace-for-git-for-windows/</guid>
      <description><![CDATA[Prerequisites to download/install:

Git for Windows (https://git-scm.com/)
Fiddler...]]></description>
      <content:encoded><![CDATA[<p>Prerequisites to download/install:</p>
<ul>
<li>Git for Windows (<a href="https://git-scm.com/" target="_blank">https://git-scm.com/</a>)</li>
<li>Fiddler (<a href="https://www.telerik.com/fiddler" target="_blank">https://www.telerik.com/fiddler</a>)</li>
<li>gitfiddler.cmd (attached at bottom)</li>
</ul>
<p>Steps:</p>
<ol>
<li>Run gitfiddler.cmd in a new command prompt. &nbsp;This script configures git.exe to use Fiddler as a proxy, and then waits for a key press. &nbsp;Once a key is pressed, the script clears the settings that it sets, and then exists.</li>
<ul>
<li>Leave the script running for now.</li>
<li>READ the script before running it!</li>
</ul>
<li>Start Fiddler</li>
<ul>
<li>If you are using HTTPS, enable HTTPS decryption (<a href="https://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/DecryptHTTPS" target="_blank">https://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/DecryptHTTPS</a>)</li>
</ul>
<li>Run your git commands</li>
<li>Select the captured requests in Fiddler and save them in a ArchiveZip (*.saz) file.</li>
</ol>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/34/65/2728.fiddler.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-34-65/2728.fiddler.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/34/65/2728.fiddler.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-34-65/2728.fiddler.png" alt="" border="0" /></a></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/10/58/20/94/gitfiddler.cmd" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-10-58-20-94/gitfiddler.cmd">gitfiddler.cmd</a></p>]]></content:encoded>
    </item>
    <item>
      <title>TFS Version Control Permissions - Why can't I Branch/Rename/Delete X?</title>
      <link>https://docs.microsoft.com/archive/blogs/congyiw/tfs-version-control-permissions-why-cant-i-branchrenamedelete-x</link>
      <pubDate>Thu, 20 Oct 2011 14:14:00 GMT</pubDate>
      <dc:creator><![CDATA[Congyi Wu (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/congyiw/2011/10/20/tfs-version-control-permissions-why-cant-i-branchrenamedelete-x/</guid>
      <description><![CDATA[UPDATE: Will Lennon has a new blog post with nicer instructions for investigating permissions in Web...]]></description>
      <content:encoded><![CDATA[<p><strong>UPDATE:</strong> Will Lennon has a <a href="https://blogs.msdn.com/b/wlennon/archive/2015/09/21/what-are-my-version-control-permissions-on-visual-studio-online.aspx">new blog post</a> with nicer instructions for investigating permissions in Web Access.</p>
<h4>If you see one of the following errors when branching [<a title="1" href="#footnote1">1</a>] or renaming a path in TFS:</h4>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">TF14098: Access Denied: User DOMAIN\Bob needs Read permission(s) for $/p0/folder/*.</span></p>
<h4>Or the following error when checking in:</h4>
<p style="padding-left: 30px;"><span style="font-family: 'courier new', courier;">TF14098: Access Denied: User DOMAIN\Bob needs Checkin permission(s) for $/p0/folder/*.</span></p>
<p><br />You can follow these steps to figure out which permission entries are blocking your operation.&nbsp; The instructions are for when you do not have Read permissions, but apply to Checkin permissions as well (just replace Read with Checkin)</p>
<h4><br />These are the scenarios that can result in DOMAIN\Bob not having Read permission on $/p0/folder/a.txt</h4>
<ol>
<li>
<p><strong>The Read permission is explicitly denied</strong> for $/p0/folder/a.txt for DOMAIN\Bob, or a group that he belongs to.</p>
</li>
<ul>
<li>
<p>Note that group membership includes both direct and indirect membership (e.g. Bob belongs to subgroup which belongs to supergroup).</p>
</li>
</ul>
<li>
<p><strong>The Read permission is unset for a.txt</strong> and all&nbsp;parent folders that it's inheriting permissions from, for Bob or any groups he belongs to. Unset permissions default to implicitly denied.</p>
</li>
<ul>
<li>
<p><strong>Note that you can hit this case when permission inheritance is turned off for a.txt or one of it's parents.</strong></p>
</li>
</ul>
<li>
<p>The Read permission is&nbsp;explicitly denied on a parent of $/p0/folder/a.txt for DOMAIN\bob or a group that he belongs to. If this permission is not overridden at a lower level, $/p0/folder/a.txt will have&nbsp;inherit the deny entry.</p>
</li>
<li>
<p>If there are multiple applicable entries, denies&nbsp;will override allows. &nbsp;If Contributors are denied Read access, and Bob belongs to Contributors, giving Bob Read access will not actually give him Read access</p>
</li>
<ul>
<li>
<p>The way to fix this is to either scope the deny down to a smaller group that Bob does not belong to, or turn off inheritance and leave permissions unset instead of using deny entries at all.</p>
</li>
</ul>
</ol>
<h4>To diagnose what entry is causing issues [<a href="#footnote2">2</a>]:</h4>
<ol>
<li><strong>The following steps are only guaranteed to work if you authenticate as a member of the Team Foundation Administrators group (for the entire instance) or the Team Project Collection Administrators group.</strong>&nbsp; Being an ordinary user or a&nbsp;member of the Team Project Administrators group is insufficient.&nbsp; That is because if you do not have Read permissions, TFS will&nbsp;not tell you don&rsquo;t have Read permissions.&nbsp; The exception is that the special Administrators groups are always allowed to see all paths and permissions.&nbsp; This is to keep Administrators from accidentally locking themselves out. Administrators will still get Access Denied errors, but they can at least see and fix the offending permissions entries.</li>
<li>In a Visual Studio Command Prompt, run&nbsp;<span style="font-family: courier new,courier;">tfssecurity /imx&nbsp;DOMAIN\Bob /server:https://SERVER:8080/tfs</span>&nbsp;to get the list of groups Bob belongs to, directly, or indirectly.</li>
<li>In the same prompt, run <span style="font-family: courier new,courier;">tf permission $/p0/folder /recursive &gt; out.txt</span>, and open out.txt in a&nbsp;text editor that supports regex search (like Visual Studio):</li>
<ul>
<li>Note the use of the /recursive flag</li>
<li>We are redirecting output to a text file because there may be&nbsp;ton of entries</li>
<li>Search for any&nbsp;paths that include the following entries:</li>
<ul>
<li>&ldquo;Inherit: No&rdquo; where there is no explicit Allow: Read entry for the user or one of the groups he belongs to directly/indirectly</li>
<li>&ldquo;Deny.*Read&rdquo; (use a regex search) for Bob or any groups that tfssecurity showed.</li>
</ul>
</ul>
</ol>
<p>&nbsp;</p>
<p><a name="footnote1"></a>[1] We block server side branching (which checks in immediately without pending changes in your&nbsp;workspace) if you don't have recursive Read permissions on the source. Operations that result in server-side branches include:</p>
<ul>
<li>tf branch /checkin</li>
<li>the VersionControlServer.CreateBranch() client object model call</li>
<li>Branching from a Branch Object in Source Control Explorer</li>
</ul>
<p>We do this because:</p>
<ul>
<li>If the user doesn't have Read permission on an item in the source, he shouldn't be allowed to branch that item</li>
<li>If&nbsp;TFS offered to skip those items, it could only&nbsp;tell the user that one or more items will be skipped, not which items will be skipped.&nbsp; The user doesn't have Read permissions, so disclosing the affected paths could leak sensitive information.</li>
<li>If we allow the user to skip any items, there is&nbsp;no way for the user to figure out if anything important is missing from the new branch&nbsp;without talking to an Admin.&nbsp; In that case, the user might as well have the Admin perform the branch anyway.</li>
</ul>
<p>If you pend a branch instead (a non-server side branch), then we silently skip files with no Read perms. I consider that a bug (and have filed it): it should show a warning that one or more items couldn't be branched. Otherwise there is no way to trust that the branch is complete. Even an admin may be affected by explicit denies or disabled inheritance.<br /><br /><br /><a name="footnote2"></a>[2]I've heard on the MSDN forums that the TFS Permissions Sidekick from Attrice&nbsp;has a&nbsp;better UI for figuring out where you don't have Read access, but I've never used it.</p>]]></content:encoded>
    </item>
    <item>
      <title>hello world</title>
      <link>https://docs.microsoft.com/archive/blogs/congyiw/hello-world-2</link>
      <pubDate>Tue, 22 Feb 2011 13:40:00 GMT</pubDate>
      <dc:creator><![CDATA[Congyi Wu (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/congyiw/2011/02/22/hello-world-2/</guid>
      <description><![CDATA[hello world
test post]]></description>
      <content:encoded><![CDATA[<p>hello world</p>
<p>test post</p>]]></content:encoded>
    </item>
  </channel>
</rss>