2012-11-28 50 views
2

我將我的工作文件夾設置爲RAM驅動器。夜間發生延時停電,UPS耗盡,機器停機。幸運的是,在我回家之前,我擱置了所做的更改,並且可以在團隊資源管理器中看到shelveset。變更集包括項目文件和一些尚未添加到源代碼管理的新文件。TFS崩潰 - 如何恢復擱置的更改

我試圖恢復受影響的文件,但我得到的錯誤:

試圖查看擱置的文件給出了TF10187(或一般的,未編號)The system cannot find the file specified即使我能看到他們在Pending Changes列表。

試圖取消整個集合的完整性給出了我無法解決的有關incompatible changes的錯誤。

猜測 TFS緩存擱置本地RAM盤這已經重新初始化本身,並因此失去了高速緩存上,但我希望我錯了。

任何人都可以協助嗎?

+0

同樣的情況,但對於TFS2015。我發佈瞭解決方案http://stackoverflow.com/questions/42233302/tfs2015-how-can-i-recover-shelved-changes –

回答

5

昨天我有人來找我問相同的問題,幸運的是他們有了TFS項目數據庫(tfs_)的備份,所以我們將它恢復到另一個數據庫,並且繞過並找出它(所以,如果你有備份然後是的,你可以恢復所有的文件)。

首先是關於數據庫中表格的一些信息。

Shelveset可以通過查詢tbl_Workspace表並查找Type = 1(Shelveset)的所有記錄來標識,當然也可以按名稱過濾WorkspaceName列。

感興趣的其他表如下:

tbl_PendingChanges(引用自tbl_Workspace的WorkspaceId) - 該文件是擱置

tbl_VersionedItem(通過ITEMID列掛tbl_PendingChanges)的一部分 - 父路徑和名稱文件

tbl_Content(通過FILEID掛PendingChanges) - 這是你的文件內容存儲在爲壓縮(gzip的)數據

現在的解決方案;下面的查詢可以告訴你你的文件:

SELECT c.[CreationDate], c.[Content], vi.[ChildItem], vi.ParentPath 
FROM [dbo].[tbl_Content] c 
INNER JOIN [dbo].[tbl_PendingChange] pc ON pc.FileId = c.FileId 
INNER JOIN [dbo].[tbl_Workspace] w ON w.WorkspaceId = pc.WorkspaceId 
INNER JOIN [dbo].[tbl_VersionedItem] vi ON vi.ItemId = pc.ItemId 
WHERE w.WorkspaceName = '<YOUR SHELVESET NAME>' 

隨着我寫一些代碼來獲取數據從SQL回來,然後解壓縮與GZipStream類的內容和保存文件從磁盤。

一個星期的工作回來了一個小時左右。

這是用TFS 2010.完成的。

希望這有助於!

+0

非常感謝您的回覆。不幸的是,由於時間的壓力,我最終不得不重寫丟失的代碼以符合截止日期。但是這是我下一次的'基本'技術列表。或者直到我們切換到'git' ;-) – 5arx

2

我在TFS 2012實例中發生了類似的事情。我的SQL查詢有點不同,因爲TFS 2012的模式發生了變化。希望這可以幫助某人。

SELECT c.[CreationDate], c.[Content], v.FullPath 
FROM [dbo].[tbl_Content] c 
INNER JOIN [dbo].[tbl_File] f ON f.ResourceId = c.ResourceId 
INNER JOIN [dbo].[tbl_PendingChange] pc ON pc.FileId = f.FileId--c.FileId 
INNER JOIN [dbo].[tbl_Workspace] w ON w.WorkspaceId = pc.WorkspaceId 
INNER JOIN [dbo].[tbl_Version] v ON v.ItemId = pc.ItemId AND v.VersionTo = 2147483647 
WHERE w.WorkspaceName = @ShelvesetName 

2147483647似乎是2^32 - 1,我認爲可以代表在TFS 2012「最新」後來我也寫了一個C#小部件的解壓gzip編碼流和轉儲到磁盤正確的文件名稱。我不保留層次結構。

