将同一主干的分支合并到其中一个分支

Merging branches from the same trunk into one of the branches

下图显示了我们拥有的 (RGB) 和我们想要的 (紫色)。

在不同的时间,我们从主干做了三个分支(特征A到C)。我们已经更新(合并)了从主干到每个分支的更改。

我们可以将每个分支合并到trunk但是,我们想将分支B和C合并到A,并在分支A上继续开发。

这可能吗,因为分支 B 和 C 不是从 A 创建的,而是从 trunk 创建的?

您需要使用 2-URL 合并,正如 svn help merge 中的文字所解释的那样:

  1. This form is called a '2-URL merge':

    svn merge SOURCE1[@REV1] SOURCE2[@REV2] [TARGET_WCPATH]

    You should use this merge variant only if the other variants do not apply to your situation, as this variant can be quite complex to master.

    Two source URLs are specified, identifying two trees on the same branch or on different branches. The trees are compared and the difference from SOURCE1@REV1 to SOURCE2@REV2 is applied to the working copy of the target branch at TARGET_WCPATH. The target branch may be the same as one or both sources, or different again. The three branches involved can be completely unrelated.

    [...]

    2-URL Merge Example:

    Two features have been developed on separate branches called 'foo' and 'bar'. It has since become clear that 'bar' should be combined with the 'foo' branch for further development before reintegration.

    Although both feature branches originate from trunk, they are not directly related -- one is not a direct copy of the other. A 2-URL merge is necessary.

您说每个分支都已将 trunk 的所有更改合并到其中,因此不需要为第一个源指定修订。

首先彻底检查您的 A 分支。然后,合并 BA:

svn merge ^/trunk ^/branches/B

这会将 Btrunk 之间的差异合并到您的工作副本中,即 A.验证并提交这些更改(您可以通过在上述命令中将 diff 替换为 merge 来预览合并):

svn commit -m "Merging B to A"

接下来,合并CA

svn merge ^/trunk ^/branches/C

这会将 Ctrunk 之间的差异合并到您的工作副本中,即 AB 的变化。验证并提交这些更改,现在您的 A 分支将拥有所有 BC的变化。


为了验证这一点,我创建了一个简单的脚本(Windows 批处理文件)。它首先设置一些路径常量:

@ECHO OFF

SET CWD=%~dp0
SET REPO_NAME=repo
SET REPO_PATH="%CWD%%REPO_NAME%"
SET WC_NAME=wc
SET WC_PATH="%CWD%%WC_NAME%"

:: Create REPO URI (C:\path\to\repo -> file:///C:/path/to/repo, see 
FOR /f "delims=" %%R IN (%REPO_PATH%) DO SET REPO_URL=%%~fR%
SET REPO_URL=file:///%REPO_URL%
SET REPO_URL=%REPO_URL:///\=//%
SET REPO_URL=%REPO_URL:\=/%
SET REPO_URL="%REPO_URL%"

:: Cleanup previous run
RMDIR /S /Q %REPO_PATH%
RMDIR /S /Q %WC_PATH%

然后创建存储库和结帐主干:

svnadmin create %REPO_PATH%
svn mkdir %REPO_URL%/trunk -m "Creating trunk directory"
svn mkdir %REPO_URL%/branches -m "Creating branches directory"

:: Checkout trunk
svn checkout %REPO_URL%/trunk %WC_PATH%

交替创建虚拟内容和分支,使分支具有不同的内容:

echo alpha > %WC_PATH%\alpha.txt
svn add %WC_PATH%\alpha.txt
svn commit %WC_PATH% -m "Creating alpha.txt in trunk"
svn copy %REPO_URL%/trunk %REPO_URL%/branches/A -m "Creating branch A"

echo beta > %WC_PATH%\beta.txt
svn add %WC_PATH%\beta.txt
svn commit %WC_PATH% -m "Creating beta.txt in trunk"
svn copy %REPO_URL%/trunk %REPO_URL%/branches/B -m "Creating branch B"

echo gamma > %WC_PATH%\gamma.txt
svn add %WC_PATH%\gamma.txt
svn commit %WC_PATH% -m "Creating gamma.txt in trunk"
svn copy %REPO_URL%/trunk %REPO_URL%/branches/C -m "Creating branch C"

echo delta > %WC_PATH%\delta.txt
svn add %WC_PATH%\delta.txt
svn commit %WC_PATH% -m "Creating delta.txt in trunk"

现在通过从主干合并来同步分支:

svn switch %REPO_URL%/branches/A %WC_PATH%
svn merge %REPO_URL%/trunk %WC_PATH%
svn commit %WC_PATH% -m "Synchronizing branch A with trunk"

svn switch %REPO_URL%/branches/B %WC_PATH%
svn merge %REPO_URL%/trunk %WC_PATH%
svn commit %WC_PATH% -m "Synchronizing branch B with trunk"

svn switch %REPO_URL%/branches/C %WC_PATH%
svn merge %REPO_URL%/trunk %WC_PATH%
svn commit %WC_PATH% -m "Synchronizing branch C with trunk"

在分支 BC 中创建一些不同的内容,因此合并实际上会做一些事情:

svn switch %REPO_URL%/branches/B %WC_PATH%
echo epsilon > %WC_PATH%\epsilon.txt
svn add %WC_PATH%\epsilon.txt
svn commit %WC_PATH% -m "Creating epsilon.txt in B"

svn switch %REPO_URL%/branches/C %WC_PATH%
echo zeta > %WC_PATH%\zeta.txt
svn add %WC_PATH%\zeta.txt
svn commit %WC_PATH% -m "Creating zeta.txt in C"

将我们的工作副本切换回分支 A:

> svn switch %REPO_URL%/branches/A %WC_PATH%
D    wc\zeta.txt
 U   wc
Updated to revision 14.

现在,我们准备好将 B 合并到 A:

> svn merge %REPO_URL%/trunk %REPO_URL%/branches/B %WC_PATH%
--- Merging differences between repository URLs into 'wc':
A    wc\epsilon.txt
 G   wc
--- Recording mergeinfo for merge between repository URLs into 'wc':
 G   wc
Sending        wc
Adding         wc\epsilon.txt

> svn commit %WC_PATH% -m "Merged B to A"
Committing transaction...
Committed revision 15.

> svn update %WC_PATH%
Updating 'wc':
At revision 15.

所以现在 epsilon.txt 在我们的 A 分支中。现在让我们合并 CA:

> svn merge %REPO_URL%/trunk %REPO_URL%/branches/C %WC_PATH%
--- Merging differences between repository URLs into 'wc':
A    wc\zeta.txt
 G   wc
--- Recording mergeinfo for merge between repository URLs into 'wc':
 G   wc
Sending        wc
Adding         wc\zeta.txt

> svn commit %WC_PATH% -m "Merged C to A"
Committing transaction...
Committed revision 16.

> svn update %WC_PATH%
Updating 'wc':
At revision 16.

这把zeta.txt合并成了A,如果我们看A就可以验证现在:

> svn ls %REPO_URL%/branches/A
alpha.txt
beta.txt
delta.txt
epsilon.txt
gamma.txt
zeta.txt