如何避免团队中的git冲突?

我们是一些在同一个项目上工作的开发人员,我们使用git作为项目。 如果我们中有两个或两个以上的人碰巧在同一个文件上工作,我们会收到很难处理的git冲突,有时一个开发人员所做的更改会在这些冲突发生时丢失。

他们如何在团队中使用git? 什么应该是正确的stream程,以避免git冲突?

提前致谢。

在深入了解工作stream程之前,在花费一些时间或花一分钱重build沟通stream程之前,请向您的团队提出三个问题:

  1. 我们是否执行空白约定?
  2. 如果我们使用IDE,他们都使用相同的格式和关键字设置? 例如,Eclipse可以自动完成参数 。
  3. 我们是否生成文本构build工件? 例如,我们是否缩小js,从.sass.sass文件生成css规则,或者即时创buildxmlconfiguration? 我们检查他们吗?

经过多年的冲突和帮助他人解决集中式的工作stream程,我提出这三件事导致我们绝大多数集体冲突的痛苦:

合并冲突的原因

在上图中,“!” 切片代表合法的合并冲突。 绝大多数可怕的合并来自懒惰的空白惯例或者过于积极的IDE(或者偶尔是过度耐用的开发者)。 在做其他事情之前,请将您的IDE设置和空白约定标准化。 然后让每个人在他们的本地仓库中发出这个命令:

 # Enable the repository's stock pre-commit hook mv .git/hooks/pre-commit.sample .git/hooks/pre-commit 

每次发出git commit ,pre-commit钩子都会进行一系列检查,包括git diff --check一个版本, git diff --check是一个检查提交的更改是否引入空白错误的命令。 如果提交将会被拒绝。 如果你真的需要解决它,你可以发出git commit --no-verify ,但是不要:空白错误就像版本控制的未爆炸条例。 他们正在等待发生合并冲突。

如果要清理空白,重构文件以改进缩进,或者进行大量纯粹的格式化更改,请在隔离提交中执行此操作,并警告团队首先检查正在进行的冲突工作。

如果你进行代码审查,那么每个审稿人都会提出第一个问题:“这个变更是否触及它不应该做的事情?是否清理了任何格式?是否不必要地重构了一个方法? 如果确实如此,则不能通过审查。 或者,如果你不能,确保这些变化与逻辑变化(即在不同的提交中)有足够的隔离,以使你的历史有用。

样式表语言,RequireJS和js限定符如果检入其生成的目标,也会导致冲突。由这些技术创build的文件是构build工件。 您不会检入WAR档案; 不要签入SASS编译的CSS文件。 或者,如果你觉得你必须使用.gitattributes文件让git把它们当作二进制文件。

如果在做完所有这些事情之后,您仍然会合并冲突,实现工作stream程改进。 加里Fixler的答案是绝对正确的:合法的合并冲突出现,因为团队不能或不能很好地沟通他们的项目范围。 只要确保它不是执行不力的格式化规则。

那么,说实话,正确的工作stream程需要良好的沟通和pipe理。 团队成员不应该经常在同一件事情上工作,造成冲突。 像日常的立场,以及知道每个团队成员所要做的细心的经理(至less在一般情况下),在很多情况下都会有很长的路要走。

当然,这取决于产品的确切性质,但这更像是一个组织问题,而不是git问题。 事实上,冲突往往被认为是“好”的东西,因为冲突让人们站起来,或者互相打电话来谈论为什么会发生冲突,以及应该怎样处理冲突。 这是一个计算出一个人应该拥有一个区域或一组文件的机会,或者至less是讨论对该部分进行修改的联系点。

在制定预先计划之外,没有办法避免git冲突,但这在任何版本控制系统中都是同样的问题。 任何时候,两个人改变同一部分的代码,你必须找出谁赢了。 这就是为什么寻求解决scheme的版本并不合适,而是要看看你的团队的方法和实践。 两辆车不能同时通过十字路口,但发明可以相互穿越的汽车极其困难,所以我们发明了停车标志和交通信号控制系统。 这是一个类似的问题。 我们不能真正对同一个事物做两个改变不冲突,所以我们必须控制我们如何处理文件。

可以考虑允许在git中locking的前端之一,但是我不完全同意这个概念,除了不可兼容的文件types之外。 我认为最好是找出一个更好的团队工作stream程,同时用这个机会来合并文件。 我这样做了,现在经过了几个月的努力,冲突对我来说并不是一件令人不安的事情。

只有一种方法可以避免冲突:没有不同的人同时编辑同一个文件。 基本上每个文件都有一个所有者负责所有编辑,谁可以将所有权转让给另一个。 只要所有权清晰,文件的所有权可以基于特定的function/分支或每天的日常传递。

如果你发现你不能给每个文件一个所有者,那么:

  • 您需要将文件分割成可分配给一个所有者的较小文件
  • 绝对要求GIT冲突得到解决(所有编辑坐在一起解决个人冲突)。
  • 使用一个好的多合并工具来可视化并解决冲突。

订购。

还有一些其他的事情可以帮助你。 如果我单独发布它会更清楚。

插入新东西的位置将有助于确定是否产生冲突。

想象一下员工的名单

 Andy, Oliver, Ivan, 

然后Brad和Patrickjoin,他们的名字被添加到列表中。 你添加布拉德,我添加帕特里克。 我们都将名称添加到列表的底部,然后使用git来合并我们的列表。 结果将是熟悉的git用户:

 Merge branch 'Patrick' into Brad Conflicts: names.txt @@@ -1,4 -1,4 +1,8 @@@ Andy, Oliver, Ivan, <<<<<<< HEAD +Brad, ======= + Patrick, >>>>>>> Patrick 

