Closed6

VSCodeのGit拡張機能を使って、ブランチ間の差分を表示する

skysan87skysan87

目的

VSCodeのソース管理の拡張機能では、ブランチ間の差分を表示できるものがある。
そういった拡張は多機能なものが多く、DevContainerを使ったリモート開発環境でもこの機能だけ利用可能したいので、自作できるか調査する。

作業

  • VSCodeの拡張機能の開発環境作成
  • VSCode APIでどういったことができるか調査
    • 以前調べたとき、差分表示機能があることは確認済み
skysan87skysan87

VS Code API調査: 差分エディター

VSCodeの差分エディターを開く

vscode.diff - Opens the provided resources in the diff editor to compare their contents.

  • left - Left-hand side resource of the diff editor
  • right - Right-hand side resource of the diff editor
  • title - Human readable title for the diff editor
  • options - (optional) Either the column in which to open, or editor options (see vscode.TextDocumentShowOptions)

https://code.visualstudio.com/api/references/commands

引数leftrightには 比較するテキストを設定することはできなかった。
一時ファイルなどに保存し、URI形式で設定する。

await vscode.commands.executeCommand('vscode.diff',
  vscode.Uri.file(file), 
  vscode.Uri.file(file2),
  'diff'
)

skysan87skysan87

VS Code API: Git拡張機能

ビルトインのGit拡張機能を利用して、VSCodeで開いているフォルダ内のリポジトリを操作できる。
https://stackoverflow.com/questions/59442180/vs-code-git-extension-api

https://github.com/microsoft/vscode/tree/main/extensions/git
公式のREADMEに記載の通り設定する。

  • package.jsonに依存関係を設定
package.json
"extensionDependencies": [
  "vscode.git"
]
  • 定義ファイルsrc/api/git.d.tsをコピペする
  • 拡張機能で呼び出す例
    • 各メソッドの説明はsrc/api/git.d.tsに記載がないため、メソッドから推測したり、上記リポジトリのコードを調べる。
extension.ts
import { type GitExtension } from './git'

const gitExtension = vscode.extensions.getExtension<GitExtension>('vscode.git').exports
const git = gitExtension.getAPI(1)
skysan87skysan87

ブランチ間の比較方法の調査

まず、gitコマンドでの実施方法を調べる。
今回のやりたいコマンドはgit diff ブランチ名1..ブランチ名2の形式で実現可能。
差分はVSCodeの差分エディタで表示するので、ファイル名のみ取得する。

git diff --name-only branch1..branch2

前述のVSCodeのGit機能でこの機能があるか確認した。
メソッド名からRepository.diffBetweenを試してみたが、出力内容はgit diffの結果と異なった。

git.d.ts
export interface Repository {
	diffBetween(ref1: string, ref2: string): Promise<Change[]>;
}

ソースコードを確認したところ、git diff ref1...ref2のコマンドを実行していた(.の数が異なる)。
https://github.com/microsoft/vscode/blob/main/extensions/git/src/git.ts#L1478

ここはVSCodeのGit機能は対応していない、と判断し、node.js経由でgitコマンドを直接実行する。

# Git 1.8.5以降
git -C <リポジトリのパス> <コマンド>
extension.ts
import * as vscode from 'vscode'
import { Branch, Repository, type GitExtension } from './git'
import { execSync } from 'child_process'
import os from 'os'

...(省略)

const gitExtension = vscode.extensions.getExtension<GitExtension>('vscode.git')?.exports
const git = gitExtension?.getAPI(1)
if (!git) return

// VSCodeで開いているフォルダからローカルブランチを取得
const repo: Repository = git.repositories[0] // TODO: UIでユーザに選択させる
const branches: Branch[] = await repo.getBranches({ remote: false })

// git diff --name-only branch1..branch2
// TODO: UIでユーザに選択させる
const src = branches[0].name!
const dist = branches[1].name!
// Git 1.8.5以上で実行可能
const args = ['git', '-C', repo.rootUri.path, 'diff', '--name-only', `${src}..${dist}`]
const stdout = execSync(args.join(' '))
// 差分のあるファイルを取得
const files = stdout.toString().split(os.EOL)
skysan87skysan87

比較するファイルを取得し、差分エディターで表示する

各ブランチのファイルを取得する

いずれかの方法でファイルの内容を取得し、一時フォルダや拡張機能のフォルダ内に保存する。

  • git コマンド
git show ブランチ名:ファイル名
  • VSCodeのGit機能
export interface Repository {
  show(ref: string, path: string): Promise<string>;
}

保存したファイルを差分エディターで表示

await vscode.commands.executeCommand('vscode.diff',
  vscode.Uri.file(file), 
  vscode.Uri.file(file2),
  'diff'
)
このスクラップは2ヶ月前にクローズされました