Preamble
I'm using git as a version control system for a paper that my lab is writing, in LaTeX. There are several people collaborating.
I'm running into git being stubborn about how it merges. Let's say two people have made single-word changes to a line, and then attempt to merge them. Though git diff --word-diff seems capable of SHOWING the difference between the branches word-by-word, git merge seems unable to perform the merge word-by-word, and instead requires a manual merge.
With a LaTeX document this is particularly annoying, as the common habit when writing LaTeX is to write a full paragraph per line and just let your text editor handle word wrapping when displaying for you. We are working around for now by adding a newline for each sentence, so that git can at least merge changes on different sentences within a paragraph. But it will still get confused about multiple changes within a sentence, and this makes the text no longer wrap nicely of course.
The Question
Is there a way to git merge two files "word by word" rather than "line by line"?
Merging Branches in a Local Repository To merge branches locally, use git checkout to switch to the branch you want to merge into. This branch is typically the main branch. Next, use git merge and specify the name of the other branch to bring into this branch.
Git can handle most merges on its own with automatic merging features. A conflict arises when two separate branches have made edits to the same line in a file, or when a file has been deleted in one branch but edited in the other.
Here's a solution in the same vein as sehe's, with a few changes which hopefully will address your comments:
As in saha's solution make a (or append to) .gittatributes
.
*.tex filter=sentencebreak
Now to implement the clean and smudge filters:
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\""
I've created a test file with the following contents, notice the one-line paragraph.
\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
After we commit it to the local repo, we can see the raw contents.
$ 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
So the rules of the clean filter are whenever it finds a string of text that ends with .
or ?
or !
or ''
(that's the latex way to do double quotes) then a space, it will add %NL% and a newline character. But it ignores lines that start with \ (latex commands) or contain a comment anywhere (so that comments cannot become part of the main text).
The smudge filter removes %NL% and the newline.
Diffing and merging is done on the 'clean' files so changes to paragraphs are merged sentence by sentence. This is the desired behavior.
The nice thing is that the latex file should compile in either the clean or smudged state, so there is some hope for collaborators to not need to do anything. Finally, you could put the git config
commands in a shell script that is part of the repo so a collaborator would just have to run it in the root of the repo to get configured.
#!/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
That last little bit is a hack because when this script is first run, the branch is already checked out (in the clean form) and it doesn't get smudged automatically.
You can add this script and the .gitattributes file to the repo, then new users just need to clone, then run the script in the root of the repo.
I think this script even runs on windows git if done in git bash.
Drawbacks:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With