Git在一行内合并

前言

我使用git作为我的实验室在LaTeX上撰写的论文的版本控制系统。 有几个人合作。

我遇到了git固执的如何合并。 假设有两个人对一行进行了单字改变,然后尝试合并它们。 虽然git diff –word-diff似乎能够逐字显示分支之间的差异,但git merge似乎无法逐字执行合并,而是需要手动合并。

使用LaTeX文档时,特别烦人,因为编写LaTeX的常见习惯是每行写一个完整的段落,让文本编辑器在显示时处理文字换行。 我们现在正在为每个句子添加一个换行符,这样git至less可以合并段落内不同句子的改变。 但是它仍然会对一个句子中的多个变化感到困惑,这使得文本不再被很好地包裹。

问题

有没有办法让git合并两个文件“逐字”而不是“逐行”?

这里的解决scheme和sehe的一样,有一些希望能够解决你的问题的改变:

  • 这个解决scheme考虑用句子而不是用词来合并,直到现在,用户每段都会看到一行,但git会将段落看成句子。 这似乎更合乎逻辑,因为添加/删除段落中的句子可能与段落中的其他更改兼容,但是当两个提交编辑相同的句子时,可能更希望进行手动合并。 这也有“干净的”快照的好处,仍然有点人类可读(和乳胶compilable!)。
  • 这些filter是单行命令,可以使它更容易移植到合作者身上。

就像在saha的解决scheme中一样(或附加到) .gittatributes

  *.tex filter=sentencebreak 

现在执行清洁和污迹filter:

  git config filter.sentencebreak.clean "perl -pe \"s/[.]*?(\\?|\\!|\\.|'') /$&%NL%\\n/g unless m/%/||m/^[\\ *\\\\\\]/\"" git config filter.sentencebreak.smudge "perl -pe \"s/%NL%\n//gm\"" 

我已经创build了以下内容的testing文件,请注意单行的段落。

  \chapter{Tumbling Tumbleweeds. Intro} A way out west there was a fella, fella I want to tell you about, fella by the name of Jeff Lebowski. At least, that was the handle his lovin' parents gave him, but he never had much use for it himself. This Lebowski, he called himself the Dude. Now, Dude, that's a name no one would self-apply where I come from. But then, there was a lot about the Dude that didn't make a whole lot of sense to me. And a lot about where he lived, like- wise. But then again, maybe that's why I found the place s'durned innarestin'. This line has two sentences. But it also ends with a comment. % here 

我们把它交给当地的回购之后,我们可以看到原始内容。

  $ git show HEAD:test.tex \chapter{Tumbling Tumbleweeds. Intro} A way out west there was a fella, fella I want to tell you about, fella by the name of Jeff Lebowski. %NL% At least, that was the handle his lovin' parents gave him, but he never had much use for it himself. %NL% This Lebowski, he called himself the Dude. %NL% Now, Dude, that's a name no one would self-apply where I come from. %NL% But then, there was a lot about the Dude that didn't make a whole lot of sense to me. %NL% And a lot about where he lived, like- wise. %NL% But then again, maybe that's why I found the place s'durned innarestin'. This line has two sentences. But it also ends with a comment. % here 

所以干净的filter的规则是每当它发现一个文本结尾的string. 还是?!'' (这是乳胶的方式做双引号),然后一个空格,它会添加%NL%和一个换行符。 但它会忽略以\(latex命令)开头的行或包含任何地方的注释(以便注释不能成为主要文本的一部分)。

涂抹filter删除%NL%和换行符。

对“干净的”文件进行扩展和合并,因此对段落的改变逐句合并。 这是所需的行为。

好的是,乳胶文件应该在干净或污迹的状态下编译,所以合作者有一些希望不需要做任何事情。 最后,你可以把git config命令放在一个shell脚本中,这个脚本是repo的一部分,所以协作者只需要在repo的根目录下运行它就可以进行configuration。

  #!/bin/bash git config filter.sentencebreak.clean "perl -pe \"s/[.]*?(\\?|\\!|\\.|'') /$&%NL%\\n/g unless m/%/||m/^[\\ *\\\\\\]/\"" git config filter.sentencebreak.smudge "perl -pe \"s/%NL%\n//gm\"" fileArray=($(find . -iname "*.tex")) for (( i=0; i<${#fileArray[@]}; i++ )); do perl -pe "s/%NL%\n//gm" < ${fileArray[$i]} > temp mv temp ${fileArray[$i]} done 

最后一点是黑客,因为当这个脚本第一次运行,分支已经签出(在干净的forms),并不会自动弄脏。

您可以将此脚本和.gitattributes文件添加到回购站,然后新用户只需克隆,然后在回购站的根目录下运行该脚本。

我认为这个脚本甚至运行在Windows GIT,如果在Git bash中完成。

缺点:

  • 这不会巧妙地处理带有注释的行,它只是忽略它们。
  • %NL%有点丑
  • filter可能搞砸了一些方程式(不知道这个)。

可以试试这个:

而不是交换一个合并引擎( ),你可以做一些“规范化”(正规化,如果你愿意的话)。 我不会说LateX,但让我来说明如下:

假设你有类似test.rawinput

 curve ball well received {misfit} whatever proprietary format extinction {benefit}. 

你想要它逐字地差异/合并。 添加以下.gitattributes文件

 *.raw filter=wordbyword 

然后

 git config --global filter.wordbyword.clean /home/username/bin/wordbyword.clean git config --global filter.wordbyword.smudge /home/username/bin/wordbyword.smudge 

最简单的filter的实现将是

/home/username/bin/wordbyword.clean

 #!/usr/bin/perl use strict; use warnings; while (<>) { print "$_\n" foreach (m/(.*?\s+)/go); print '#@#DELIM#@#' . "\n"; } 

/home/username/bin/wordbyword.smudge

 #!/usr/bin/perl use strict; use warnings; while (<>) { chomp; '#@#DELIM#@#' eq $_ and print "\n" or print; } 

提交文件后,用`git show检查提交的blob的原始内容

 HEAD:test.raw`: curve ball well received {misfit} whatever #@#DELIM#@# proprietary format extinction {benefit}. #@#DELIM#@# 

将test.raw的内容更改为

 curve ball welled repreived {misfit} whatever proprietary extinction format {benefit}. 

git diff --patch-with-stat的输出可能是你想要的:

  test.raw | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test.raw b/test.raw index b0b0b88..ed8c393 100644 --- a/test.raw +++ b/test.raw @@ -1,14 +1,14 @@ curve ball -well -received +welled +repreived {misfit} whatever #@#DELIM#@# proprietary -format extinction +format {benefit}. #@#DELIM#@# 

你可以看到这将如何奇迹般的工作合并导致逐字比较和合并。 QED

我希望你喜欢我创造性地使用.gitattributes。如果不是,我喜欢做这个小练习

我相信git mergealgorithm是非常简单的 (即使您可以通过“耐心”合并策略使其更加努力)。
其工作项目将保持不变。

但总体思路是将任何细粒度的检测解决scheme委托给可以使用git config mergetool进行设置的第三方工具。
如果一长串中的某些单词不同,那么这个外部工具( KDiff3DiffMerge ,…)将能够接收到这个更改并呈现给您。