Search code examples
jsongiteslintpackage.jsonpackage-lock.json

Is there any way to prevent from commintng package-lock.json unless package.json has changed?


These days I have a problem of pushing package-lock.json unintentionally.

Ex)

I run npm install in my feature branch and my package-lock.json is updated.

I made a commit and my feature branch is merged into develop branch. Package-lock.json in develop branch is overwritten by package-lock.json in my feature branch.

Due to updated packages in package-lock.json, it broke the application.


I know that I have to be careful not to push package-lock.json unless package.json has changed, however, sometime I forget.

So I'm thinking if I can add some rule in pre-commit to show some warning if I commit package-lock.json only. Is there any way to accomplish it?

thank you


Solution

  • If you are already using Git Hooks like "pre-commit", you can basically add one more script to the "pre-commit" list and write a script that does what you need (code below).

    Using a combination of git/grep commands you can check that in the list of staged files, "package.json" and "package-lock.json" are both there (or none of them is).

    The script can be:

    #!/bin/sh
    if [ `git diff --name-only --cached | egrep -c 'package.json|package.lock.json'` == "0" -o `git diff --name-only --cached | egrep -c 'package.json|package.lock.json'` == "2" ]; then
      echo "Checked successfully."
    elif [ `git diff --name-only --cached | egrep -c 'package.json'` == "1" -a `git diff --name-only --cached | egrep -c 'package.lock.json'` == "0" ]; then
      echo "Warning: you are committing package.json without package.lock.json"
    else
      echo "Error: make sure you commit BOTH package.json and package.lock.json"
      exit 1
    fi
    exit 0
    

    git diff --name-only --cached gets the list of staged files (file names only)

    | use the result of previous command as argument for the next

    egrep to perform a search (in this case search for strings 'package.json' and 'package.lock.json')

    -c counts the number of matches

    Wrapping the whole command in backticks will execute it and provide the result to the main script.

    The result of the git+egrep command returns the number of occurrences found. You then check what this result is, to tell the script to continue (exit 0) or quit (exit 1).

    Make the script file executable, and add the reference to it in your package.json:

    "scripts": {
      "check-package": "./bin/check-package.sh",
    }
    ...
    "pre-commit": [
      "check-package"
    ]
    

    That should be it!

    When you are done, just make sure you first commit the script only, and then package.json (otherwise it would already look for the script, without finding it).

    Final note: This approach is valid to check any 2 or more files that need to be there at the same time in the list of files staged for commit.