MSExcel 版本控制的最佳方法

你在使用 MSExcel (2003/2007)时使用了哪些版本控制系统?你有什么建议? 为什么?您发现了顶级版本控制系统的哪些局限性?

为了更好地理解这个问题,这里有几个用例:

  1. VBA 模块的版本控制
  2. 不止一个人在使用 Excel 电子表格,他们可能对同一个工作表进行更改,以便合并和集成。这个工作表可能有公式,数据,图表等
  3. 用户技术性不强,使用的版本控制系统越少越好
  4. 空间限制是一个考虑因素。理想情况下,只保存增量更改,而不是保存整个 Excel 电子表格。
166600 次浏览

使用任何标准版本控制工具,如 SVN 或 CVS。局限性取决于目标是什么。除了存储库的小规模增加,我没有面临任何问题

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

[事实上,与 Access 的集成包括查询、报告和模块,它们是可以进行版本控制的单个对象]

MSDN 链路是 给你

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

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

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

如果您正在查看具有常规办公室非技术用户的办公设置,Sharepoint 是一个可行的替代方案。您可以设置启用了版本控制并签入和签出的文档文件夹。对于普通办公室用户来说更友好。

你可以做的一件事就是在你的工作簿中包含以下片段:

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”命令。这样就行了。我甚至在考虑自己做这件事:)

我不知道有什么工具可以做到这一点,但我已经看到了各种各样的自制解决方案。其中的共同主线是在版本控制下最小化二进制数据,并最大化文本数据以利用常规 scc 系统的能力。要做到这一点:

  • 像对待其他应用程序一样对待工作簿。分离逻辑、配置和数据。
  • 从工作簿中分离代码。
  • 以编程方式生成 UI。
  • 编写生成脚本以重新构建工作簿。

只有在文档库中打开版本控制特性时,版本控制才能作为版本控制很好地工作。 此外,请注意,任何通过相对路径调用其他文件的代码都不会起作用。最后,当一个文件保存在 Sharepoint 中时,任何指向外部文件的链接都会中断。

我刚刚设置了一个使用 Bazaar 的电子表格,通过 TortiseBZR 手动签出。考虑到这个主题帮助我完成了保存部分,我想在这里发布我的解决方案。

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

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

我已经为我的 BZR 存储库设置了一个目录 X: Data MySheet。在回购中是 MySheet.xls 和1。每个模块的 vba 文件(即: Module1Macros)。在我的电子表格中,我添加了一个不受导出/导入周期影响的模块,称为“ 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

接下来,我们必须为 open/save 设置事件钩子来运行这些宏。在代码查看器中,右键单击“ ThisWorkbook”并选择“ View Code”。您可能必须下拉代码窗口顶部的选择框才能从“(常规)”视图更改为“工作簿”视图。

“工作簿”视图的内容:

Private Sub Workbook_Open()


ImportCodeModules


End Sub


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


SaveCodeModules


End Sub

在接下来的几个星期里,我会适应这个工作流程,如果我有任何问题,我会发布。

感谢您分享 VBComponent 代码!

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

即使不使用 TortoiseSVN,您也可能会发现这很有用。

我也在调查这件事。似乎最新的 TeamFoundationServer2010可能有 Excel 外接程序。

这里有一条线索:

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

还有一个称为 无与伦比的程序,它有一个相当不错的 Excel 文件比较。我找到了一张中文截图,简要地显示了这一点:

Beyond Compare - comparing two excel files (Chinese)
原始图像来源

他们的 呼叫有30天的试用期

我使用 VBA 编写了一个修订版控制电子表格。 它更适合于工程报告,其中你有多个人工作的材料清单或时间表,然后在某个时候,你想创建一个快照修订,显示增加,德尔和更新从上一个牧师。

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

所有密码都解锁了。

转速控制电子表格

您可能已经尝试过在 zip 容器中使用 Microsoft 的 Excel XML (。Xlsx 和。Xslm)进行版本控制,发现 vba 存储在 vbaProject.bin 中(这对于版本控制是无用的)。

