当前位置:  开发笔记 > 后端 > 正文

为MS Excel执行版本控制的最佳方法

如何解决《为MSExcel执行版本控制的最佳方法》经验,为你挑选了7个好方法。

您在MS Excel(2003/2007)中使用了哪些版本的控制系统?你会推荐什么?为什么?您的顶级版本控制系统有哪些限制?

为了正确看待这一点,这里有几个用例:

    VBA模块的版本控制

    不止一个人正在处理Excel电子表格,他们可能正在对他们想要合并和集成的同一工作表进行更改.此工作表可能包含公式,数据,图表等

    用户不是太技术化,使用的版本控制系统越少越好

    空间约束是一个考虑因素.理想情况下,只保存增量更改而不是整个Excel电子表格.

Demosthenex.. 63

我刚刚设置了一个使用Bazaar的电子表格,通过TortiseBZR手动签到/退出.鉴于该主题帮助我保存部分,我想在这里发布我的解决方案.

对我来说,解决方案是创建一个电子表格,在导出时导出所有模块,并在打开时删除并重新导入模块.是的,这可能对转换现有电子表格有潜在危险.

这允许我通过Emacs(是的,emacs)或本机在Excel中编辑模块中的宏,并在重大更改后提交我的BZR存储库.因为所有模块都是文本文件,所以BZR中的标准diff-style命令适用于我的源,但Excel文件本身除外.

我为我的BZR存储库设置了一个目录,X:\ Data\MySheet.在repo中是我的每个模块的MySheet.xls和一个.vba文件(即:Module1Macros).在我的电子表格中,我添加了一个免于导出/导入周期的模块,名为"VersionControl".要导出和重新导入的每个模块必须以"宏"结尾.

"VersionControl"模块的内容:

Sub SaveCodeModules()

'This code Exports all VBA modules
Dim i%, sName$

With ThisWorkbook.VBProject
    For i% = 1 To .VBComponents.Count
        If .VBComponents(i%).CodeModule.CountOfLines > 0 Then
            sName$ = .VBComponents(i%).CodeModule.Name
            .VBComponents(i%).Export "X:\Tools\MyExcelMacros\" & sName$ & ".vba"
        End If
    Next i
End With

End Sub

Sub ImportCodeModules()

With ThisWorkbook.VBProject
    For i% = 1 To .VBComponents.Count

        ModuleName = .VBComponents(i%).CodeModule.Name

        If ModuleName <> "VersionControl" Then
            If Right(ModuleName, 6) = "Macros" Then
                .VBComponents.Remove .VBComponents(ModuleName)
                .VBComponents.Import "X:\Data\MySheet\" & ModuleName & ".vba"
           End If
        End If
    Next i
End With

End Sub

接下来,我们必须设置事件挂钩以进行打开/保存以运行这些宏.在代码查看器中,右键单击"ThisWorkbook"并选择"查看代码".您可能需要下拉代码窗口顶部的选择框以从"(常规)"视图更改为"工作簿"视图.

"工作簿"视图的内容:

Private Sub Workbook_Open()

ImportCodeModules

End Sub

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

SaveCodeModules

End Sub

我将在接下来的几周内完成这个工作流程,如果我有任何问题,我会发布.

感谢分享VBComponent代码!



1> Demosthenex..:

我刚刚设置了一个使用Bazaar的电子表格,通过TortiseBZR手动签到/退出.鉴于该主题帮助我保存部分,我想在这里发布我的解决方案.

对我来说,解决方案是创建一个电子表格,在导出时导出所有模块,并在打开时删除并重新导入模块.是的,这可能对转换现有电子表格有潜在危险.

这允许我通过Emacs(是的,emacs)或本机在Excel中编辑模块中的宏,并在重大更改后提交我的BZR存储库.因为所有模块都是文本文件,所以BZR中的标准diff-style命令适用于我的源,但Excel文件本身除外.

我为我的BZR存储库设置了一个目录,X:\ Data\MySheet.在repo中是我的每个模块的MySheet.xls和一个.vba文件(即:Module1Macros).在我的电子表格中,我添加了一个免于导出/导入周期的模块,名为"VersionControl".要导出和重新导入的每个模块必须以"宏"结尾.

