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

时间:2008-09-25 05:31:27

标签: excel version-control

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

为了正确看待这一点,以下是几个用例:

  1. VBA模块的版本控制
  2. 不止一个人正在处理Excel电子表格,他们可能正在对他们想要合并和集成的同一工作表进行更改。此工作表可能包含公式,数据,图表等
  3. 用户不是太技术化,使用的版本控制系统越少越好
  4. 空间约束是一个考虑因素。理想情况下,只保存增量更改而不是整个Excel电子表格。

25 个答案:

答案 0 :(得分: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 :(得分:41)

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

即使不使用TortoiseSVN,您也会觉得这很有用。

答案 2 :(得分:9)

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

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

MSDN链接为here

答案 3 :(得分:7)

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

  • 像处理其他任何应用程序一样处理工作簿。分离逻辑,配置和数据。
  • 将代码与工作簿分开。
  • 以编程方式构建UI。
  • 编写构建脚本以重建工作簿。

答案 4 :(得分:7)

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

  1. 什么:

    • 代码(VBA)
    • 电子表格(公式)
    • 电子表格(值)
    • 图表
    • ...
  2. 为什么:

    • 审核日志
    • 协作
    • 版本比较(&#34;差异&#34;)
    • 合并
  3. 正如其他人在此发布的那样,在现有版本控制系统之上有几个解决方案,例如:

    • GIT中
    • 水银
    • 的Subversion
    • 巴扎

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

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

    但是,电子表格比较是一个非常重要的算法问题。有一些工具,例如Microsoft的电子表格比较(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

答案 5 :(得分:6)

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

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

这不会跟踪对工作簿代码的更改。因此,您需要同步它们。

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

答案 6 :(得分:6)

将@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

可以像VBA代码一样导出和导入UserForms。唯一的区别是导出表单时将创建两个文件(每个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\"

答案 7 :(得分:3)

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

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”命令。那样做会。我甚至想自己这样做:)

答案 8 :(得分:3)

我使用 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

答案 9 :(得分:2)

如果您正在寻找具有常规办公室非技术用户的办公环境,那么Sharepoint是一种可行的选择。您可以设置启用了版本控制以及签入和签出的文档文件夹。使其成为常规办公用户的免费提供者。

答案 10 :(得分:2)

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

答案 11 :(得分:1)

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

答案 12 :(得分:1)

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

答案 13 :(得分:1)

我也一直在研究这个问题。看来最新的Team Foundation Server 2010可能有一个Excel加载项。这是一个线索:

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

答案 14 :(得分:1)

您应该尝试使用DiffEngineX。它可以通过编程方式调用,也可以从命令行获取命令行参数。它不仅可以比较Excel电子表格单元格,还可以比较工作簿中嵌入的Visual Basic宏。还比较了Excel定义的名称和注释,很多免费工具都错过了。它可以从

下载

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

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

答案 15 :(得分:1)

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

XLTools Version Control for VBA macros

  • Excel工作表和VBA模块的版本控制
  • 在提交版本之前预览和区别更改
  • 非常适合同一个文件上的多个用户的协同工作(跟踪谁更改了什么/何时/评论)
  • 比较版本并逐行突出显示代码中的更改
  • 适合那些不懂技术或精通Excel的用户
  • 版本历史记录存储在您自己的PC上的Git-repository中 - 任何版本都可以轻松恢复

VBA code versions side by side, changes are visualized

答案 16 :(得分:1)

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

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

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

答案 17 :(得分:0)

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

答案 18 :(得分:0)

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

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

(在Tom's Tutorials上找到,它还介绍了一些可能需要使其工作的设置。)

由于每当我处理代码时,我都会一直运行宏,因此可以保证git将接管所做的更改。唯一令人讨厌的部分是,如果我需要签出早期版本,则必须手动将*.txt复制/粘贴到电子表格中。

答案 19 :(得分:0)

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

答案 20 :(得分:0)

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

解决方案很简单。

  1. 使用LibreOffice Calc打开excel文件
  2. 在LibreOffice Calc中
    1. 档案
    2. 另存为
    3. 保存类型:ODF电子表格(.ods)
    4. 关闭LibreOffice Calc
    5. 将新文件的文件扩展名从.ods重命名为.zip
    6. 在GIT维护区域中为电子表格创建一个文件夹
    7. 将zip解压缩到它的GIT文件夹
    8. 承诺加入GIT
    9. 当您使用下一版电子表格重复此操作时,您必须确保使文件夹的文件与zip容器中的文件完全匹配(并且不要留下任何已删除的文件)。

答案 21 :(得分:0)

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

Beyond Compare - comparing two excel files (Chinese)
Original image source

page

上有30天的试用期

答案 22 :(得分:-1)

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

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

所有代码都已解锁。

Rev Controlled Spreadsheet

答案 23 :(得分:-1)

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

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

答案 24 :(得分:-1)

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