解决办法很简单。

  1. 使用 LibreOfficeCalc 打开 excel 文件
  2. 在 LibreOffice 中计算
    1. 档案
    2. 除了
    3. 另存为类型: ODF 电子表格(. ods)
  3. 关闭 LibreOffice Calc
  4. 将新文件的文件扩展名从.ods 重命名为.zip
  5. 在 GIT 维护区域中为电子表格创建一个文件夹
  6. 将压缩文件解压缩到它的 GIT 文件夹中
  7. 致力于 GIT

当你在下一个版本的电子表格中重复这个步骤时,你必须确保文件夹中的文件与压缩包中的文件完全匹配(不要留下任何已删除的文件)。

在@Demosthenex 工作,@Tmdean 和@Jon Crowell 的宝贵意见! (+ 1)

我将模块文件保存在工作簿位置旁边的 git 目录中。

这不会跟踪对工作簿代码的更改,所以由您来同步它们。

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

然后在练习本模块中:

Private Sub Workbook_Open()


ImportCodeModules


End Sub


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


SaveCodeModules


End Sub

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

这是一个简单的 Excel 插件,其中的代码可以找到 给你

导入后没有重复的模块。只要保存工作簿 而不需要修改任何现有的工作簿,它就会自动导出代码。 它还提供了一个 vba 代码格式化程序。

对@Demosthenex 的回答更进一步,如果你还想跟踪你的微软 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文件)。其中一个包含您编写的软件,另一个是二进制文件,它(我很确定)定义了表单的布局。

MicrosoftExcel 对象(MEO)(意思是 Sheet1Sheet2ThisWorkbook等)可以导出为 .cls文件。但是,当您希望将此代码重新导入到工作簿中时,如果您试图以与导入 VBA 模块相同的方式导入该代码,则如果工作簿中已经存在该表,则会得到一个错误。

为了解决这个问题,我决定不尝试导入。Cls 文件到 Excel 中,但要将 .cls文件作为字符串读取到 Excel 中,然后将该字符串粘贴到空 MEO 中。以下是我的 Import CodeModule:

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\"

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

这是我的 。 gitconfig文件(这允许不同的脚本驻留在我的项目的回购) :

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

如果你想让脚本适用于许多不同的回购协议,那么使用下面这样的东西:

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

我的 。 gittribute档案:

*.xlsx diff=xlsx

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

  1. 什么:

    • 代码(VBA)
    • 电子表格(公式)
    • 电子表格(数值)
    • 图表
    • ...
  2. 原因:

    • 审计日志
    • 合作
    • 版本比较(“差异”)
    • 融合

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

  • 饭桶
  • 反复无常
  • 颠覆
  • 集市

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

如果你不仅担心代码,还担心表格中的数据(“硬编码”值和公式结果) ,你可以使用类似的策略: 将表格中的内容序列化为某种文本格式(通过 Range)。值,并使用现有的版本控制系统。这里有一篇非常好的关于这个的博客文章: 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/)和扬基 X (https://www.florencesoft.com/compare-excel-workbooks-differences.html)。但是将这些比较集成到像 Git 这样的版本控制系统中是另一个挑战。

最后,您必须确定一个适合您需要的工作流。对于一个简单的、为 Excel 工作流量量身定制的 Git,可以看看 https://www.xltrail.com/blog/git-workflow-for-excel

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

VBA 宏的 XLTools 版本控制

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

VBA 代码版本并排,变化是可视化的

我想推荐一个称为 橡皮鸭的伟大的开源工具,它内置了 VBA 代码的版本控制。试试看!

我找到了一个非常简单的解决这个问题的办法,它满足了我的需要。我在所有宏的底部添加了一行代码,每次运行它都会导出一个带有整个宏代码的 *.txt文件。密码:

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

(可以在 汤姆教程上找到,它也涵盖了一些设置,您可能需要让这个工作。)

因为我总是在处理代码的时候运行宏,所以我保证 git 会处理这些更改。唯一恼人的地方是,如果我需要签出早期版本,我必须手动从 *.txt复制/粘贴到电子表格中。