【问题标题】:How can I cherry pick from a TFVC repo to Git repo?如何从 TFVC 存储库中挑选到 Git 存储库?
【发布时间】:2019-04-10 08:57:57
【问题描述】:

我们刚刚从 TFVC 迁移到 Git,马上就遇到了一个问题——如何挑选 TFVC 提交到 Git?

给定

  • TFVC 分支$/Alice
  • TFVC 分支$/Bob
  • 带有$/Alice 的Git 存储库迁移为alice 分支和$/Bob - 作为bob 分支。
  • TFVC 历史未迁移,因此“$/Alice”的整个 TFVC 历史只是一次 Git 提交。 $\Bob 也是如此。

问题

现在我们在 $/Alice 中发现了一个 TFVC 提交,它在迁移之前没有合并到 $/Bob。现在在迁移之后,我们意识到我们需要将它放在bob 分支中。大败笔。

我说的是一个很大的变化——很多文件。因此,手动区分文件并复制更改不是很可行。我需要尽可能地自动化这个过程。

到目前为止我做了什么

我想我应该为有问题的 TFVC 变更集创建一个补丁。所以,这里是代码(假设我需要挑选提交 123):

$files = (tf changeset /noprompt 123 | sls '\$/') -replace '^[^$]+',''
$files |% { tf diff /version:C122~C123 /format:unified $_ } >> 123.diff

(我一个一个文件一个文件来做,因为它比使用/r标志运行tf diff要快得多)

无论如何,我得到一个像这样的补丁文件:

File: BackgroundJobTests\BackgroundJobTests.csproj
===================================================================
--- Server: BackgroundJobTests.csproj;115493
+++ Server: BackgroundJobTests.csproj;389742
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
===================================================================
File: BI\a8i\a8i.csproj
===================================================================
--- Server: a8i.csproj;342293
+++ Server: a8i.csproj;389742
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
...

一个典型的 Git 存储补丁看起来有点不同:

diff --git a/Yogi.txt b/Yogi.txt
index 056fd9e..1f73d44 100644
--- a/Yogi.txt
+++ b/Yogi.txt
@@ -1 +1 @@
-yaba daba do
+yaba daba doo
diff --git a/hello.txt b/hello.txt
index ce01362..980a0d5 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1 @@
-hello
+Hello World!

我觉得我需要一些指导。也许我做错了,有一个现成的解决方案可以解决我的痛苦。或者也许我的方向是正确的,我所需要的只是一种“欺骗”Git 接受我的补丁作为隐藏补丁的方法。但魔鬼在细节中,我缺少它们。

【问题讨论】:

    标签: git migration tfvc cherry-pick git-cherry-pick


    【解决方案1】:

    我最终得到了以下 Powershell 脚本:

    param(
        [Parameter(Mandatory = $true, Position = 0)]$SrcBaseDir, 
        [Parameter(Mandatory = $true, Position = 1)]$SrcRepo,
        [Parameter(Mandatory = $true, Position = 2)]$DstBaseDir, 
        [Parameter(Mandatory = $true, Position = 3)][int]$Changeset)
    
    [io.directory]::SetCurrentDirectory($DstBaseDir)
    cd $SrcBaseDir
    $files = @((tf changeset /noprompt $Changeset | sls '\$/') -replace '^[^$]+','')
    Write-Host -ForegroundColor Green "Found $($files.Length) files"
    
    cd $DstBaseDir
    $GitStatus = git status --porcelain
    $FailedPatches = @{}
    $PatchFilePathPrefix = "$env:TEMP\$(Get-Date -Format 'yyyyMMddHHmmss')_"
    $NotFound = @()
    $Modified = @()
    $i = 0
    $files |% {
        ++$i
        $TargetFile = $_.Substring($SrcRepo.Length)
        if (!(Test-Path $TargetFile))
        {
            Write-Host -ForegroundColor Yellow "[$i] not found skipped $TargetFile"
            $NotFound += $TargetFile
        }
        elseif ($GitStatus | sls -SimpleMatch $TargetFile)
        {
            # Very important - git status returns wrong result if the case is different
            # This is why I pipe it through PowerShell Select-String command which lets me check
            # the status case insensitively
            Write-Host -ForegroundColor Yellow "[$i] already modified skipped $TargetFile"
            $Modified += $TargetFile
        }
        else 
        {
            Write-Host -ForegroundColor Green "[$i] $TargetFile"
            pushd $SrcBaseDir
            try
            {
                $patch = tf diff /version:"C$($Changeset - 1)~C$Changeset" /format:unified $_
            }
            finally
            {
                popd
            }
    
            $PatchFileName = "${PatchFilePathPrefix}$($TargetFile -replace '[\\/]','_').patch"
            $patch `
                -replace "^--- Server: .*","--- a/$TargetFile" `
                -replace "^\+\+\+ Server: .*","+++ b/$TargetFile" | Out-File -Encoding utf8 $PatchFileName
    
            $res = git apply --whitespace=nowarn $PatchFileName 2>&1
            $failed = $LASTEXITCODE
            if ($failed)
            {
                $bytes = [io.file]::ReadAllBytes($TargetFile)
                $BOMCount = 0
                while ($bytes[$BOMCount] -gt 127)
                {
                    ++$BOMCount
                }
                if ($BOMCount)
                {
                    $fs = [io.file]::Create($TargetFile)
                    $fs.Write($bytes, $BOMCount, $bytes.Length - $BOMCount)
                    $fs.Close()
                    $res = git apply --whitespace=nowarn $PatchFileName 2>&1
                    $failed = $LASTEXITCODE
                    if ($failed)
                    {
                        [io.file]::WriteAllBytes($TargetFile, $bytes)
                    }
                    else
                    {
                        $NewBytes = [io.file]::ReadAllBytes($TargetFile)
                        $fs = [io.file]::Create($TargetFile)
                        $fs.Write($bytes, 0, $BOMCount)
                        $fs.Write($NewBytes, 0, $NewBytes.Length)
                        $fs.Close();
                    }
                }
            }
            if ($failed)
            {
                $res |% {
                    if ($_ -is [Management.Automation.ErrorRecord])
                    {
                        $_.Exception.Message
                    }
                    else
                    {
                        $_
                    }
                } | Write-Host -ForegroundColor Red
                $FailedPatches[$TargetFile] = $PatchFileName
            }
            else 
            {
                del $PatchFileName
            }
        }
    }
    @{
        Failed = $FailedPatches
        NotFound = $NotFound
        AlreadyModified = $Modified
    }
    

    【讨论】:

      猜你喜欢
      • 2015-07-14
      • 2020-01-03
      • 2018-07-27
      • 2020-09-19
      • 2020-01-13
      • 1970-01-01
      • 2020-10-25
      • 1970-01-01
      • 2014-10-21
      相关资源
      最近更新 更多