DEV Community

Cover image for Resolving Git conflicts in package-lock.json using a merge driver
Axel Navarro for Cloud(x);

Posted on • Edited on

Resolving Git conflicts in package-lock.json using a merge driver

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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'"
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)