在 Mercurial 中不断合并 .hgignore
这是一个过程问题,因此可能有多个正确答案。不过,我会接受我现在所拥有的一切。
我的团队最近转而使用 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
This is a process question, so there may be more than one right answer. I'll take anything over what I have now, though.
My team has recently switched to using Mercurial (from Subversion) and for the most part, we like the new power. However, there are a few things that are reducing productivity. One of those things is managing the .hgignore
file.
In accordance with the established literature and the advice of "some guys on the internet" :), our team is keeping the .hgignore
file up-to-date so that hg addremove
always does the right thing. Also, missing files that need to be added is the #1 cause of build failures, so it is important that hg st
only returns files that genuinely need action.
The problem is that since we always add new ignores to the bottom of the file, it always causes a merge conflict if two people make .hgignore
changes. (Most people use the TortoiseHg client, which adds to the end of the file.) The result of this is that about half the time the file is changed, the person changing it has to handle a merge of .hgignore
. This feels a lot like having to monkey with the innards of our source control.
It's causing developers to not want to add files to the .hgignore
, since they know it will take at minimum several additional minutes to deal with. We have a fairly large project with a fairly large team that is undergoing constant changes. New build artifacts are introduced fairly regularly, so the problem doesn't appear to be going away. The .hgignore
isn't really stabilizing much, since the project is changing a lot. (Which itself is a different issue, of course.)
The 'right' thing to do is 'take both sides' almost always. Technically, two people might have modified the exact same prior line with a text editor, but this is highly unlikely. Unlikely enough that even if the 'take both' approach failed, the consequences are minor.
So, I put the question to the community: How can I improve the situation? Is there a process change that would mitigate this? Is there a tool to automatically take both sides? Can I automate the merge somehow? Is there a checkbox that I can check to magically solve the problem :)?
Edit 1: Here's the (obviously redacted) version of my current .hgignore. You can easily observe that there are several different technologies being used. Several portions of the code are in the midst of being transitioned from one tech to another (VB to C# for example). That causes the set of build artifacts to change and the file needs to be updated.
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
通常,在项目开始时,忽略文件会发生一系列更改,但很快就会稳定下来。我猜你没有有效地使用通配符。如果您无法考虑如何在您的情况下使用通配符,您可能需要构建代码,以便新创建的忽略文件全部进入一个目录。例如,将所有构建工件放入“build”目录中。这是构建脚本中更多的前期工作,但也有助于制表符完成等操作,因为源目录中只有源文件。
Usually there's a flurry of changes in ignore files at the beginning of a project, but it settles in pretty quickly. I'm guessing you aren't using wildcards effectively. If you can't think how to use wildcards in your situation, you probably need to architect your code so newly created ignored files all go into one directory. For example, putting all the build artifacts into a "build" directory. That's a little more up front work in your build scripts, but also helps with things like tab completion since there are only source files in your source directories.
将 build-root 移至存储库树的外部,并作为
hg 导出
的结果获取构建器的源代码。通过这种方式,您可以用一块石头杀死两只鸟,Move build-root outside of repo-tree and get sources for builder as result of
hg export
. This way you can kill two birds with one stone与任何工具一样,Mercurial 的作用也有限。正如之前指出的,大多数项目结构在一段时间后往往会稳定下来,这使得您的问题在标准用例中的相关性不如在您自己的用例中的相关性。
就您而言,您很可能只能忍受这一点。
一种替代方法是重组您的项目,使所有可忽略的文件位于同一位置,或者可以通过通配符模式引用。如果图片中唯一的力量是需要减轻忽视管理问题,我倾向于建议反对。换句话说,源代码控制系统的特性或限制不应该成为决定项目结构的力量。
也就是说,通常有真正的力量致力于产生稳定的项目结构,这些力量超越了源代码控制。例如,开发人员需要熟悉项目,而不断的变化会损害熟悉度。显然您的情况并非如此,因为您的源代码被忽略了。
我知道这对回答你的问题不会有太大帮助,但我觉得问题出在源代码控制之外,并且在你的项目中,其他力量已经停止施加影响。
Like any tool, Mercurial can only go so far. As pointed out before, most project structures tend to stabilize after a while, making your problems less relevant in a standard use case than in your own.
In your case, it may well be that you just have to live with this.
One alternative would be to restructure your project such that all your ignorable files are co-located, or otherwise referentiable by a wildcard pattern. I would tend to advise against it if the only force in the picture is the need to mitigate ignore management issues. In other words, peculiarities or limitations of your source control system should not constitute a force in deciding project structure.
That said, there are typically genuine forces working to produce a stable project structure, forces that go beyond source control. For instance, the developers need to be familiar with the project, and constant changes impair familiarity. Apparently not the case for you, as you have source code being ignored.
I know this will not go far towards answering your question, but I feel the problem lies outside source control and that in your project those other forces have ceased to exert influence.