LoginSignup
1
0

More than 3 years have passed since last update.

denoでgitを呼び出してみた

Last updated at Posted at 2020-06-12

はじめに

nodeでgitブランチをちょっと弄るやつを書いて使ってたんだけど、せっかくだしdenoで書き直してnodeからdenoに完全に乗り換えようかなと思った。

とりあえずgithubからモジュールを読み込めるみたいだし、元々nodeでやってたのと同じようにnpmパッケージのsimple-gitを使えば良いかなとインポートしてみたら、インポート文だけなら問題なかったけど、中身を利用しようとすると文句言われたので結局Deno.runを使って自前でgitを呼び出すことに…

コード

workブランチにwip/日時ブランチを作って作業して、終わったらworkにマージという定形作業をやるスクリプトです。
deno installでスクリプトインストールすれば作業開始も終了もgit-wipを実行するだけというお手軽仕様。

gitの標準出力を取得するためにはDeno.runに{stdout: 'piped'}を渡して、new TextDecoder().decode(await p.output())でstringにしないといけない。

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にコピーされない

async function branches(): Promise<string[]> {
  const p = Deno.run({ cmd: ['git', 'rev-parse', '--abbrev-ref', '--branches'], stdout: 'piped', stderr: 'piped' })
  const { code } = await p.status()
  if (code !== 0) return []
  return (new TextDecoder().decode(await p.output())).trim().split(/\r\n|\n/)
}

async function currentBranch(): Promise<string | null> {
  const p = Deno.run({ cmd: ['git', 'rev-parse', '--abbrev-ref', 'HEAD'], stdout: 'piped', stderr: 'piped' })
  const { code } = await p.status()
  return code !== 0 ? null : (new TextDecoder().decode(await p.output())).trim()
}

async function checkoutBranch(branch: string): Promise<boolean> {
  const p = Deno.run({ cmd: ['git', 'checkout', '-b', branch], stdout: 'piped', stderr: 'piped' })
  const { code } = await p.status()
  return code === 0
}

async function checkout(branch: string): Promise<boolean> {
  const p = Deno.run({ cmd: ['git', 'checkout', branch], stdout: 'piped', stderr: 'piped' })
  const { code } = await p.status()
  return code === 0
}

async function merge(branch: string): Promise<boolean> {
  const p = Deno.run({ cmd: ['git', 'merge', '--no-ff', branch], stdout: 'piped', stderr: 'piped' })
  const { code } = await p.status()
  return code === 0
}

async function deleteBranch(branch: string): Promise<boolean> {
  const p = Deno.run({ cmd: ['git', 'branch', '-D', branch], stdout: 'piped', stderr: 'piped' })
  const { code } = await p.status()
  return code === 0
}

const work = 'work'
const twoDigits = (n : number): string => (n > 9 ? '' : '0') + n

const current = await currentBranch()
if (current === null) {
  console.error('not a git repository')
  Deno.exit(-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 checkoutBranch(wip)) {
    console.log(`branching "${wip}"`)
    Deno.exit(0)
  } else {
    console.error(`do not branching "${wip}"`)
    Deno.exit(-1)
  }
} else if (current.startsWith('wip/')) {
  if (!(await branches()).includes(work)) {
    console.error('no exists "work" branch')
    Deno.exit(-1)
  } else {
    console.log(`${current} is merging to work`)
    await checkout(work)
    await merge(current)
    await deleteBranch(current)
    Deno.exit(0)
  }
} else {
  console.error('not a work or wip branch')
  Deno.exit(-1)
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0