现在假设我们做了同样的事情,但在我们的列表上强加了一个简单的字母sorting规则。 现在当我们来合并这两个分支时,结果会更令人高兴:

 Andy, Ivan, Oliver, 

自己添加一个名字,然后将其他人的更改与git合并,以添加其他名称。

 Auto-merging names.txt Merge made by the 'recursive' strategy. names.txt | 1 + 1 file changed, 1 insertion(+) 

我们得到

 Andy, Brad, Ivan, Oliver, Patrick, 

由于我们不知道下一个将要join公司的人,我们正在随机添加到列表中,并且通过随机插入,文件中的位置冲突的可能性较小。

在推送更改时通知同事

减less冲突痛苦的另一种方法就是当你推动你的改变时通知同事。 它允许他们拉你的变化,然后解决一些冲突。 任何冲突都可能发生在你最近的变化之间,你心中的新鲜事物和他们正在做的事情,他们的想法都是新鲜的。

如果人们不把主要分支的变化拉大,直到他们完成了一个大的发展,然后与许多人的变化发生冲突,所有在同一地区,那么将是更难以解决。

使用一个mergetool

Git的目的之一就是版本控制。 其他程序专注于合并文件和解决冲突。 如果你将一个mergetoolconfiguration成和git一起使用,那么它可以自动解决git认为是冲突的许多问题,或者至less为你检查一个非常好的猜测,如果看起来没问题就干脆离开,或者你信任这个工具。

这减less了真正的冲突,需要一个明智的决议来解决。

使用较小的文件

我在mycontrollers.js的底部添加一个新的控制器,并在yourcontrollers.js的底部添加一个新的控制器:没问题。

我们都在allcontrollers.js :冲突的底部添加一个新的控制器。

(但是请记住关于按字母顺序排列事物的build议,以M开头的myNewController()可能在文件的中间,而以Y开头的yourNewController()可能会在同一个文件的末尾,再次没有冲突。

使用附加的块开始

像这样的软件…

 function chess() { while (!end_of_game) { make_move() 

带有花括号的起始块的行很容易与单个花括号的软件中的其他行混淆。 如果同样的软件是这样写的,追加块开始到前面的行…

 function chess() { while (!end_of_game) { make_move() 

我个人不喜欢,但是Git确实有很多看起来和Git很相似的行,并且会被误认为是对方,也就是说Git更像是认为编辑和我们做的一样,使得冲突更容易解决。

并评论块结尾

使用注释来区分类似的线条。

如果你写了很多的JavaScript和JSON,你可能会有很多看起来像这样的线。

  } } } ) 

如果你评论的东西,那么他们可以区分。

  } } } ) // end of weekdays() 

  } } } ) // end of weekend() 

不再看起来一样的混帐。 这可以帮助你更好地理解你的改变。 如果你添加一些东西,比如

 function a() { ... } // end of a() 

git更有可能将这看作是一个变化的单位,而不是认为你已经添加了类似的东西

 } function a() { ... 

就在其他函数结束之前。 即使这并不能防止冲突,但如果git明智地看到和展示你的变化(即我们在思维上看待它们的方式),那么你也许可以更容易地解决冲突。 一个描述性的头文件说明了函数做了什么,它们所采用的参数等等,将进一步帮助防止git混淆相邻函数的内容。

为了减less版本控制中的冲突次数而不用担心谁在编辑什么内容,只需进行较小的更改并逐步提交/推送。 将问题分成足够小的部分,以便快速修改文件并将其推回主干。 你的分支越短,合并冲突的机会就越小。

即使这样,在某个时刻,两个人也会同时编辑同一个文件,而不是自己的错误。 发生这种情况的明显问题是:

“我怎么能解决解决git冲突的痛苦?

答案是,你应该经常拉动树干并重新设置分支,当它们仍然很小的时候,你会尽早注意到这些冲突。 在这一点上,开发人员应该坐在一起,冷静地讨论最好的方式,而他们的想法是新鲜的。

对比这种方法,试图在发布截止date之前解决巨大的长期分支机构的恐慌,当时开发商努力记住他们前一段时间所做的所有改变。

对文本文件使用UTF-8而不是UTF-16。

据我所知,许多版本的Git(即我所使用的每个版本)都可以将UTF-16文件视为二进制文件,因为在典型的UTF-16文本文件中存在许多零字节。

一旦Git认为一个文件是一个二进制文件,即使它改变了,它也可能继续把文件视为一个二进制文件。 这意味着版本控制是通过存储文件的完整版本而不是它们之间的差异来完成的,并且版本控制系统的一些优点将会丢失。 (编辑:我最近通过将UTF-16文件更改为UTF-8提交,编辑并再次提交进行了testing,并开始将更改视为文本更改一次。原始文件和编辑文件均为UTF-8。 )

大多数现代编辑器将识别文件的字符编码和行尾样式,并以相同的格式保存文件。 有些编辑器(例如Babelpad)将允许您select是以UTF-8还是UTF-16格式保存文件,也可以使用或不使用字节顺序标记等。

如果您想要进行版本控制的文件是(i)UTF-16格式,并且(ii)在UTF-8中同样可以工作 – 例如一个体面的现代编译器的源程序 – 值得考虑将其转换为UTF-8。

如果Git认为你的源文本是第一次提交之前的二进制文件,那么看看它是否值得在编辑器中加载它,并将其保存为Git识别为文本的不同格式。

(注意,Linux文件默认情况下是UTF-8,一些Windows程序习惯于创buildUTF-16,所以Windows用户最有可能遇到问题,另外请注意,在Git认为它有一个二进制文件之前,首先提交该文件!)

在这里输入图像说明

使用Git rerere

重用logging的分辨率!

https://git-scm.com/book/en/v2/Git-Tools-Rerere