string cnstring = string.Format("Server={0};Database={1};Trusted_Connection=True;", txtDbInstance.Text, txtDbName.Text); 
SqlConnection cn = new SqlConnection(cnstring); 
SqlCommand cmd = new SqlCommand(@" 
SELECT c.[CreationDate], c.[Content], v.FullPath 
FROM [dbo].[tbl_Content] c 
INNER JOIN [dbo].[tbl_File] f ON f.ResourceId = c.ResourceId 
INNER JOIN [dbo].[tbl_PendingChange] pc ON pc.FileId = f.FileId--c.FileId 
INNER JOIN [dbo].[tbl_Workspace] w ON w.WorkspaceId = pc.WorkspaceId 
INNER JOIN [dbo].[tbl_Version] v ON v.ItemId = pc.ItemId AND v.VersionTo = 2147483647 
WHERE w.WorkspaceName = @ShelvesetName", cn); 

cmd.Parameters.AddWithValue("@ShelvesetName", txtShelvesetName.Text); 

DataTable dt = new DataTable(); 
new SqlDataAdapter(cmd).Fill(dt); 
listBox1.DisplayMember = "FullPath"; 
listBox1.ValueMember = "FullPath"; 
listBox1.DataSource = dt; 

if(!Directory.Exists(txtOutputLocation.Text)) { Directory.CreateDirectory(txtOutputLocation.Text); } 
foreach (DataRow row in dt.Rows) 
{ 
    string[] arrFilePath = row[2].ToString().Split('\\'); 
    string fileName = arrFilePath[arrFilePath.Length - 2]; 
    byte[] unzippedContent = Decompress((byte[])row[1]); 
    File.WriteAllBytes(Path.Combine(txtOutputLocation.Text, fileName), unzippedContent); 
} 
} 

    static byte[] Decompress(byte[] gzip) 
    { 
using(GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress)) 
{ 
    const int size = 4096; 
    byte[] buffer = new byte[size]; 
    using(MemoryStream memory = new MemoryStream()) 
    { 
     int count = 0; 
     do 
     { 
    count = stream.Read(buffer, 0, size); 
    if(count > 0) 
    { 
     memory.Write(buffer, 0, count); 
    } 
     } 
     while(count > 0); 
     return memory.ToArray(); 
    } 
} 
} 
+0

這非常有幫助。我能夠從數據庫備份中獲得丟失的工作。絕對的「神派」。謝謝。 – wavedrop

+0

你可以擴展如何運行這個C#代碼嗎? – MAW74656

2

這是TFS2015的更新響應,它有另一個模式更改。以下是用於將txt文件寫入桌面的C#控制檯應用程序。確保填寫connString和shelvesetName變量。

using System; 
using System.Data; 
using System.Data.SqlClient; 
using System.IO; 
using System.IO.Compression; 

namespace RestoreTFSShelve 
{ 
    internal class Program 
    { 
     private static void Main(string[] args) 
     { 
      string shelvesetName = ""; 
      string connString = ""; 

      SqlConnection cn = new SqlConnection(connString); 
      SqlCommand cmd = new SqlCommand(@" 
SELECT c.[CreationDate], c.[Content], v.FullPath 
FROM [dbo].[tbl_Content] c 
INNER JOIN [dbo].tbl_FileMetadata f ON f.ResourceId = c.ResourceId 
INNER JOIN [dbo].tbl_FileReference b ON f.ResourceId = b.ResourceId 
INNER JOIN [dbo].[tbl_PendingChange] pc ON pc.FileId = b.FileId 
INNER JOIN [dbo].[tbl_Workspace] w ON w.WorkspaceId = pc.WorkspaceId 
INNER JOIN [dbo].[tbl_Version] v ON v.ItemId = pc.ItemId AND v.VersionTo = 2147483647 
WHERE w.WorkspaceName = '@ShelvesetName'", cn); 

      cmd.Parameters.AddWithValue("@ShelvesetName", shelvesetName); 

      DataTable dt = new DataTable(); 
      new SqlDataAdapter(cmd).Fill(dt); 

      foreach (DataRow row in dt.Rows) 
      { 
       string[] arrFilePath = row[2].ToString().Split('\\'); 
       string fileName = arrFilePath[arrFilePath.Length - 2]; 
       byte[] unzippedContent = Decompress((byte[])row[1]); 
       File.WriteAllBytes(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), fileName), unzippedContent); 
      } 
     } 

     private static byte[] Decompress(byte[] gzip) 
     { 
      using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress)) 
      { 
       const int size = 4096; 
       byte[] buffer = new byte[size]; 
       using (MemoryStream memory = new MemoryStream()) 
       { 
        int count = 0; 
        do 
        { 
         count = stream.Read(buffer, 0, size); 
         if (count > 0) 
         { 
          memory.Write(buffer, 0, count); 
         } 
        } 
        while (count > 0); 
        return memory.ToArray(); 
       } 
      } 
     } 
    } 
}