"VersionControl"模块的内容:

Sub SaveCodeModules()

'This code Exports all VBA modules
Dim i%, sName$

With ThisWorkbook.VBProject
    For i% = 1 To .VBComponents.Count
        If .VBComponents(i%).CodeModule.CountOfLines > 0 Then
            sName$ = .VBComponents(i%).CodeModule.Name
            .VBComponents(i%).Export "X:\Tools\MyExcelMacros\" & sName$ & ".vba"
        End If
    Next i
End With

End Sub

Sub ImportCodeModules()

With ThisWorkbook.VBProject
    For i% = 1 To .VBComponents.Count

        ModuleName = .VBComponents(i%).CodeModule.Name

        If ModuleName <> "VersionControl" Then
            If Right(ModuleName, 6) = "Macros" Then
                .VBComponents.Remove .VBComponents(ModuleName)
                .VBComponents.Import "X:\Data\MySheet\" & ModuleName & ".vba"
           End If
        End If
    Next i
End With

End Sub

接下来,我们必须设置事件挂钩以进行打开/保存以运行这些宏.在代码查看器中,右键单击"ThisWorkbook"并选择"查看代码".您可能需要下拉代码窗口顶部的选择框以从"(常规)"视图更改为"工作簿"视图.

"工作簿"视图的内容:

Private Sub Workbook_Open()

ImportCodeModules

End Sub

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

SaveCodeModules

End Sub

我将在接下来的几周内完成这个工作流程,如果我有任何问题,我会发布.

感谢分享VBComponent代码!


