您在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代码!
我刚刚设置了一个使用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代码!
TortoiseSVN是Subversion版本控制系统的一个非常好的Windows客户端.我刚刚发现它的一个特性是当你单击以获得Excel文件版本之间的差异时,它将在Excel中打开两个版本并突出显示(红色)已更改的单元格.这是通过这里描述的vbs脚本的魔力完成的.
即使不使用TortoiseSVN,您也会发现这很有用.
这取决于您是在谈论数据还是电子表格中包含的代码.虽然我非常不喜欢微软的Visual Sourcesafe,并且通常不会推荐它,但它确实可以轻松地与Access和Excel集成,并提供模块的源代码控制.
[实际上与Access集成,包括查询,报告和模块作为可以版本化的单个对象]
MSDN链接在这里.
我不知道有这么好的工具,但我已经看到了各种本土解决方案.这些的共同点是在版本控制下最小化二进制数据并最大化文本数据以利用传统scc系统的能力.去做这个:
像处理任何其他应用程序一样处理工作簿 分离逻辑,配置和数据.
从工作簿中分离代码.
以编程方式构建UI.
编写构建脚本以重构工作簿.
让我总结一下您希望版本控制的内容以及原因:
什么:
代码(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.
致力于@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
将@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\"