首页 文章

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

提问于
浏览
158

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

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

  • 版本控制VBA模块

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

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

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

25 回答

  • 1

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

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

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

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

    Contents of the "VersionControl" module:

    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”并选择“查看代码” . 您可能需要下拉代码窗口顶部的选择框以从“(常规)”视图更改为“工作簿”视图 .

    Contents of "Workbook" view:

    Private Sub Workbook_Open()
    
    ImportCodeModules
    
    End Sub
    
    Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    
    SaveCodeModules
    
    End Sub
    

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

    感谢分享VBComponent代码!

  • 1

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

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

  • 1

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

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

    MSDN链接是here .

  • -1

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

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

    • 从工作簿中分离代码 .

    • 以编程方式构建UI .

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

  • -1

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

    • 什么:

    • 代码(VBA)

    • 电子表格(公式)

    • 电子表格(值)

    • 图表

    • ......

    • 为什么:

    • 审核日志

    • 协作

    • 版本比较("diffing")

    • 合并

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

    • Git

    • Mercurial

    • Subversion

    • Bazaar

    如果您唯一关心的是工作簿中的VBA代码,那么上面提到的Demosthenex方法或VbaGit(https://github.com/brucemcpherson/VbaGit)工作得非常好并且实现起来相对简单 . 优点是你可以依靠成熟的版本控制系统,并根据你的需要选择一个(看看https://help.github.com/articles/what-are-the-differences-between-svn-and-git/,以便在Git和Subversion之间进行简单的比较) .

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

  • 3

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

    I save module files in git\ dir beside workbook location. Change that to your liking.

    This will NOT track changes to Workbook code. So it's up to you to synchronize them.

    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
    
  • 40

    将@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的 .frm.frx 文件) . 其中一个保存了您确定的表单布局的软件 .

    Microsoft Excel对象(MEO)(意思是 Sheet1Sheet2ThisWorkbook 等)可以导出为 .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\"
    
  • 2

    您可以做的一件事是在工作簿中包含以下代码段:

    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 "C:\Code\" & sName$ & ".vba"
                End If
            Next i
        End With
    End Sub
    

    我在互联网上找到了这个片段 .

    之后,您可以使用Subversion来维护版本控制 . 例如,通过在VBA中使用Subversion的命令行界面和“shell”命令 . 那样做会 . 我甚至想过自己这样做:)

  • 1

    我使用 git ,今天我将this (git-xlsx-textconv)移植到Python,因为我的项目基于Python代码,并且它与Excel文件交互 . 这适用于至少 .xlsx 文件,但我认为它也适用于 .xls . Here's github链接 . 我写了两个版本,一个是每一行都有自己的行,另一个是每个单元格都在自己的行上(后者是因为 git diff 不喜欢在默认情况下包装长行,至少在Windows上是这样) .

    这是我的 .gitconfig 文件(这允许不同的脚本驻留在我的项目的repo中):

    [diff "xlsx"]
        binary = true
        textconv = python `git rev-parse --show-toplevel`/src/util/git-xlsx-textconv.py
    

    如果您希望脚本可用于许多不同的repos,那么使用以下内容:

    [diff "xlsx"]
        binary = true
        textconv = python C:/Python27/Scripts/git-xlsx-textconv.py
    

    我的 .gitattributes 文件:

    *.xlsx diff=xlsx
    
  • 0

    如果您正在寻找具有常规办公室非技术用户的办公环境,那么Sharepoint是一个可行的选择 . 您可以设置启用了版本控制以及签入和签出的文档文件夹 . 使常规办公用户更自由 .

  • 9

    使用任何标准版本控制工具,如SVN或CVS . 限制取决于目标是什么 . 除了存储库大小的小幅增加外,我没有遇到任何问题

  • 1

    为响应mattlant的回复 - 只有在文档库中打开版本控制功能时,sharepoint才能作为版本控件使用 . 另外请注意,通过相对路径调用其他文件的任何代码都不会起作用 . 最后,当文件保存在sharepoint中时,任何指向外部文件的链接都会中断 .

  • 7

    你应该尝试DiffEngineX . 它可以通过编程方式调用,也可以从命令行获取命令行参数 . 它不仅可以比较Excel电子表格单元格,还可以比较工作簿中嵌入的Visual Basic宏 . 还比较了Excel定义的名称和注释,这是许多免费软件工具所遗漏的出 . 它可以从下载

    http://www.florencesoft.com/excel-differences-download.html

    我确定您的版本控制系统有一个选项或框,因此您可以使用原始和修改的Excel工作簿自动调用DiffEngineX .

  • -1

    我也一直在研究这个问题 . 它表明最新的Team Foundation Server 2010可能具有Excel加载项 .

    这是一个线索:

    http://team-foundation-server.blogspot.com/2009/07/tf84037-there-was-problem-initializing.html

  • 1

    搜索了几年并尝试了许多不同的工具后,我在这里找到了对vba版本控制问题的答案:https://stackoverflow.com/a/25984759/2780179

    这是一个简单的excel插件,可以找到代码here

    导入后没有重复的模块 . 只要您保存工作簿,它就会自动导出您的代码,而无需修改任何现有工作簿 . 它与vba代码格式化程序一起使用 .

  • 63

    实际上,只有少数几种解决方案可以跟踪和比较宏代码中的变化 - 其中大部分已在此处命名 . 我一直在浏览网页,并且遇到了值得一提的这个新工具:

    XLTools Version Control for VBA macros

    Excel工作表和VBA模块的

    • 版本控制
      在提交版本之前

    • 预览和差异更改

    • 非常适 Contract 一个文件上的多个用户的协同工作(跟踪谁更改了什么/何时/评论)

    • 比较版本并逐行突出显示代码中的更改

    • 适合那些不懂技术或精通Excel的用户

    • 版本历史存储在您自己的PC上的Git-repository中 - 任何版本都可以轻松恢复

    VBA code versions side by side, changes are visualized

  • 3

    我想推荐一个名为Rubberduck的开源工具,它内置了VBA代码的版本控制 . 试试吧!

  • 6

    您可能已经尝试在zip容器(.xlsx和.xslm)中使用Microsoft的Excel XML进行版本控制,并发现vba存储在vbaProject.bin中(对于版本控制来说没用) .

    解决方案很简单 .

    • 使用LibreOffice Calc打开excel文件

    • 在LibreOffice Calc中

    • 文件

    • 另存为

    • 另存为类型:ODF电子表格(.ods)

    • 关闭LibreOffice Calc

    • 将新文件的文件扩展名从.ods重命名为.zip

    • 在GIT维护区域中为电子表格创建一个文件夹

    • 将zip解压缩到它的GIT文件夹中

    • 承诺给GIT

    当您使用下一版本的电子表格重复此操作时,您必须确保使文件夹的文件与zip容器中的文件完全匹配(并且不要留下任何已删除的文件) .

  • 0

    还有一个名为 Beyond Compare 的程序,它有一个非常好的Excel文件比较 . 我找到了一个中文截图,简要说明了这一点:

    Beyond Compare - comparing two excel files (Chinese)

    Original image source

    他们的page有30天的试用期

  • 0

    我的公司在自动化Microsoft Office解决方案方面做了大量工作,因此我编写了一个.DLL,每次保存模板时都会导出解决方案的来源 . 它创建一个名为Source的文件夹作为保存模板的文件夹的子文件夹,在Source下面创建一个与VBA项目同名的文件夹 . 在项目文件夹中,它导出模块,类和用户表单的所有源代码 . 选择这种安排是为了便于管理大量模板集合的源 . 如果您有本地配置文件或全局配置文件,则DLL能够解锁锁定的项目以访问VBA项目 . 使用此工具,开发人员可以根据自己的内容处理模板,并使用他们喜欢的修订控制工具来管理他们的工作 . 我们主要在我们的环境中使用Git,我们保留完整的模板二进制文件以及版本控制下的VBA资源 .

  • 0

    这是一个GitHub项目,它解决了OP问题的第1点和第4点:https://github.com/ColmBhandal/VbaMisc . 它仅适用于VBA模块的VC解决方案 . 通过复制GitHub上看到的项目结构并将要放在VC下的任何模块添加到ExportImport模块中定义的whiteList,可以轻松地为任何项目定制它 . 该模块控制VBA模块白名单的导出和导入,可能包括自身 . 有关如何使用的说明,请参阅GitHub存储库 .

  • 0

    我找到了一个满足我需求的非常简单的解决方案 . 我在我的所有宏的底部添加一行,每次运行时都会导出 *.txt 文件和整个宏代码 . 代码:

    ActiveWorkbook.VBProject.VBComponents("moduleName").Export"C:\Path\To\Spreadsheet\moduleName.txt"
    

    (在Tom's Tutorials上找到,它也包含了一些你可能需要的设置才能使它工作 . )

    自从我'll always run the macro whenever I'米工作了代码,我保证git会接受更改 . 唯一令人讨厌的部分是,如果我需要签出早期版本,我必须手动从 *.txt 复制/粘贴到电子表格中 .

  • 1

    这取决于你想要的集成级别,我使用了Subversion / TortoiseSVN,这对于简单的使用来说似乎很好 . 我还添加了关键字,但似乎存在文件损坏的风险 . 在Subversion中有一个选项可以使关键字替换固定长度,据我所知,如果固定长度是偶数但不是奇数,它将起作用 . 在任何情况下你都没有得到任何有用的差异功能,我认为有些商业产品会做'差异' . 我确实找到了基于将内容转换为纯文本并进行比较的差异,但这并不是很好 .

  • 7

    它应该适用于大多数VCS(取决于您可能选择SVN,CVS,Darc,TFS等的其他标准),但它实际上是完整的文件(因为它是二进制格式),这意味着“改变了什么”的问题是不那么容易回答 .

    如果人们完成日志消息,您仍然可以依赖日志消息,但您也可以尝试使用Office 2007中基于XML的新格式来获得更多可见性(尽管仍然很难清除大量的XML,加上AFAIK XML文件在磁盘上压缩,因此你需要一个预提交钩子来解压缩它以使文本差异正常工作) .

  • 6

    我使用VBA编写了一个修订控制的电子表格 . 它适用于工程报告,其中您有多个人在处理物料清单或计划,然后在某个时间点您要创建一个快照修订版本,显示上一次修订版本中的添加,删除和更新 .

    注意:它是一个启用宏的工作簿,您需要登录才能从我的站点下载(您可以使用OpenID)

    所有代码都已解锁 .

    Rev Controlled Spreadsheet

相关问题