Browse files

feat(api): set up install and merge as separate command

BREAKING CHANGE: This changes the install api to `npm-merge-driver install [opts]`, and the merge api to `npm-merge-driver merge <npm-bin> <current> <old> <theirs> <filename>`.
  • Loading branch information...
zkat committed Dec 3, 2017
1 parent e2f13c7 commit 76072b9944ab0af8fd9f00cb7a8aa0d109ffa9cf
Showing with 259 additions and 121 deletions.
  1. +52 −13
  2. +51 −24 index.js
  3. +143 −76 package-lock.json
  4. +13 −8 package.json
@@ -2,31 +2,72 @@
# npm-merge-driver(1) -- git merge driver for automatic merging of npm files
## Installing
**NOTE**: This driver **requires** `npm@5.7.0` or higher.
It's recommended to use `npm-merge-driver` through `npx`, or else to install it
as a local `devDependency`.
### Automatic Setup (recommended):
This merge driver works only with `npm@>=5.7`.
To start using it right away:
### Configuring git
$ cd /path/to/git/repository
$ npx npm-merge-driver install
...And you're good to go!
Next time your lockfile has a conflict, it will be automatically fixed. You
don't need to do anything else.
Some assembly is required before you can start auto-merging those lockfiles!
### Example
Automatic (recommended):
$ cd /your/project/dir
$ npx npm-merge-driver --install
$ npx npm-merge-driver install
$ git merge my-conflicting-branch
npm WARN conflict A git conflict was detected in package-lock.json. Attempting to auto-resolve.
added 1 package in 0.077s
Auto-merging package-lock.json
Merge made by the 'recursive' strategy.
package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
$ git status
### Advanced
The following section is only for advanced configuration of the driver if you
have specific needs.
#### Setup Options
`npm-merge-driver install` supports a couple of config options:
`--driver` - string to install as the driver in the git configuration
`--driver-name` - string to use as the merge driver name in your configuration
#### Install as Dependency
To avoid regular `npx` installs, consider installing the driver:
`$ npm install [-g|--save-dev] npm-merge-driver`
#### Manual Setup (advanced):
`npm-merge-driver` requires two git configurations to work:
a git configuration to add the driver to git, which is by default your local
`.git/config` file, and a `gitattributes` configuration, which is by default
your local `.git/info/attributes`.
If you **do not** want `npm-merge-driver` to install itself for you:
Add the driver to `.git/config`:
$ git config merge."npm-merge-driver".name \
"Automatically merge npm lockfiles"
$ git config merge."npm-merge-driver".driver \
"npx npm-merge-driver %A %O %B %P"
"npx npm-merge-driver merge npm %A %O %B %P"
Add the relevant attributes to `.gitattributes` or `.git/info/attributes`:
@@ -35,8 +76,6 @@ package-lock.json merge=npm-merge-driver
npm-shrinkwrap.json merge=npm-merge-driver
Globally: Do the manual steps, on your global or system configurations.
Written by [Kat Marchan](
@@ -4,31 +4,52 @@
const cp = require('child_process')
const fs = require('fs')
const path = require('path')
const yargs = require('yargs')
if (require.main === module) {
function main (argv) {
if (argv[2] === '--install') {
return configureGit()
} else if (argv.length < 6) {
'ERROR: merge file arguments required. Were you looking for --install?'
function parseArgs () {
return yargs
'Set up the merge driver in the current git repository.',
driver: {
type: 'string',
default: 'npx npm-merge-driver merge npm %A %O %B %P',
'string to install as the driver in the git configuration'
'driver-name': {
type: 'string',
default: 'npm-merge-driver',
'string to use as the merge driver name in your configuration'
} else {
return mergeFiles.apply(null, argv.slice(2))
'merge <npm-bin> <%A> <%O> <%B> <%P>',
'Check for lockfile conflicts and correct them if necessary.',
.alias('version', 'v')
.alias('help', 'h')
.epilogue('For the full documentation, see npm-merge-driver(1)')
function configureGit () {
`git config merge."npm-merge-driver".name "automatically merge npm lockfiles"`
function configureGit (argv) {
`git config merge."npm-merge-driver".driver "npx npm-merge-driver %A %O %B %P"`
`git config merge."${argv.driverName}".name "automatically merge npm lockfiles"`
cp.execSync(`git config merge."${argv.driverName}".driver "${argv.driver}"`)
const gitDir = cp
.execSync(`git rev-parse --git-dir`, {
encoding: 'utf8'
@@ -38,17 +59,23 @@ function configureGit () {
path.join(gitDir, 'info', 'attributes'),
'npm-shrinkwrap.json merge=npm-merge-driver',
'package-lock.json merge=npm-merge-driver'
`npm-shrinkwrap.json merge=${argv.driverName}`,
`package-lock.json merge=${argv.driverName}`
function mergeFiles (current, old, theirs, file) {
const ret = cp.spawnSync('git', ['merge-file', '-p', current, old, theirs], {
stdio: [0, 'pipe', 2]
function mergeFiles (argv) {
const ret = cp.spawnSync(
['merge-file', '-p', argv['%A'], argv['%O'], argv['%B']],
stdio: [0, 'pipe', 2]
fs.writeFileSync(argv['%P'], ret.stdout)
cp.spawnSync(argv.npmBin, ['install', '--package-lock-only'], {
stdio: 'inherit'
fs.writeFileSync(file, ret.stdout)
cp.spawnSync('npm', ['install', '--package-lock-only'], { stdio: 'inherit' })
fs.writeFileSync(current, fs.readFileSync(file))
fs.writeFileSync(argv['%A'], fs.readFileSync(argv['%P']))
Oops, something went wrong.

0 comments on commit 76072b9

Please sign in to comment.