如何将一个大的Git分支拆分成许多小分支?

voj3qocg  于 2023-06-04  发布在  Git
关注(0)|答案(6)|浏览(623)

我已经从SVN导入到Git,现在我有一个大分支,像这样:

  • 在功能C上工作
  • 在功能B上工作
  • 在功能C上工作
  • 在功能C上工作
  • 在功能B上工作
  • 在特征A上工作

我想要A、B、C的独立特性分支。我正在挑选新分支的提交,但这并没有将它们从原始分支中删除,所以我必须手动跟踪我已经删除的提交。
大约有800个提交需要拆分,可能有50个特性/错误修复。
最好能在git日志中以某种方式反映出我已经提取的那些,这样我就知道哪些是我已经做过的。这可能吗?
我可以重定整个分支的基,跳过我已经取出的提交,但我担心这会导致很多冲突。我不想每次提交一次就解决500个冲突。
将提交从一个超级分支拉到更小的功能分支,同时跟踪进度的最佳方法是什么?

dgsult0t

dgsult0t1#

在这个例子中,我使用了interactive rebase
HEAD上,创建分支ABC。同时创建一个“备份”分支(您可以将其命名为backup),以防出现问题而需要恢复原始的HEAD

git branch feature-a
git branch feature-b
git branch feature-c
git branch backup-before-rebase

然后,在你希望它们开始的提交中创建一个分支,也许在一个方便的稳定提交中。叫它new_trunk或者别的什么。

git checkout HEAD~50       ## this will be the new tree-trunk
git branch new_trunk

然后,执行交互式rebase s,并挑选出您希望保留在该分支中的提交。使用这种方式,它基本上就像批量执行cherry-pick

git checkout feature-a
git rebase -i new_trunk    ## -i is for "Interactive"

完成后,您应该有3个分支,从new_trunk开始具有单独的历史记录,如果您仍然需要,则有一个backup分支反映旧的HEAD

qeeaahzv

qeeaahzv2#

就我个人而言,我真的会考虑这样大的变化的利弊(如果你已经这样做了,再一次)。如果你遇到了冲突(这是一个大的rebase/cherry-pick,很烦人,很难解决),你可能会有坚韧的时候,合并功能回到你的“主”分支。
冻结你的大分支,让它“完成”(或“足够好”),并在上面创建新的特性分支,这不是更好/更容易吗?(或者只排除一些分支?)
但对于你的问题:
如果你想自动跟踪更改/丢失的提交,可以使用git cherry命令。

git cherry featureBranch bigBranch

如果在cherrypicking或rebase特性分支时没有冲突,您可以使用以前的代码和一些额外的管道:

git cherry featureBranch bigBranch | awk '{ print "pick " $2 }' | tee remaining

