Understanding NPM Versioning With Git Tags
If you’ve ever spent much time contributing to or building your own published npm packages, there is a good chance you have run the following set of commands in your terminal.
$ npm version patch
$ git push —-tags origin master
$ npm publish
I know I certainly have. However, given that my knowledge of this workflow originated from watching others or simply being told to do it, I never really gave much thought into what exactly was going on under the hood when each of these three commands were executed. I knew what a git tag was (sort of) and understood that my goal at the end of this set of commands was to bump the version of my npm package and publish that new version to the registry. Why git was involved I wasn’t totally sure. How npm and git worked together, also not totally sure.
Finally, I did some investigating of each command in order to commit (hooray puns) them and their functionality to memory once and for all. I thought it might be nice to share these learnings with others.
Breaking it down, line by line
npm version patch
At first glance, this command looks simple. npm version bumps our package version for us, altering the version in our package.json file in the process. The patch argument indicates that we would like to bump our package’s semver version as a patch.
What isn’t directly apparent is that this command also has git implications. The npm documentation for version reads…
If run in a git repo, it will also create a version commit and tag.
Woah, did not realize how nosy npm was being here. So, in addition to bumping our package’s version and altering our package.json, this command has also added that change and committed it to our local git branch. Furthermore, it has gone along and created a git tag for us, which is named after the new version. All because it recognized that it was being run inside of a git repository.
git push — tags origin master
This one looks so familiar yet has that goofy little ` — tags` option. What’s that doing for us?
In addition to the expected behavior of pushing our local master branch’s commits to the remote repository, it is also updating the remote’s list of tags with the tag that was created for us by npm in step 1.
Lastly, our friendly publish command takes the updated codebase and publishes it to the registry using the information provided in our package.json, including the bumped version.
While the underlying behavior here is probably desired 99% of the time, you aren’t forced into it.
Continuing from the npm documentation indicating the git tag creation,
This behavior is controlled by git-tag-version (see below), and can be disabled on the command line by running npm — no-git-tag-version version. It will fail if the working directory is not clean, unless the — force flag is set.
This means there is a very simple way to avoid npm inherently creating the git commit and tag if preventing such is desired.
Lastly, if you want to learn more about the details of these commands, go ahead and check out the official documentation resources below. Also, during my investigations, I stumbled upon this outrageously cool interactive site from NodeSource that gives a great overview of npm’s role and scope. Check it out!