Run Git commands from Node.js application using JavaScript! 🚀
Tags: javascript, git, node
Published: 2021-01-25 17:00:49

When dealing with large applications and with **complex, CI/CD pipelines with multiple staging environments**, it might be useful for you to have some way to automate applying the latest changes from one environment to the other.

## Consistency between multiple environments
At my work, we have three environments - one is the production environment (**PROD**), and two others are for fixing critical errors (**HOTFIX**) and developing new stuff (**STAGING**) with the possibility of introducing breaking changes.

While creating a pull request with a quick fix of some bug and merging it to the **HOTFIX** environment (with future deployment to production), it is also necessary to have this code in the **STAGING** environment, so the future deployment of **STAGING** into **PROD** would not cause conflicts.

The easiest way for having this cross-environment consistency is to make cherry-pick of the commit to **STAGING** after it is merged into **HOTFIX**. Easy, but manual, and since it's manual, someone can forget to do this. 😅 Plus, we need to know the specific identifier of a commit, so it's rather tricky for automatization.

Another way to achieving this is to rebase **STAGING** on top of **HOTFIX** periodically. By doing it, we will have all of our feature changes as well as fixes of bugs. And also, it is somewhat manual work, but this time it is easy for automatization.

For this automatization, we will use a [simple-git](https://github.com/steveukx/git-js) library.

## A lightweight interface for running git commands
[Simple-git](https://github.com/steveukx/git-js) is a tool for running git commands in any Node.js application. 
It gives us access to make all kinds of permutations on top of your commits and branches. With that library, we can easily create a script responsible for releasing our latest changes and running it from the command line.

All we need to do in order to start using simple-git is to include into our JavaScript app and create a `git` instance:

```js
const simpleGit = require("simple-git");
const git = simpleGit.default();
```

Then, we have access to any git command as well as for options supported by that command. You can later visit the [public API of the library](https://github.com/steveukx/git-js#api) to see the full list of available methods. 

For now, simply try to checkout on some test branch:

```js
await git.checkout("test-branch");
const branch = await git.branch();

// logs "test-branch"
console.log(branch.current)
```
It works, and it's plain and simple like standard git commands! 🙂

> **Note**: Remember that from within your script, any git command is like a side-effect, and it is not synchronous. 

Let's imagine having a script like one below, which executes all the commands needed for rebase one branch into another:

```js
async function main() {
  try {
    const status = await git.status();

    if (!status.isClean()) {
      return;
    }

    await git.checkout("HOTFIX");
    await git.reset("hard", ["origin/HOTFIX"]);
    await git.pull();

    await git.checkout("STAGING");
    await git.reset("hard", ["origin/STAGING"]);
    await git.pull();

    await git.rebase(["HOTFIX"]);
    await git.push("origin", "STAGING", ["--force"]);
  } catch (error) {
    const status = await git.status();

    if (status.conflicted.length > 0) {
      return;
    }

    console.log(error);
  }
}
```

Our script fetches the latest changes on every branch, then it rebases **STAGING** branch on top of **HOTFIX**. Before executing anything, we check for not committed files since a hard reset will discard any changes made in development. Unfortunately in case of an error or merge conflicts, we must continue manually. 

So we have an automated way of rebasing branches to date with the latest **HOTFIX** environment. And with [chalk](https://github.com/chalk/chalk), we can make it a beautiful command-line script:

{% twitter 1349085418269138946 %}

Now with this script, which takes care of rebasing for us, the whole process of making your environments consistent is encapsulated in one single file, which can be executed from the command-line.

```js
node update-branches.js

// or we can specify a command in package.json
yarn update:branches
npm run update:branches
```

I guess it is even possible to hook up this script in the deployment pipeline, for example, with [Github Actions](https://github.com/features/actions) or [Husky](https://github.com/typicode/husky). I will explore this topic in the future. 😃


I really recommend you to inspect this awesome library for yourselves!


Thanks for reading! If you are interested in the latest tech news, you can follow my account since I plan to post here regularly. I also tweet on a regular basis so that you can follow [My Twitter account](https://twitter.com/SkonecznyJakub) as well!