这将打印(并保存到名为“remaining”的文件)featureBranch中缺少的提交。你可以在bigBranch上的交互式rebase中添加这个,以丢弃你不想要的提交。(也许你可以使用“艾德”编辑器作为git编辑器来编写更多的脚本,并将命令传递给交互式rebase的标准输入,但我没有尝试过。

bhmjp9jg

bhmjp9jg3#

为了进一步简化willoller's answer
制作特征分支,并备份,以防

git branch feature-a
git branch feature-b
git branch feature-c
git branch backup-before-rebase

然后 checkout 一个特性分支,并从你希望它们开始的提交中进行交互式变基

git checkout feature-a
git rebase -i <safecommit>
enter code here

如果你想让一些特性分支共享一些提交来保持你的树的整洁,不要在开始的时候创建后面的特性分支,但是一旦你有了一个重新定基的特性分支,然后使用共享的提交引用作为你的下一个 safecommit

#on branch feature-a
git checkout -b feature-d
git rebase -i <sharedcommit>
xesrikrc

xesrikrc4#

我刚刚发现的另一种方法是使用“git notes”。
http://alblue.bandlem.com/2011/11/git-tip-of-week-git-notes.html
这个特性允许添加注解到现有的提交中,而不需要实际改变分支/要求变基。一种跟踪哪些提交被取出的方法是给每个提交添加一个git note:
Cherry-picked to features\xyz 925a5239d4fbcf7ad7cd656020793f83275ef45b
这在很大程度上可以帮助手动处理-您可以编写一个小脚本来选择特定分支的提交,然后将相关的git note添加回原始提交。
或者,如果你想变得非常时髦,你可以通过以下方式自动化整个过程:
1.在每个提交中添加一个git note,说明你希望它被选中到哪个功能分支:TOCHERRYPICK: features\xyz
1.编写一个脚本来扫描所有的git notes,并自动创建所有的feature分支和cherry-pick正确选择的commit。然后,它可以将git note更改为CHERRYPICKED: features\xxx at 925a5239d4fbcf7ad7cd656020793f83275ef45b,以允许稍后重新运行该工具以挑选更多的提交。
1.如果你真的很想在提交被选中时突出它,你也可以自动创建一个具有类似名称的标签:CHERRYPICKED:<branch>:SHA

sz81bmfz

sz81bmfz5#

老实说,我不会这样做,除非你有一个巨大的提交列表,需要分开,他们是非常独立的功能,即。不改变同一行,因为这会产生冲突。

正如其他人所建议的,为每个特性创建一个新的分支,并使用git rebase --interactive来包含所需的提交。
为确保不会丢失,请通过以下方式创建git-rebase-todo文件的内容:

  • 编辑所有所需提交的列表并按功能对其进行分类
  • 将提交列表分隔到单独的文件中

您可以使用类似于以下命令创建提交列表

git log --oneline --reverse  44e19^... > log.txt

显示提交44 e19。这会给予你一个这样的文件

44e1936 dSRGratuities (SummaryRecord)
67fedda Receipt Report HEADER: 20! multiply by Paym_FieldCount
69d70e2 Receipt Report: Payment
....

编辑时(要添加分类:功能a、B、c等)可能看起来像我的sorted.txt

c 44e1936 dSRGratuities (SummaryRecord)
a 67fedda Receipt Report HEADER: 20! multiply by Paym_FieldCount
b 69d70e2 Receipt Report: Payment
c abea7db Receipt Report: Cashback
a cf96185 Receipt Report: Gratuity
c 70e987a Receipt Report: use amount tendered for printing
a 7722ac8 Receipt Report: use amount tendered for calculations
c 47f1754 Receipt Report: store amount tendered
b b69a73f Receipt Report: Use enum Paym_FieldCount
a 9a0b471 Receipt Report HEADER: enum PaymentEntries (with Paym_FieldCount)
c ad67e79 Use SharpReport enum
b 3c510c6 enum SharpReport
a e470e07 m_Gratuities m_dSSGratuities (SalesSummary)
b 4e0c3e4 m_Gratuities m_szGratuities (SalesSummaryRecord)
b bd054f7 _gx_fn_Cashback

然后用您喜欢的脚本语言编写脚本,将排序后的列表转换为git-rebase-todo文件的集合。你的剧本可能和我刚写的很像。

foreachline text sorted.txt {
    set fields  [split $text { }]
    set branch  [lindex $fields 0]
    set commit  [lindex $fields 1]
    set comment [string range $text 10 end]
    set command "echo pick $commit $comment"
    exec cmd /S /C $command >> $branch.txt
}

该脚本逐行读取提交排序文件,并以空格字符{ }拆分以获得两个字段branchcommit,并接受子字符串(从10个字符开始)作为提交的描述。描述不是必需的,但它对我们人类检查错误很有用。
然后将一行代码放入适当的git-rebase-todo文件中,为每个功能创建一个文件。我通过执行一个非常丑陋的Windows echo string >> file命令破解了这个问题。
这将创建多个文件,例如我的文件a.txt

pick 67fedda Receipt Report HEADER: 20! multiply by Paym_FieldCount
pick cf96185 Receipt Report: Gratuity
pick 7722ac8 Receipt Report: use amount tendered for calculations
pick 9a0b471 Receipt Report HEADER: enum PaymentEntries (with Paym_FieldCount)
pick e470e07 m_Gratuities m_dSSGratuities (SalesSummary)

整件事都很丑陋。我不推荐它,除非你必须这样做,并且擅长写脚本。
前段时间我写了上面的文字,我对事情有了一点反思。上面我暗示这是一个很大的工作,不值得做,但我已经看到的情况下,它看起来像有人做了上述,这是非常值得的。
我记得Visual Studio for MFC/C++的版本,其中每个新版本都有编译器更改,IDE更改,MFC改进,并在更高版本的Windows上运行。这意味着,如果你想让你的编译器远离VS 6和Windows XP,你可能不得不改变语言来满足编译器,改变函数调用来满足MFC等。
现在假设微软在开发Visual Studio时每周进行一次备份,有人有条不紊地采取了旧备份并将代码更改提交到Git等版本控制系统中。然后他们开始对变化进行分类。。

  • a. =编译器更改
  • B. =库更改
  • c. = IDE变更
  • D. =安全改进

等等的。
微软可以为每一个都创建分支,并开始拥有最新和最好的IDE(包括c),在最新的Windows上运行,并且仍然能够使用他们编写的语言(没有a)和库(没有b)编译旧的遗留程序。
以前被遗留软件束缚的开发人员可以以逻辑和增量的方式进行改进,例如语言更改和库更改彼此独立,并且在最新和最好的Visual Studio上进行,而无需通过所有中间版本。
示例

<LanguageStandard>stdcpp14</LanguageStandard>

现在我并不是说这就是已经发生的事情,但在我看来,Visual Studio的最新版本在允许旧程序更新方面要好得多,而不是扔掉和(永远不会?)重写,在我看来是由于版本控制和将旧软件更改组织成逻辑分支:编译器版本、DLL/库版本。
因此,我可以看到将大量旧提交拆分到不同分支的情况可能是值得的。
在Visual Studio 2019中,我可以添加以下行

<PlatformToolset>v141_xp</PlatformToolset>

配置文件,并设法编译和运行一个旧的Windows程序,该程序无法编译和链接VS 2015和VS 2017。看起来很像微软的某个人已经将性能和安全改进重新基于一些旧软件,而忽略了经常伴随现代化而来的breaking changes

ehxuflar

ehxuflar6#

//在develop分支上

git diff develop your/branch > diff.patch
git apply diff.patch

相关问题