上面的这个脚本远非完美.importCodeModules()子有bug并产生重复的模块.此外,您需要编辑每个工作簿以添加open和before_save事件.这是无法接受的.在搜索网页很长一段时间后,我终于找到了一些[实际工作](http://stackoverflow.com/a/25984759/2780179),(这里指的是[这里](https:// github. COM/hilkoc/vbaDeveloper)).它具有代码导入,导出,代码格式等功能.导出在保存时自动发生,无需编辑任何现有工作簿.
当您重新导入时,您还可以检查模块类型.ThisWorkbook.VBProject.VBComponents.Item(i).Type为1表示标准模块,2表示类模块,3表示用户表单,100表示​​文档模块(工作簿或工作表).
这是一个很棒的发现!我建议使用它而不是上面的脚本.我写了一次并使用了一段时间,它满足了我的需求.对于每天使用Excel和VBA的人来说,专门用于该导出的程序或项目会更合适.感谢分享!
导入代码中存在错误.由于您已删除并导入模块,因此它会更改模块的顺序,因此您每次都会丢失一些模块.您需要更改For循环以在数组中向后移动.例如,对于i = .VBComponents.Count到1步-1

2> mcherm..:

TortoiseSVN是Subversion版本控制系统的一个非常好的Windows客户端.我刚刚发现它的一个特性是当你单击以获得Excel文件版本之间的差异时,它将在Excel中打开两个版本并突出显示(红色)已更改的单元格.这是通过这里描述的vbs脚本的魔力完成的.

即使不使用TortoiseSVN,您也会发现这很有用.


很高兴知道TortoiseSVN可以比较作为内置功能^^
我刚刚测试过 - 这也适用于Word文件.很酷^^
这与Word文件是一回事吗?

3> Mitch Wheat..:

这取决于您是在谈论数据还是电子表格中包含的代码.虽然我非常不喜欢微软的Visual Sourcesafe,并且通常不会推荐它,但它确实可以轻松地与Access和Excel集成,并提供模块的源代码控制.

[实际上与Access集成,包括查询,报告和模块作为可以版本化的单个对象]

MSDN链接在这里.


更好的秘密之一 - 我不知道VSS可以做到这一点.+1

4> Hobbo..:

我不知道有这么好的工具,但我已经看到了各种本土解决方案.这些的共同点是在版本控制下最小化二进制数据并最大化文本数据以利用传统scc系统的能力.去做这个:

像处理任何其他应用程序一样处理工作簿 分离逻辑,配置和数据.

从工作簿中分离代码.

以编程方式构建UI.

编写构建脚本以重构工作簿.


因为您无法合并二进制对象

5> Bjoern Stiel..:

让我总结一下您希望版本控制的内容以及原因:

    什么:

    代码(VBA)

    电子表格(公式)

    电子表格(值)

    图表

    ...

    为什么:

    审核日志

    合作

    版本比较("差异")

    合并

正如其他人在此发布的那样,在现有版本控制系统之上有几个解决方案,例如:

混帐

水银

颠覆

市场

如果您唯一关心的是工作簿中的VBA代码,那么上面提到的Demosthenex方法或VbaGit(https://github.com/brucemcpherson/VbaGit)工作得很好,并且实现起来相对简单.优点是您可以依靠经过充分验证的版本控制系统并根据您的需求选择一个(请查看https://help.github.com/articles/what-are-the-differences-between-svn-and -git /用于Git和Subversion之间的简短比较).

如果您不仅担心代码而且担心工作表中的数据("硬编码"值和公式结果),您可以使用类似的策略:将工作表的内容序列化为某种文本格式(通过Range.Value)并使用现有的版本控制系统.这是一篇非常好的博客文章:https://wiki.ucl.ac.uk/display/~ucftpw2/2013/10/18/Using+git+for+version+control+of+spreadsheet+models+-+part + 1 + + 3

但是,电子表格比较是一个非常重要的算法问题.有一些工具,如微软的电子表格比较(https://support.office.com/en-us/article/Overview-of-Spreadsheet-Compare-13fafa61-62aa-451b-8674-242ce5f2c986),Exceldiff(http://exceldiff.arstdesign.com/)和DiffEngineX(https://www.florencesoft.com/compare-excel-workbooks-differences.html).但是将这些比较与像Git这样的版本控制系统集成是另一个挑战.

最后,您必须确定适合您需求的工作流程.有关简单,量身定制的Git for Excel工作流程,请查看https://www.xltrail.com/blog/git-workflow-for-excel.



6> przemo_li..:

致力于@Demosthenex工作,@Tmdean和@Jon Crowell宝贵的评论!(+1他们)

我在工作簿位置旁边的git\dir中保存模块文件.根据自己的喜好改变.

这不会跟踪对Workbook代码的更改.因此,您需要同步它们.

Sub SaveCodeModules()

'This code Exports all VBA modules
Dim i As Integer, name As String

With ThisWorkbook.VBProject
    For i = .VBComponents.count To 1 Step -1
        If .VBComponents(i).Type <> vbext_ct_Document Then
            If .VBComponents(i).CodeModule.CountOfLines > 0 Then
                name = .VBComponents(i).CodeModule.name
                .VBComponents(i).Export Application.ThisWorkbook.Path & _
                                            "\git\" & name & ".vba"
            End If
        End If
    Next i
End With

End Sub

Sub ImportCodeModules()
Dim i As Integer
Dim ModuleName As String

With ThisWorkbook.VBProject
    For i = .VBComponents.count To 1 Step -1

        ModuleName = .VBComponents(i).CodeModule.name

        If ModuleName <> "VersionControl" Then
            If .VBComponents(i).Type <> vbext_ct_Document Then
                .VBComponents.Remove .VBComponents(ModuleName)
                .VBComponents.Import Application.ThisWorkbook.Path & _
                                         "\git\" & ModuleName & ".vba"
            End If
        End If
    Next i
End With

End Sub

然后在Workbook模块中:

Private Sub Workbook_Open()

    ImportCodeModules

End Sub

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

    SaveCodeModules

End Sub



7> dslosky..:

将@Demosthenex的答案更进一步,如果你想跟踪Microsoft Excel对象和用户表格中的代码,你必须有点棘手.

首先,我改变了我的SaveCodeModules()功能,以考虑我计划导出的不同类型的代码:

Sub SaveCodeModules(dir As String)

'This code Exports all VBA modules
Dim moduleName As String
Dim vbaType As Integer

With ThisWorkbook.VBProject
    For i = 1 To .VBComponents.count
        If .VBComponents(i).CodeModule.CountOfLines > 0 Then
            moduleName = .VBComponents(i).CodeModule.Name
            vbaType = .VBComponents(i).Type

            If vbaType = 1 Then
                .VBComponents(i).Export dir & moduleName & ".vba"
            ElseIf vbaType = 3 Then
                .VBComponents(i).Export dir & moduleName & ".frm"
            ElseIf vbaType = 100 Then
                .VBComponents(i).Export dir & moduleName & ".cls"
            End If

        End If
    Next i
End With

End Sub

UserForms可以像VBA代码一样导出和导入.唯一的区别是导出表单时将创建两个文件(您将获得每个UserForm的a .frm和一个.frx文件).其中一个包含你编写的软件,另一个是二进制文件(我很确定)定义了表单的布局.

微软Excel对象(MEOS)(意思是Sheet1,Sheet2,ThisWorkbook等),可以导出为一个.cls文件.但是,如果要将此代码恢复到工作簿中,如果尝试以与VBA模块相同的方式导入它,则如果工作簿中已存在该工作表,则会出现错误.

为了解决这个问题,我决定不尝试将.cls文件导入Excel,而是将.cls文件作为字符串读入excel,然后将此字符串粘贴到空MEO中.这是我的ImportCodeModules:

Sub ImportCodeModules(dir As String)

Dim modList(0 To 0) As String
Dim vbaType As Integer

' delete all forms, modules, and code in MEOs
With ThisWorkbook.VBProject
    For Each comp In .VBComponents

        moduleName = comp.CodeModule.Name

        vbaType = .VBComponents(moduleName).Type

        If moduleName <> "DevTools" Then
            If vbaType = 1 Or _
                vbaType = 3 Then

                .VBComponents.Remove .VBComponents(moduleName)

            ElseIf vbaType = 100 Then

                ' we can't simply delete these objects, so instead we empty them
                .VBComponents(moduleName).CodeModule.DeleteLines 1, .VBComponents(moduleName).CodeModule.CountOfLines

            End If
        End If
    Next comp
End With

' make a list of files in the target directory
Set FSO = CreateObject("Scripting.FileSystemObject")
Set dirContents = FSO.getfolder(dir) ' figure out what is in the directory we're importing

' import modules, forms, and MEO code back into workbook
With ThisWorkbook.VBProject
    For Each moduleName In dirContents.Files

        ' I don't want to import the module this script is in
        If moduleName.Name <> "DevTools.vba" Then

            ' if the current code is a module or form
            If Right(moduleName.Name, 4) = ".vba" Or _
                Right(moduleName.Name, 4) = ".frm" Then

                ' just import it normally
                .VBComponents.Import dir & moduleName.Name

            ' if the current code is a microsoft excel object
            ElseIf Right(moduleName.Name, 4) = ".cls" Then
                Dim count As Integer
                Dim fullmoduleString As String
                Open moduleName.Path For Input As #1

                count = 0              ' count which line we're on
                fullmoduleString = ""  ' build the string we want to put into the MEO
                Do Until EOF(1)        ' loop through all the lines in the file

                    Line Input #1, moduleString  ' the current line is moduleString
                    If count > 8 Then            ' skip the junk at the top of the file

                        ' append the current line `to the string we'll insert into the MEO
                        fullmoduleString = fullmoduleString & moduleString & vbNewLine

                    End If
                    count = count + 1
                Loop

                ' insert the lines into the MEO
                .VBComponents(Replace(moduleName.Name, ".cls", "")).CodeModule.InsertLines .VBComponents(Replace(moduleName.Name, ".cls", "")).CodeModule.CountOfLines + 1, fullmoduleString

                Close #1

            End If
        End If

    Next moduleName
End With

End Sub

如果你dir对这两个函数的输入感到困惑,那就是你的代码库!所以,你将这些函数称为:

SaveCodeModules "C:\...\YourDirectory\Project\source\"
ImportCodeModules "C:\...\YourDirectory\Project\source\"

推荐阅读
ifx0448363
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有