Everyone that uses auto generated files like the package-lock.json
, yarn.lock
, Gemfile.lock
or any files that store code coverage reports (or test results) in XML format inside a Git repository has experienced Git conflicts in these files.
Let's see how to resolve this kind of conflict more smoothly.
I'm sure you know that you can delete the package-lock.json
file and run npm install
again - similarly with Yarn.
rm package-lock.json
npm install
git add package-lock.json
But Git can resolve this automatically (plus this solution works for other auto generated files and binary files, e.g. images).
The Git attributes
You can create a special file called .gitattributes
placed in the root of your Git repository where you can manually configure how Git handles files. Let's see an example:
# Auto detect text files and perform LF normalization
* text=auto
# JS and TS files must always use LF for tools to work
*.js eol=lf
*.ts eol=lf
# Use UTF-16 instead of UTF-8 for C source files.
*.c working-tree-encoding=UTF-16LE-BOM
# Mark all JPEG files as binary.
*.jpg binary
# Handle as a text file but merge as binary.
package-lock.json merge=binary
The built-in binary merge driver can't merge binary files, so in case of a conflict Git will leave your package-lock.json
as-is but marked in a conflicted state.
💡 If you want to keep these attributes for youself instead of applying them to every user of a Git repository you can use .git/info/attributes
file with the same structure.
If you need the changes from the upstream branch just checkout the theirs version.
git checkout --theirs package-lock.json
This can also be done with a custom merge driver. 👐
A Git merge driver
A merge driver tries to resolve Git conflicts and you can create your own. Let's define a driver called theirs
that will use the upstream version (%B
) over our version (%A
).
git config --global merge.theirs.name "Keep upstream changes"
git config --global merge.theirs.driver "cp -f '%B' '%A'"
💡 Use --global
to make this driver available to all repositories in your machine.
Then, add the following to your .gitattributes
(or .git/info/attributes
, or ~/.config/git/attributes
) file.
package-lock.json merge=theirs
Now, every conflict will be resolved by our driver accepting the upstream version. Remember that you should run npm install
to re-add your changes to the package-lock.json
because this driver is not smart enough, and discards your changes to the lock file. You need to keep the file in sync with your changes to the package.json
.
The npm merge driver
The npm team has created npm-merge-driver which makes smarter merges than our previous driver - which does an overwrite 😁, keeping the lock file in sync with our changes in the package.json
. You can just install it globally in your machine without affecting your coworkers because the ~/.config/git/attributes
is used for all your cloned repositories.
npx npm-merge-driver install --global
The bad part is that this repo is archived and doesn't receive any updates. 🐛
You can find other merge drivers in the npm registry, even for other types of files like the git-json-merge.
Conclusion
Now we've learned how to handle line endings and fix encodings on Windows using the .gitattributes
.
We can treat auto generated files as a binary
, or as text but with merge=binary
or using a non built-in driver to merge them automatically.
There are long discussions about handling these large files as binaries. Git compresses all the changes so the size of your repo won't be compromised with a binary package-lock.json
file. It's up to you.
Tell me how you manage this type of Git conflicts in the comments.
Top comments (0)