您在MS Excel(2003/2007)中使用了哪些版本控制系统?您会推荐什么,为什么?您对最高评价的版本控制系统有什么限制?
为了正确理解这一点,这里有一些用例:
- VBA模块的版本控制
- 超过一个人正在处理Excel电子表格,他们可能正在更改要合并和集成的同一工作表。该工作表可能包含公式,数据,图表等
- 用户不太技术,使用的版本控制系统越少越好
- 空间限制是一个考虑因素。理想情况下,仅保存增量更改,而不是整个Excel电子表格。
您在MS Excel(2003/2007)中使用了哪些版本控制系统?您会推荐什么,为什么?您对最高评价的版本控制系统有什么限制?
为了正确理解这一点,这里有一些用例:
Answers:
我刚刚设置了一个使用Bazaar的电子表格,并通过TortiseBZR手动签入/签出。鉴于该主题对我的保存部分有所帮助,因此我想在此处发布解决方案。
对我来说,解决方案是创建一个电子表格,该电子表格在保存时导出所有模块,然后在打开时删除并重新导入模块。是的,这对于转换现有电子表格可能具有潜在的危险。
这使我可以通过Emacs(是,emacs)或在Excel中本地编辑模块中的宏,并在进行重大更改后提交我的BZR存储库。因为所有模块都是文本文件,所以BZR中的标准diff样式命令适用于我的源文件,但Excel文件本身除外。
我已经为BZR存储库设置了一个目录X:\ Data \ MySheet。在仓库中是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代码!
对于Subversion版本控制系统,TortoiseSVN是一个非常好的Windows客户端。我刚刚发现的一个功能是,单击以获取Excel文件版本之间的差异时,它将在Excel中打开两个版本并以红色突出显示已更改的单元格。这是通过一个VBS脚本的魔力,完成描述这里。
即使不使用TortoiseSVN,您也可能会发现它很有用。
让我总结一下您想要进行版本控制的原因以及原因:
什么:
为什么:
正如其他人在此处发布的那样,在现有版本控制系统之上有一些解决方案,例如:
如果您唯一关心的是工作簿中的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/使用+ git + for + version + control + of +电子表格+模型+-+部分+ 1 + 3
但是,电子表格比较是一个不平凡的算法问题。周围有一些工具,例如Microsoft的Spreadsheet Compare(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。
这取决于您是在谈论数据还是电子表格中包含的代码。尽管我非常不喜欢Microsoft的Visual Sourcesafe,通常不建议这样做,但它确实可以轻松地与Access和Excel集成,并提供模块的源代码控制。
[实际上,与Access的集成包括查询,报告和模块,它们是可以版本化的单个对象]
MSDN链接在这里。
我不知道有什么工具可以很好地做到这一点,但我已经看到了各种本地解决方案。这些的共同点是在版本控制下最小化二进制数据,并在文本数据最大化时利用传统scc系统的功能。去做这个:
在@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
然后在工作簿模块中:
Private Sub Workbook_Open()
ImportCodeModules
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
SaveCodeModules
End Sub
如果您还想跟踪Microsoft Excel对象和UserForms中的代码,请进一步使用@Demosthenex的答案。
首先,我更改了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代码一样导出和导入UserForm。唯一的区别是,导出表单时将创建两个文件(您将为每个UserForm得到.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\"
我使用git,今天我将其(git-xlsx-textconv)移植到Python,因为我的项目基于Python代码,并且可以与Excel文件交互。这至少适用于.xlsx文件,但我认为它也适用于.xls。这是github链接。我写了两个版本,一个版本的每一行都在自己的行上,另一个版本的每个单元格都在自己的行上(之所以这样写是因为git diff不喜欢默认情况下换行,至少在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
我的.gitattributes文件:
*.xlsx diff=xlsx
您可以做的一件事是在工作簿中包含以下代码段:
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”命令配合使用。那样就可以了。我什至在想自己做这个:)
我想推荐一个很棒的开源工具,名为Rubberduck,该工具内置了VBA代码的版本控制。
我也一直在研究这个。这说明最新的Team Foundation Server 2010可能具有Excel加载项。
这是一个线索:
http://team-foundation-server.blogspot.com/2009/07/tf84037-there-was-problem-initializing.html
经过多年的探索并尝试了许多不同的工具之后,我在这里找到了针对vba版本控制问题的答案:https : //stackoverflow.com/a/25984759/2780179
这是一个简单的excel插件,可在此处找到其代码
导入后没有重复的模块。保存工作簿后,它将自动导出代码,而无需修改任何现有工作簿。它与vba代码格式化程序一起提供。
实际上,只有少数解决方案可以跟踪和比较宏代码中的更改-大多数解决方案已在此处命名。我一直在浏览网络,发现了这个值得一提的新工具:
您可能已经尝试在zip容器(.xlsx和.xslm)中使用Microsoft的Excel XML进行版本控制,并且发现vba存储在vbaProject.bin中(对于版本控制没有用)。
解决方案很简单。
当您在电子表格的下一个版本中重复此操作时,必须确保使文件夹的文件与zip容器中的文件完全匹配(并且不要留下任何已删除的文件)。
我找到了一个非常简单的解决方案,可以满足我的需求。我在所有宏的底部添加了一行,*.txt
每次运行时,该宏就会导出带有完整宏代码的文件。编码:
ActiveWorkbook.VBProject.VBComponents("moduleName").Export"C:\Path\To\Spreadsheet\moduleName.txt"
(可在Tom's Tutorials上找到,该指南还介绍了可能需要进行一些设置才能使其正常工作。)
由于每当我处理代码时,我都会一直运行宏,因此可以保证git将接受更改。唯一令人烦恼的部分是,如果我需要签出早期版本,则必须手动从中复制/粘贴*.txt
到电子表格中。