如何避免团队中的 git 冲突?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16490873/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to avoid git conflicts in a team?
提问by Dev01
We are some developers who work on same project and we use git for the project. If two or more of us happen to work on same file, we receive git conflicts which are hard to deal with, sometimes changes done by one developer are lost when these conflicts happen.
我们是一些在同一个项目上工作的开发人员,我们在项目中使用 git。如果我们中的两个或更多人碰巧在同一个文件上工作,我们会收到难以处理的 git 冲突,有时当这些冲突发生时,一位开发人员所做的更改会丢失。
How do they work with git in a team? What should be the proper flow in order to avoid git conflicts ?
他们如何在团队中使用 git?为了避免 git 冲突,正确的流程应该是什么?
Thanks in advance.
提前致谢。
回答by Christopher
Before you dig deep into your workflow, before you spend a moment of time or a dollar of money rebuilding your communication processes, ask your team three questions:
在您深入研究您的工作流程之前,在您花一点时间或一美元的金钱重建您的沟通流程之前,请先问您的团队三个问题:
- Do we enforce whitespace conventions?
- If we use IDEs, do they all use the same formatting and keyword settings? For example, Eclipse can automatically finalize parameters.
- Do we generate textual build artifacts? For example, do we minify js, generate css rules from
.sass
or.scss
files, or build xml configurations on the fly? Do we check them in?
- 我们是否强制执行空格约定?
- 如果我们使用 IDE,它们是否都使用相同的格式和关键字设置?例如,Eclipse 可以自动完成参数。
- 我们是否生成文本构建工件?例如,我们是缩小 js,从
.sass
或.scss
文件生成 css 规则,还是动态构建 xml 配置?我们检查他们吗?
After years of generating conflicts and helping others solve them in centralized workflows, I submit these three things cause the vast majority of our collective conflict pain:
经过多年产生冲突并在集中工作流程中帮助其他人解决它们,我提交了这三件事导致了我们绝大多数的集体冲突痛苦:
In the above image, the '!' slice represents legitimate merge conflicts. The vastmajority of awful merges come from lazy whitespace conventions or overly aggressive IDEs (or occasionally, overly-refactory developers). Before you do anything else, standardize your IDE settings and whitespace conventions. Then have everyone issue this command in their local repositories:
在上图中,“!” slice 代表合法的合并冲突。在广大大多数可怕合并的来自懒惰空白公约或过于激进的IDE(或偶尔过于refactory开发者)。在你做任何其他事情之前,标准化你的 IDE 设置和空格约定。然后让每个人在他们的本地存储库中发出这个命令:
# Enable the repository's stock pre-commit hook
mv .git/hooks/pre-commit.sample .git/hooks/pre-commit
That pre-commit hook will conduct a series of checks every time you issue git commit
, including a version of git diff --check
, a command that checks if your committed changes introduce whitespace errors. The commit will be rejected if it does. If you really need to get around it, you can issue git commit --no-verify
, but don't: Whitespace errors are like the unexploded ordinance of version control. They're merge conflicts waiting to happen.
该 pre-commit hook 将在您每次发出 时进行一系列检查git commit
,包括 的一个版本git diff --check
,该命令检查您提交的更改是否引入了空格错误。如果提交,则提交将被拒绝。如果你真的需要绕过它,你可以发出git commit --no-verify
,但不要:空白错误就像未爆炸的版本控制条例。它们是等待发生的合并冲突。
If you want to clean up whitespace, refactor a file to improve its indentation, or otherwise make a large series of purely formatting changes, do it in isolated commits, and warn the team to check in their conflicting work in progress first.
如果您想清理空白、重构文件以改进其缩进,或以其他方式进行大量纯格式更改,请在独立提交中进行,并警告团队首先检查正在进行的冲突工作。
If you conduct code reviews, make these the first questions every reviewer asks: "Did this change set touch anythingit wasn't supposed to? Did it clean up any formatting? Did it unnecessarily refactor a method?" If it did, fail the review. Or if you can't, make sure those changes are sufficiently isolated from the logical changes (i.e. in different commits) to make your history useful.
如果您进行代码,请将这些作为每个者问的第一个问题:“这个变更集是否触及了任何不应该发生的事情?它是否清理了任何格式?它是否不必要地重构了一个方法?” 如果是,则审核不通过。或者,如果您不能,请确保这些更改与逻辑更改(即在不同的提交中)充分隔离以使您的历史记录有用。
Stylesheet languages, RequireJS, and js minifiers also cause conflicts, if their generated targets are checked in. The files created by these technologies are build artifacts. You wouldn't check in a WAR archive; don't check in a SASS-compiled CSS file. Or, if you feel you must, use a .gitattributes
fileto let git treat them as binaries.
如果已检入样式表语言、RequireJS 和 js 压缩器生成的目标,它们也会导致冲突。这些技术创建的文件是构建工件。您不会签入 WAR 档案;不要签入 SASS 编译的 CSS 文件。或者,如果您觉得必须,请使用.gitattributes
文件让 git 将它们视为二进制文件。
If after doing all of these things, you still have merge conflicts, institute workflow improvements. Gary Fixler's answer is absolutely right: Legitimate merge conflicts arise because teams cannot or do not communicate well about the scope of their projects. Just make sure its not poorly enforced formatting rules first.
如果在完成所有这些事情后,您仍然有合并冲突,请改进工作流程。Gary Fixler 的回答是绝对正确的:合法的合并冲突的产生是因为团队不能或没有就他们的项目范围进行良好的沟通。首先要确保它的格式规则执行不力。
回答by Gary Fixler
Well, to be really honest, the proper workflow involves good communication and management. Team members shouldn't oftenbe working on the same thing and causing conflicts. Things like daily standups, and an attentive manager who knows what each member of the team is up to - at least in general - will go a long way in many cases to limit this.
好吧,说实话,正确的工作流程涉及良好的沟通和管理。团队成员不应该经常做同样的事情并引起冲突。诸如每日站会之类的事情,以及一个细心的经理,他知道团队中的每个成员都在做什么——至少在一般情况下——在许多情况下会大大限制这种情况。
It depends on the exact nature of the product, of course, but this is more of an organizational issue than a git issue. In fact, conflicts are often seen as "good" things, because they get people to get up from their desks, or call each other up to talk about why there was a conflict, and what should be done about it going forward. This is a chance to figure out that one person should own one area, or a set of files, or at least be the point of contact for discussing changes to that section.
当然,这取决于产品的确切性质,但这更多是组织问题而不是 git 问题。事实上,冲突通常被视为“好事”,因为它们让人们从办公桌上站起来,或者互相打电话讨论为什么会发生冲突,以及接下来应该怎么做。这是一个确定一个人应该拥有一个区域或一组文件的机会,或者至少是讨论该部分更改的联系人。
Outside of making an up-front plan, there is no way to avoid git conflicts, but this would be the same issue in any versioning system. Any time two people change the same section of code, you have to figure out who wins. This is why it's not really appropriate to look toward the versioner for the solution, but to look to your team's methods and practices. Two cars can't go through an intersection at the same time, but it's extremely hard to invent cars that can pass through each other, so instead we invented the control systems of stop signs and traffic signals. This is a similar issue. We can't really make two changes to the same thing not conflict, so we must control how we work with the files.
除了制定预先计划之外,没有办法避免 git 冲突,但这在任何版本控制系统中都是相同的问题。任何时候两个人更改同一段代码,您都必须弄清楚谁赢了。这就是为什么向版本控制者寻求解决方案并不是真正合适的原因,而是考虑您团队的方法和实践。两辆车不能同时通过一个十字路口,但是要发明可以互相通过的汽车是非常困难的,所以我们发明了停车标志和交通信号的控制系统。这是一个类似的问题。我们不能真正对同一事物进行两次更改而不发生冲突,因此我们必须控制我们如何处理文件。
You couldconsider one of the front-ends that allows locking in git, but I don't really agree with the concept, outside of non-mergeable filetypes. I think it's better to figure out a better team workflow, and meanwhile, use this as an opportunity to get really good at merging files. I did that, and now after months of doing it, conflicts are not an upsetting thing to me.
您可以考虑允许锁定 git 的前端之一,但我并不真正同意这个概念,除了不可合并的文件类型。我认为最好找出一个更好的团队工作流程,同时,以此为契机,真正擅长合并文件。我这样做了,现在经过几个月的努力,冲突对我来说并不是一件令人不安的事情。
回答by GoZoner
There is only one way to avoid conflicts: don't have different people edit the same file at the same time. Essentially each file has an owner who is responsible for all edits and who can pass ownership to another. Ownership for a file can be passed around based on a particular feature/branch or day-to-day as long as the ownership is clear.
只有一种方法可以避免冲突:不要让不同的人同时编辑同一个文件。本质上,每个文件都有一个所有者,负责所有编辑并且可以将所有权传递给另一个人。只要所有权明确,文件的所有权就可以根据特定功能/分支或日常情况进行传递。
If you find that you can't give one owner to each file then:
如果您发现不能为每个文件指定一个所有者,则:
- you need to split your files into smaller files that can be assigned to one owner
- absolutely require that GIT conflicts get resolved (with all editors sitting together to resolve the individual conflicts).
- Use a good multi-merge tool to visualize and then resolve the conflicts.
- 您需要将文件拆分为可以分配给一个所有者的较小文件
- 绝对需要解决 GIT 冲突(所有编辑都坐在一起解决个别冲突)。
- 使用一个好的多合并工具来可视化然后解决冲突。
回答by Ivan
Ordering.
订购。
There are a few other things you can do that might help too. It will be clearer if I post them separately.
您还可以做一些其他事情,它们也可能有所帮助。如果分开贴会更清楚。
Where you insert new things will help determine whether you create conflicts.
您在何处插入新内容将有助于确定您是否会产生冲突。
Imagine a list of names of employees
想象一个员工姓名列表
Andy,
Oliver,
Ivan,
Then Brad and Patrick join and their names are added to the list. You add Brad and I add Patrick. We both add the names to the bottom of the list, and then use git to merge our lists. The result will be familiar to git users :-
然后布拉德和帕特里克加入,他们的名字被添加到列表中。你加了布拉德,我加了帕特里克。我们都将名称添加到列表的底部,然后使用 git 合并我们的列表。结果对 git 用户来说很熟悉:-
Merge branch 'Patrick' into Brad
Conflicts:
names.txt
@@@ -1,4 -1,4 +1,8 @@@
Andy,
Oliver,
Ivan,
<<<<<<< HEAD
+Brad,
=======
+ Patrick,
>>>>>>> Patrick
Now suppose we had done the same thing but imposed a simple alphabetical ordering rule on our list. Now when we come to merge the two branches the results are a little more pleasing :-
现在假设我们做了同样的事情,但在我们的列表上强加了一个简单的字母排序规则。现在,当我们合并两个分支时,结果会更令人愉悦:-
Andy,
Ivan,
Oliver,
Add one name yourself and then merge the other person's change with git, to add the other name.
自己添加一个名字,然后将其他人的更改与 git 合并,以添加另一个名字。
Auto-merging names.txt
Merge made by the 'recursive' strategy.
names.txt | 1 +
1 file changed, 1 insertion(+)
And we get
我们得到
Andy,
Brad,
Ivan,
Oliver,
Patrick,
Since we don't know who is going to join the company next we are effectively adding to the list randomly, and by inserting in random places, conflicts of location in the files are less likely.
由于我们不知道接下来谁将加入公司,因此我们实际上是随机添加到列表中,并且通过在随机位置插入,文件中位置冲突的可能性较小。
回答by Ivan
Use appended block starts
使用附加块开始
In software like this ...
在这样的软件...
function chess()
{
while (!end_of_game)
{
make_move()
the lines starting blocks with opening braces are easily going to be confused with other lines in the software consisting of single opening braces. If the same software is written like this, appending the block starts to previous lines ...
带有左大括号的行起始块很容易与软件中由单个左大括号组成的其他行混淆。如果相同的软件是这样编写的,则将块附加到前几行...
function chess() {
while (!end_of_game) {
make_move()
which I personally don't like, but Git does,there are lots less lines that look similar to Git and get mistaken for each other, i.e. Git is more likely to perceive the editing the same way we do, making any conflicts much easier to resolve.
我个人不喜欢这一点,但 Git 确实如此,看起来与 Git 相似并且会被误认为彼此的行少得多,即 Git 更有可能以与我们相同的方式感知编辑,从而使任何冲突更容易解决解决。
And comments on block endings
以及对块结尾的评论
Use comments to make similar looking lines distinguishable.
使用注释来区分相似的线条。
If you write lots of javascript and JSON, you might have lots of lines that look a little like this.
如果你编写了大量的 javascript 和 JSON,你可能会有很多看起来像这样的行。
}
}
}
)
If you comment things then they can become distinguishable.
如果您评论事物,则它们可以变得可区分。
}
}
}
) // end of weekdays()
and
和
}
}
}
) // end of weekend()
no longer look the same to git. This can help git to understand your changes better. If you add something, like
git 看起来不再一样了。这可以帮助 git 更好地理解您的更改。如果你添加一些东西,比如
function a()
{
...
} // end of a()
git is more likely to see that as a unit of change and not think you have added something like
git 更有可能将其视为一个更改单位,而不是认为您添加了类似
}
function a()
{
...
just before the end of some other function. Even when this does not prevent conflicts, if git sees and presents your changes sensibly (i.e. the way we mentally view them), then you can perhaps resolve conflicts more easily. A descriptive header commenting what functions do, the parameters they take, etc, will further help to prevent git from muddling the contents of neighboring functions together.
就在其他一些功能结束之前。即使这并不能防止冲突,如果 git 能够明智地看到并呈现您的更改(即我们在心理上看待它们的方式),那么您或许可以更轻松地解决冲突。一个描述函数做什么的描述性标题,它们采用的参数等,将进一步有助于防止 git 将相邻函数的内容混淆在一起。
回答by Will Sheppard
To reduce the number of conflicts in version control without worrying about who is editing what, you simply need to make smaller changes and commit/push them incrementally. Split the problem up into small enough pieces that you can quicklymodify files and push them back to trunk. The shorter lived your branches are, the less chance there will be of merge conflicts.
为了减少版本控制中的冲突数量而不用担心谁在编辑什么,您只需要进行较小的更改并逐步提交/推送它们。将问题分解成足够小的部分,以便您可以快速修改文件并将它们推回主干。你的分支寿命越短,合并冲突的可能性就越小。
Even then, at some point two people will edit the same file at the same time through no fault of their own. The obvious question when that happens is:
即便如此,在某些时候,两个人也会因为他们自己的过错而同时编辑同一个文件。当这种情况发生时,显而易见的问题是:
"How can I take the pain out of resolving git conflicts?"
“我如何才能摆脱解决 git 冲突的痛苦?”
The answer is you should pull trunk and rebase your branch onto it frequently, and you will notice the conflicts as early as possible, while they are still small. At this point both developers should sit together and calmly discuss the best way to proceed while the changes are fresh in their minds.
答案是你应该经常拉主干并将你的分支变基到它上面,你会尽早注意到冲突,而它们仍然很小。在这一点上,两个开发人员应该坐在一起,冷静地讨论进行更改的最佳方式,同时他们还记得这些变化。
Contrast this approach with trying to resolve conflicts on huge long-lived branches in a panic just before a release deadline, when the developers struggle to remember the thinking behind all the changes they made some time ago.
将这种方法与尝试在发布截止日期前恐慌地解决巨大的长期分支上的冲突进行对比,当时开发人员很难记住他们前一段时间所做的所有更改背后的想法。
回答by Ivan
Inform colleagues when you have pushed your changes
推送更改时通知同事
Another way to reduce the pain of conflicts is simply to inform colleagues when you have pushed your changes. It allows them to pull your changes and resolve some conflicts there and then. Any conflicts are likely to be between your recent change, fresh in your mind and what they are working on, fresh in their minds.
另一种减少冲突痛苦的方法是在您推动更改时通知同事。它允许他们提取您的更改并在那里解决一些冲突。任何冲突都可能发生在你最近的改变和他们正在做的事情之间。
If people don't pull changes from the main branch until they have finished a large development and then have conflicts with changes made by a number of people, all in the same area, then it will be harder to resolve.
如果人们在完成大型开发之前不从主分支拉取更改,然后与许多人所做的更改发生冲突,并且都在同一区域,那么解决起来将更加困难。
Use a mergetool
使用合并工具
One of Git's purpose's is version control. Other programs specialize in merging files and resolving conflicts. If you configure a mergetool to use with git, then it can automatically resolve many issues which git regards as a conflict, or at least make a very good guess for you to inspect and simply leave untouched if it looks okay, or you trust the tool.
Git 的目的之一是版本控制。其他程序专门用于合并文件和解决冲突。如果您配置了一个合并工具以与 git 一起使用,那么它可以自动解决许多 git 认为是冲突的问题,或者至少为您做出一个很好的猜测,如果它看起来不错,或者您信任该工具,就不要动它。 .
That leaves fewer genuine conflicts which need an intelligent decision for resolution.
这样就减少了需要做出明智决定才能解决的真正冲突。
Use smaller files
使用较小的文件
I add a new controller at the bottom of mycontrollers.jsand you add a new controller at the bottom of yourcontrollers.js: no problem.
我在底部添加一个新的控制器mycontrollers.js和你的底部添加一个新的控制器yourcontrollers.js:没问题。
We both add a new controller at the bottom of allcontrollers.js: conflict.
我们都在allcontrollers.js的底部添加了一个新控制器:冲突。
(However remember the advice about ordering things alphabetically too. myNewController() starting with M might go in the middle of a file and yourNewController() starting with Y might go at the end of the same file, again with no conflict.)
(但是,请记住有关按字母顺序排序的建议。以 M 开头的 myNewController() 可能位于文件中间,而以 Y 开头的 yourNewController() 可能位于同一文件的末尾,同样没有冲突。)
回答by Ivan
Use UTF-8 not UTF-16 for text files.
对文本文件使用 UTF-8 而不是 UTF-16。
Many versions of Git (i.e every version I have used, as far as I know) can treat UTF-16 files as binary files due to the presence of many zero bytes in a typical UTF-16 text file.
由于在典型的 UTF-16 文本文件中存在许多零字节,许多版本的 Git(即我使用过的每个版本,据我所知)都可以将 UTF-16 文件视为二进制文件。
Once Git thinks a file is a binary file, it is likely to keep on treating the file as a binary file even when it is changed. This means that the version control is done by storing complete versions of the file rather than the differences between them and the some of the advantages of a version control system are lost. (Edit: No. I tested this recently by changing a UTF-16 file to UTF-8 committing it, editing it and committing again - and it started treating the changes as text changes once BOTH the original and edited files were UTF-8.)
一旦 Git 认为一个文件是一个二进制文件,即使它被更改,它也可能继续将文件视为二进制文件。这意味着版本控制是通过存储文件的完整版本而不是它们之间的差异来完成的,并且版本控制系统的一些优势会丢失。(编辑:不。我最近通过将 UTF-16 文件更改为 UTF-8 提交、编辑并再次提交来测试这一点 - 一旦原始文件和编辑过的文件都是 UTF-8,它就开始将更改视为文本更改。 )
Most modern editors will recognize the character encoding and line ending style of a file and save the file in the same format. Some editors (e.g. Babelpad) will allow you to choose whether you save your file in UTF-8 or UTF-16, and with or without a byte order mark, etc.
大多数现代编辑器都会识别文件的字符编码和行尾样式,并以相同的格式保存文件。一些编辑器(例如 Babelpad)将允许您选择以 UTF-8 或 UTF-16 格式保存文件,以及带或不带字节顺序标记等。
If the file you want to version control is (i) in UTF-16 format and (ii) would work equally well in UTF-8 -- for example a source program for a decent modern compiler -- it is worth considering converting it to UTF-8.
如果您要进行版本控制的文件是 (i) UTF-16 格式并且 (ii) 在 UTF-8 中也能很好地工作——例如一个体面的现代编译器的源程序——那么值得考虑将其转换为UTF-8。
If Git thinks your source text is a binary file before its very first commit, look at it and see if it is worth loading it in an editor and saving it in a different format that Git recognizes as text.
如果 Git 在第一次提交之前认为你的源文本是一个二进制文件,请查看它,看看是否值得将它加载到编辑器中,并以 Git 识别为文本的不同格式保存它。
(Note. Linux files tend to be UTF-8 by default. Some Windows programs had a habit of creating UTF-16. So it's Windows users that are most likely to have the problem. Also note that you want to correct this before the very first commit of the file, before Git believes it has a binary file!)
(注意。Linux 文件在默认情况下往往是 UTF-8。一些 Windows 程序有创建 UTF-16 的习惯。所以 Windows 用户最有可能遇到这个问题。另外请注意,你想在最第一次提交文件,在 Git 认为它有一个二进制文件之前!)
Use Git rerere
使用 Git rerere
Reuse recorded resolution!
重复使用录制的分辨率!