はじめに
前回は1ファイルにベタ書きしてしまったので、今回はgit呼び出し関数をモジュールに切り分けて別スクリプトからも利用できるようにしてみた。
コード
そのままモジュール化するのも芸がないので、各関数の中身もベタ書きしてたのを共通処理runCmd: string[] -> Promise<string | null>
として括り出してみた。
runCmdはコマンドを呼び出して、失敗したならnullを、成功したなら標準出力を文字列として返す。
git.ts
export async function branches(): Promise<string[]> {
const ret = await runCmd(['git', 'rev-parse', '--abbrev-ref', '--branches'])
if (ret === null) return []
return ret.split(/\r\n|\n/)
}
export const currentBranch = () => runCmd(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
export const checkoutBranch = async (branch: string) => null !== await runCmd(['git', 'checkout', '-b', branch])
export const checkout = async (branch: string) => null !== await runCmd(['git', 'checkout', branch])
export const merge = async (branch: string) => null !== await runCmd(['git', 'merge', '--no-ff', branch])
export const deleteBranch = async (branch: string) => null !== await runCmd(['git', 'branch', '-D', branch])
async function runCmd(cmds: string[]): Promise<string | null> {
const p = Deno.run({ cmd: cmds, stdout: 'piped', stderr: 'piped' })
const { code } = await p.status()
return code !== 0 ? null : (new TextDecoder().decode(await p.output())).trim()
}
あとはgit.tsをインポートする形にgit-wip.tsを書き換えて終了。
git-wip.ts
// Usage: deno run --allow-run git-wip.ts
// 現在のブランチがworkなら wip/YYYYMMDD_hh ブランチを作成し移動
// wip/~ ブランチならworkブランチにマージ
//
// Script install: deno install --allow-run ~/denoscripts/git-wip.ts
// 上記でインストールすると ~/.deno/bin に ~/denoscripts/git-wip.ts を呼び出すスクリプトが作られる
// ~/denoscripts/git-wip.ts自体は~/.deno/binにコピーされない
import * as git from './git.ts'
async function main(): Promise<number> {
const work = 'work'
const twoDigits = (n: number): string => (n > 9 ? '' : '0') + n
const current = await git.currentBranch()
if (current === null) {
console.error('not a git repository')
return -1
} else if (current === work) {
const now = new Date()
const wip = `wip/${now.getFullYear()}${twoDigits(now.getMonth() + 1)}${twoDigits(now.getDate())}_${twoDigits(now.getHours())}`
if (await git.checkoutBranch(wip)) {
console.log(`branching "${wip}"`)
} else {
console.error(`do not branching "${wip}"`)
return -1
}
} else if (current.startsWith('wip/')) {
if (!(await git.branches()).includes(work)) {
console.error('no exists "work" branch')
return -1
} else {
console.log(`${current} is merging to work`)
await git.checkout(work)
await git.merge(current)
await git.deleteBranch(current)
}
} else {
console.error('not a work or wip branch')
return -1
}
return 0
}
Deno.exit(await main())
せっかくなのでgit.tsを利用したマージ処理も作る。
処理の流れは、現在のブランチを覚えておいて、toブランチに切り替え、fromブランチをマージ、覚えておいた元のブランチに戻るというもの。
git-mgft.ts
// Usage: deno run --allow-run git-mgft.ts from to
// fromをtoにマージする
import * as git from './git.ts'
async function main(): Promise<number> {
if (Deno.args.length < 2) {
console.error('Usage: git-mgft from to');
return -1
}
const [branchFrom, branchTo] = Deno.args
const current = await git.currentBranch()
if (current === null) {
console.error('not a git repository')
return -1
}
const info = await git.branches()
if (info.indexOf(branchFrom) < 0 || info.indexOf(branchTo) < 0) {
console.error('no branch: ' + branchTo)
return -1
}
console.log(`git merge: ${branchFrom} -> ${branchTo}`)
await git.checkout(branchTo)
await git.merge(branchFrom)
await git.checkout(current)
return 0
}
Deno.exit(await main())