LoginSignup
5
4

More than 5 years have passed since last update.

railsのgeneratorのmergetoolをvscodeに変更する

Posted at

やりたいこと

railsのgenerator、例えばrails g controller Root indexなどを実行した時、生成対象のファイルが既に存在し、生成したものと内容が違った場合、

Running via Spring preloader in process 26159
    conflict  app/controllers/root_controller.rb
Overwrite /path/to/app/controllers/root_controller.rb? (enter "h" for help) [Ynaqdhm]

の様な選択肢が出てきてmキーを叩くとマージできるのですが、その時起動するmergetoolをvscodeに変更します。

やりかた

シェルスクリプトを作ります

#!/bin/bash

tmp_path=$1
destination_path=$2
orig_path=${destination_path}.orig

# オリジナルを一度別名でバックアップ
mv ${destination_path} ${orig_path}

# 二つのファイルを見比べる基準、共通の祖先となるファイルを空で生成
touch ${destination_path}

# mergeする
git merge-file\
  --stdout\
  -L ORIG\
  -L BASE\
  -L GENERATED\
  ${orig_path} \
  ${destination_path} \
  ${tmp_path} > ${destination_path}

# vscodeを起動して、オリジナルのバックアップを削除。
code --wait ${destination_path} && rm -f ${orig_path}

これをどこかパスの通ってる場所に適当な名前でおきます。今回はmergetool_for_rails_generatorという名前でおきました。

環境変数を設定する

# ~/.bash_profile

...
export THOR_MERGE=mergetool_for_rails_generator

反映する

source ~/.bash_profile

これで変更かのです。

なぜこんなめんどくさいか?

git mergetoolをvscodeに変更する方法は散見し、これは期待通り変更できるのですが、これを変えてもgeneratorで起動するmergetoolは変わりません。

変わらないというかsh: vscode: command not foundというエラーで動かなくなります。

なぜそんなことが??と思って保存してるソースを見ると

      def merge(destination, content) #:nodoc:
        require "tempfile"
        Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp|
          temp.write content
          temp.rewind
          system %(#{merge_tool} "#{temp.path}" "#{destination}")
        end
      end

      def merge_tool #:nodoc:
        @merge_tool ||= ENV["THOR_MERGE"] || git_merge_tool
      end

      def git_merge_tool #:nodoc:
        `git config merge.tool`.rstrip rescue ""
      end

こんな感じでgit config merge.toolから採れたコマンドを"#{temp.path}" "#{destination}"という引数で呼び出しているからですね。

ここがハマった

git merge-fileというコマンドがあって、コンフリクトが起きた時よく見る

<<<<<<< A
lines in file A
=======
lines in file B
>>>>>>> B

のようなファイルを生成してくれるので使いたかったのですが、これの引数の渡し方がよくわからなかったです。

git merge-file fileA fileB fileC

オプションはさておき、三つの引数が必要なのですが、「fileBとfileAの差分」と「fileBとfileCの差分」をfileBにマージしてfileAに書き込むという難しい仕様です。

要はfileBが共通の祖先で、そこから先の変更のみに注目してマージすると言うことですね。書き込み先ファイルも変更したかったので--stdoutで書き出しを抑制し指定したファイルに書き込んでます。

generatorの場合、例えばcontrollerだったら、本当はクラス定義部分などは共通の祖先として指定したいところではあります。それができればオートマージが成功する可能性も上がると思われます。

独自generatorであればテンプレートにコメントでマークをつけておいて「共通の祖先」を生成することも不可能ではないと思いますが・・・ファイルの種類も多いしとりあえずこれでお茶を濁します。

5
4
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
5
4