这是一个流程问题,所以正确答案可能不止一个。不过,我愿意接受比我现在拥有的任何东西。
我的团队最近切换到使用Mercurial(从Subversion),在大多数情况下,我们喜欢新的功能。然而,有一些事情正在降低生产力。其中一件事就是管理.hgignore
文件。
根据已建立的文献和"一些家伙在互联网上"的建议:),我们的团队保持.hgignore
文件最新,以便hg addremove
总是做正确的事情。另外,缺少需要添加的文件是构建失败的首要原因,因此hg st
只返回真正需要操作的文件是很重要的。
问题是,由于我们总是在文件的底部添加新的忽略,如果两个人做.hgignore
更改,它总是会导致合并冲突。(大多数人使用TortoiseHg客户端,它添加到文件的末尾。)这样做的结果是,大约有一半的时间文件被改变,改变它的人必须处理.hgignore
的合并。这感觉就像不得不摆弄源代码控制的内部一样。
它导致开发人员不想向.hgignore
添加文件,因为他们知道这至少需要几分钟的额外时间来处理。我们有一个相当大的项目,一个相当大的团队,正在经历不断的变化。新的构建工件是相当有规律地引入的,所以这个问题似乎不会消失。.hgignore
并没有真正稳定下来,因为项目变化很大。(当然,这本身是另一个问题。)
"正确"的做法几乎总是"两边都拿"。从技术上讲,两个人可能会使用文本编辑器修改完全相同的前一行,但这是极不可能的。不太可能,即使"双管齐下"的方法失败了,后果也很小。
所以,我向社区提出了这个问题:我怎样才能改善这种情况?是否有流程变更可以减轻这种情况?有没有一种工具可以自动取两边?我能以某种方式自动化合并吗?是否有一个复选框,我可以检查神奇地解决问题:)?
编辑1:这是我当前.hgignore的(显然是编辑过的)版本。您可以很容易地观察到使用了几种不同的技术。代码的一些部分正处于从一种技术转换到另一种技术的过程中(例如VB到c#)。这会导致构建构件的集合发生变化,并且需要更新文件。
syntax: glob
*.obj
*.tds
*.map
*.il?
*/obj/*
*/lib/*
*/pch/*
Foo/Engine/frezbat/DocFiles.hpp
Foo/Engine/personal_defines.h
Foo/Engine/revision.cpp
Foo/Engine/frobbish/uLinkHlp.hpp
Foo/Engine/dll/XMLData/**.xml
Foo/Engine/dll/*.syslog
Foo/Engine/dll/*.log
Foo/Engine/dll/Scripts
Foo/Engine/dll/Linked Models
Foo/Engine/dll/prv
Foo/Engine/dll/pub
Foo/Engine/dll/failures.txt
Foo/Engine/dll/users.prm
Foo/Engine/tools/SrvIface/**.dll
Foo/Engine/tools/SrvIface/**.exe
*/dll/*.ini
*/dll/*.exe
*/dll/*.dll
*/quux_obj/*
*.dbg
*~
scripts/backupPath.txt
*.local
*.orig
FooDoc/FooDoc/bin/*
FooDoc/FooDoc/FooDoc.suo
FooDoc/FooDoc/FooDoc.vbproj.user
FooDoc/FooDoc_Setup/Release
Foo/Engine/dll/FooObjects.pdb
Foo/Engine/dll/FooObjects.tlb
Foo/Engine/dll/FooObjects.xml
Foo/Engine/dll/InitechDebugTimer.txt
*.dsk
Foo/Engine/dll/Preferences/CustomToolbar.ini
Foo/Engine/Engine.~dsk
Foo/Engine/dll/ApplicationSettings.fooprefs
Foo/Engine/dll/Foo.cgl
Foo/Engine/dll/IniShare.mem
Foo/Engine/baz_obj/*
Foo/Engine/baz_pch/*
*/dll/*.drc
*.~dsk
InitechBaz/InitechBaz/bin/Debug/InitechBaz.vshost.exe.manifest
InitechBaz/InitechBaz/bin/Debug/InitechBaz.vshost.exe.config
InitechBaz/InitechBaz/bin/Debug/InitechBaz.vshost.exe
InitechBaz/InitechBaz/bin/Debug/InitechBaz.exe.config
scripts/TestComplete/Ottertech_Replay/Log/*
scripts/TestComplete/Ottertech_Replay/[*
relre:ReSharper*
relre:_UpgradeReport_Files
glob:*.suo
glob:*.pdb
*.swp
Foo/Engine/FooObjects/FooObjects/bin/x86/
FooDoc/MCtoDAT/MCtoDAT/bin/x86
FooDoc/Deploy
Foo/Engine/installers/initech-build/bin/*
scripts/TestComplete/Users/*
Foo/Engine/dll/MCtoDAT.xml
FooDoc/Deploy/*
scripts/TestComplete/Ottertech_Replay/Log/*
scripts/TestComplete/Ottertech_Replay/[*
*.orig
Foo/Engine/installers/icon-installers-bin/*
Foo/Engine/Quux/Server/*.esp
Foo/Engine/Quux/BrapServer/*.esp
Foo/Engine/installers/bin/*.exe
Foo/Engine/installers/quux/encryptedsql/*.esp
Foo/Engine/tools/tempfile.tmp
*.pch
*.#*
*.#??
Foo/Engine/dll/frabbing.lib
re:^.*.#[0-9][0-9]$
Foo/Engine/Foo/FooObjects/FooObjects/FooObjects.xml
FooDoc/MCtoDAT/MCtoDAT/MCtoDAT.xml
*.sln.cache
FooDoc/TestFooObj/TestFooObj/bin/
*.user
Foo/Engine/FooObjects/FooObjects/FooObjects.xml
Foo/Engine/FooObjects/FooObjects/FooObjects.xml
FooDoc/MCtoDAT/MCtoDAT/MCtoDAT.xml
*/Debug Installer/*.dll
*/Debug Installer/*.tlb
*/Debug Installer/*.xml
*/Debug Installer/*.msi
*/Debug Installer/*.exe
FooDoc/FooDoc_Setup/Debug/*
re:(?i).*/UpgradeLog.xml
*.sln.cache
通常在项目开始时,会对忽略文件进行一系列更改,但很快就会适应。我猜你没有有效地使用通配符。如果您不知道如何在您的情况下使用通配符,您可能需要构建您的代码,以便新创建的被忽略的文件都放到一个目录中。例如,将所有构建工件放入"build"目录中。这在构建脚本中需要更多的前期工作,但也有助于像制表符完成这样的事情,因为源目录中只有源文件。
将build-root 移出repo-tree的并获取hg export
的builder源代码。这样可以一举两得
- 构建对象不会在存储库中丢弃
- 你可以验证所有需要的文件在存储库 中
像任何工具一样,Mercurial只能做到这一点。正如前面所指出的,大多数项目结构在一段时间后趋于稳定,使得您的问题在标准用例中的相关性低于您自己的用例。
在你的情况下,你很可能不得不忍受这个。
一种替代方法是重构您的项目,这样所有可忽略的文件都位于同一位置,或者可以通过通配符模式引用。如果唯一的推动力是需要减轻忽视管理问题,我倾向于反对这种做法。换句话说,您的源代码控制系统的特性或限制不应该构成决定项目结构的力量。
也就是说,通常有真正的力量在工作,以产生稳定的项目结构,这些力量超出了源代码控制。例如,开发人员需要熟悉项目,而不断的变化削弱了熟悉度。显然,您的情况并非如此,因为您的源代码被忽略了。
我知道这不会回答你的问题,但我觉得问题出在源代码控制之外,在你的项目中,那些其他的力量已经停止施加影响。