Как я могу выбрать вишню из репозитория TFVC в репозиторий Git? - PullRequest
0 голосов
/ 07 ноября 2018

Мы только что мигрировали из TFVC в Git, и у нас сразу же возникла проблема - как выбрать TFVC в Git?

С учетом

  • TFVC филиал $/Alice
  • TFVC филиал $/Bob
  • Репозиторий Git с $/Alice перенесен как ветвь alice и $/Bob - как ветвь bob.
  • История TFVC не была перенесена, поэтому вся история TFVC $ / Alice - это всего лишь один коммит Git. То же самое верно для $\Bob.

Проблема

Теперь мы обнаруживаем коммит TFVC в $/Alice, который не был объединен с $/Bob до миграции. Теперь, после миграции, мы понимаем, что она должна быть в ветке bob. Большой облом.

Я говорю о большом изменении - много файлов. Следовательно, диффузия файлов вручную и копирование изменений не очень осуществимы. Мне нужно максимально автоматизировать процесс.

Что я до сих пор делал

Я подумал, что должен создать патч для рассматриваемой ревизии TFVC. Итак, вот код (при условии, что мне нужно выбрать вишню коммит 123):

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

(я делаю это файл за файлом, потому что это намного быстрее, чем запуск tf diff с флагом /r)

В любом случае, я получаю файл патча, подобный этому:

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 stash выглядит немного иначе:

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, чтобы он принял мой патч как патч-тайник. Но дьявол кроется в деталях, а мне их не хватает.

1 Ответ

0 голосов
/ 09 ноября 2018

Я получил следующий скрипт 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
}
...