Node.js で Git 操作。simple-git を使ってみた
Node.js プログラムの中で Git 操作をする必要が出た。そのようなライブラリはいくつかあるようだが、simple-git というライブラリが手っ取り早そうだったので紹介する。
- simple-git - npm
- GitHub - steveukx/git-js: A light weight interface for running git commands in any node.js application.
目次
前提条件
simple-git は内部的に child_process.spawn()
を使って実際の git
コマンドを実行する、ラッパーライブラリに過ぎない。
つまり、simple-git 含めた Node.js プログラムを動かす環境に、git
コマンドがインストールされている必要がある。
グローバルな Git Config なども影響するので、動作環境に注意が必要だ。
とりあえず試してみる
それではとりあえず書いてみるとしよう。TypeScript ベースで書いてみるので、最低限のパッケージ類を用意する。
# 適当な作業ディレクトリを作成する
$ npm init -y
# tsconfig.json を準備する
cat <<EOL > tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs"
}
}
EOL
$ npm i -S simple-git
$ npm i -D typescript ts-node @types/node
# コーディングするファイルを作っておく
$ touch index.ts
コレで準備 OK。一応、本稿執筆時点でのパッケージバージョンは次のとおり。
$ npm ls --depth=0
practice-simple-git@0.0.0 /Users/Neo/practice-simple-git
├── @types/node@14.0.14
├── simple-git@2.11.0
├── ts-node@8.10.2
└── typescript@3.9.6
index.ts
を次のように実装していく。
import { promises as fs } from 'fs';
import simpleGit from 'simple-git';
(async () => {
// Git リポジトリを配置するローカルのパス。フルパス指定
const workingDirectory = `${__dirname}/my-pepo`;
// 操作したい Git リポジトリの URL。必要に応じてユーザ名やパスワードを指定したりする
const repositoryUrl = `https://github.com/Neos21/Neos21.git`;
try {
// 対象のディレクトリがなければ git clone する
if(!await fs.access(workingDirectory).then(() => true).catch(() => false)) {
await simpleGit().clone(repositoryUrl, workingDirectory);
}
const git = simpleGit(workingDirectory);
// 指定のブランチに切り替える (以下はリモートブランチがない場合はエラーとなる書き方)
await git.checkout('feat/example');
await git.pull();
// ファイルを保存したり〜
const newFilePath = `${workingDirectory}/NEW-FILE.txt`;
await fs.writeFile(newFilePath, 'New File Text', 'utf-8');
// コミット・プッシュするなど
await git.add(newFilePath);
await git.commit('Example Commit');
await git.push();
}
catch(error) {
console.error('エラー', error);
}
})();
こんな感じ。
最近知ったのだが、Node.js の fs
モジュールに、Promise 化済のモジュールが存在していた。fs.promises
というヤツで、生 Node.js だと
const fs = require('fs').promises;
なんて読み込んでも良い。もう util.promisify
って使わなくて良いのね…。
んで、fs.exists()
および fs.existsSync()
は非推奨になっているので、存在チェックのために fs.access()
を使用した。コレは Promise<void>
なメソッドなので、Boolean に扱うために if
文の中でちょっとした工夫をしている。await
した関数の Boolean を反転させる時は !await
(! await
) で良い。git clone
については後述する。
Git 用のディレクトリが用意できたら、simpleGit(path)
でインスタンスを作っておく。後はコレを使って git
コマンド1つにつき async
・await
で処理してやれば良い。当然 Promise で書いても良い。
今回の例では、指定のブランチに切り替え → Pull で最新化 → 適当なファイルを作成する (ココは fs
で普通に作業) → Add して Commit して Push、という流れ。こんなことが Node.js 上で出来てしまうのだ。
クレデンシャル情報の渡し方
simpleGit().clone()
で git clone
を行うのだが、コレはターミナルで
$ git clone 【Git URL】
コマンドが実行されるのと同じことになる。つまり、~/.gitconfig
などでクレデンシャル情報が辿れないと、そのリポジトリをクローンできないのだ。
GitHub なんかでもっとも手っ取り早いのは、URL にユーザ名とパスワード (or トークン) を混ぜ込んでしまう例。
const userName = 'Neos21';
const password = 'MY_PASSWORD';
await simpleGit().clone(`https://${userName}:${password}@github.com/USER_NAME/REPOSITORY_NAME.git`, workingDirectory);
環境変数なんかで注入できれば、コレが楽かもしれない。
Docker コンテナに閉じた環境であれば、~/.gitconfig
および ~/.gitconfig-credential
を用意して、
[credential]
helper = store --file ~/.gitconfig-credential
みたいなグローバルコンフィグを用意しても良いだろう。
また、~/.netrc
ファイルを用意して、
machine github.com
login 【ユーザ名】
password 【パスワード】
と記述して配置すれば、git clone
時の URL にユーザ名やパスワードを書かなくても処理できたりする。
いずれにおいても、生の git
コマンドがそのマシン環境で実行されていることを見越して、Docker コンテナに閉じる際はどうやってクレデンシャル情報を渡しておこうか、といったことを考えておく必要がある。
以上
手軽に Git 操作ができて良き良き。