Resolving Git conflicts in package-lock.json using a merge driver
Tags: git, npm, node, github
Published: 2022-09-20 13:21:51

---
title: Resolving Git conflicts in package-lock.json using a merge driver
published: true
description: Using Git attributes and merge drivers to resolve conflicts automatically.
tags: 'git, npm, node, github'
cover_image: 'https://raw.githubusercontent.com/cloudx-labs/posts/main/posts/navarroaxel/assets/resolving-git-conflicts-merge-driver-cover.jpg'
id: 1188285
date: '2022-09-20T13:21:51Z'
---

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.

```bash
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`](https://git-scm.com/docs/gitattributes) placed in the root of your Git repository where you can manually configure how Git handles files. Let's see an example:

```text
# 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.

```bash
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](https://git-scm.com/docs/gitattributes#_defining_a_custom_merge_driver). Let's define a driver called `theirs` that will use the upstream version (`%B`) over our version (`%A`).

```bash
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.

```text
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](https://github.com/npm/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.

```bash
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](https://github.com/jonatanpedersen/git-json-merge).

## Conclusion

Now we've learned how to handle line endings and [fix encodings on Windows](https://www.git-scm.com/docs/gitfaq#_cross_platform_issues) 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](https://github.com/yarnpkg/yarn/issues/1776) [discussions](https://mail.kde.org/pipermail/kde-devel/2022-August/001256.html) [about](https://www.reddit.com/r/webdev/comments/ak16q8/set_your_packagelockjson_as_a_binary_in/) 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.