36

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

  • 处理特征 C
  • 处理功能 B
  • 处理特征 C
  • 处理特征 C
  • 处理功能 B
  • 处理特征 A

我想要单独的功能分支,用于 A、B、C。我正在挑选新分支的提交,但这不会将它们从原始分支中删除,所以我必须手动跟踪我已经拉出的那些。

大约有 800 个提交需要拆分,可能还有 50 个功能/错误修复。

如果能以某种方式在 git 日志中反映我已拉出的那些,那就太好了,这样我就知道我已经完成了哪些。这可能吗?

我可以 rebase 整个分支,跳过我已经退出的提交,但我担心这会导致很多冲突。我不想每次拉出提交时都解决 500 个冲突。

从一个 uber 分支提取提交到较小的功能分支的最佳方法是什么,同时跟踪您的进度?

4

6 回答 6

41

在这种情况下,我所做的是使用交互式 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

然后,执行 interactiverebase并选择要保留在该分支中的提交。用这种方式,基本上就像cherry-pick是批量ing。

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

完成后,您应该有 3 个具有不同历史的分支,如果您仍然需要它,则应该有new_trunk一个backup反映旧历史的分支。HEAD

于 2012-09-22T08:20:13.897 回答
10

就我个人而言,我真的会考虑如此大的变化的利弊(如果你已经这样做了,再一次考虑)。如果您遇到冲突(这在大型 rebase/cherry-pick 中很烦人且本身难以解决),您在将功能合并回“主”分支时可能会遇到困难。

冻结你的大分支,让它“完成”(或“足够好”)并在其上创建新的功能分支不是更好/更容易吗?(或者只排除一些分支?)

但是对于你的问题:

如果您想自动跟踪更改/丢失的提交,请使用 git cherry 命令。

git cherry featureBranch bigBranch

如果在挑选或重新设置功能分支时没有冲突,您可以使用以前的代码和一些额外的管道:

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

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

于 2012-09-22T09:06:51.033 回答
6

只是为了进一步简化威勒的回答

制作功能分支和备份,以防万一

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

然后签出一个功能分支并从您希望他们开始的提交中进行交互式变基

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

如果您希望某些功能分支共享一些提交以保持树清洁,请不要在开始时创建稍后的功能分支,但是一旦您获得了重新定位的功能分支,然后使用共享提交引用作为您的下一个安全提交

#on branch feature-a
git checkout -b feature-d
git rebase -i <sharedcommit>
于 2014-05-23T21:01:04.573 回答
3

老实说,除非您有大量需要拆分的提交并且它们是非常独立的功能,否则我不会这样做,即不会更改要解决冲突的同一行。

正如其他人所建议的那样,为每个功能创建一个新分支并用于git rebase --interactive包含所需的提交。

为确保不会误入歧途,请通过以下方式创建git-rebase-todo文件的内容

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

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

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

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

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文件中,为每个功能创建一个文件。我通过执行一个非常丑陋的 Windowsecho 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 上运行。这意味着如果您想让您的编译器远离 VS6 和 Windows XP,您可能必须进行语言更改以满足编译器的要求,并更改函数调用以满足 MFC 等。

现在假设微软在开发 Visual Studio 时每周进行一次备份,有人有条不紊地进行旧备份并将代码更改提交到 Git 等版本控制系统中。然后他们开始对变化进行分类......

  • 一个。= 编译器更改

  • 湾。= 库更改

  • C。= IDE 更改

  • d。= 安全改进

    等等

微软可以为每一个创建分支,并开始拥有最新最好的 IDE(包括在内),在最新的 Windows 上运行,并且仍然能够使用它们编写的语言(否)和库(否)c编译旧的遗留程序.ab

以前锁定在遗留软件中的开发人员可以以逻辑和增量的方式进行改进,例如相互独立的语言更改和库更改,并在最新和最好的 Visual Studio 上进行,而无需通过所有中间版本。

例子

  <LanguageStandard>stdcpp14</LanguageStandard>

现在我并不是说这就是发生的事情,但在我看来,Visual Studio 的最新版本在允许更新遗留程序方面要好得多,而不是丢弃和(从不?)重写,在我看来是由于版本控制和将旧软件更改组织到逻辑分支:编译器版本、DLL/库版本。

因此,我可以看到将大量旧提交拆分为不同分支的情况可能是值得的。

在 Visual Studio 2019 上,我可以添加该行

<PlatformToolset>v141_xp</PlatformToolset>

到一个配置文件,并设法编译和运行一个旧的 Windows 程序,该程序无法编译和链接到 VS 2015 和 VS 2017。看起来很像微软的某个人在一些旧软件上重新定位了性能和安全性改进,同时省略了breaking changes这通常伴随着现代化而来。

于 2017-10-17T13:13:11.910 回答
2

我刚刚发现的另一种方法是使用“git notes”。

http://alblue.bandlem.com/2011/11/git-tip-of-week-git-notes.html

此功能允许在不实际更改分支/需要变基的情况下向现有提交添加注释。跟踪哪些提交已被拉出的一种方法是为每个提交添加一个 git 注释:

Cherry-picked to features\xyz 925a5239d4fbcf7ad7cd656020793f83275ef45b

这可以在很大程度上帮助手动过程 - 您可以编写一个小脚本来挑选特定分支的提交,然后将相关的 git 注释添加回原始提交。

或者,如果你想变得非常时髦,你可以通过以下方式自动化整个过程:

  1. 为每个提交添加一个 git 注释,说明您希望将其挑选到哪个功能分支:TOCHERRYPICK: features\xyz
  2. 编写一个脚本来扫描所有 git 注释,并自动创建所有功能分支并挑选正确的选定提交。然后它可以更改 git note 以CHERRYPICKED: features\xxx at 925a5239d4fbcf7ad7cd656020793f83275ef45b允许稍后重新运行该工具以挑选更多提交。
  3. 如果您真的很想在提交被选中时让它突出,您还可以自动创建具有相似名称的标签:CHERRYPICKED:<branch>:SHA
于 2015-11-04T12:09:56.220 回答
0

// 在开发分支上

git diff develop your/branch > diff.patch
git apply diff.patch
于 2021-05-17T05:28:40.227 回答