- 投稿日:2019-11-27T18:36:34+09:00
Git Hooksでgit cloneだけをフックする(共通テンプレートだけでは不十分なケース)
やりたいこと
言わば、
post-clone
フックです。git clone
実行後だけリポジトリディレクトリに対して特定の処理がしたい。その際、clone先ディレクトリに応じて処理を分岐させたい。つまり、共通テンプレートを設定しておくだけでは不十分。結論
trap DEBUG
でgit clone
を叩いたことを検知して、コマンド実行前にフラグを立てる。- post-checkoutスクリプト内でフラグが立っているときだけ処理を行い、処理後フラグを倒す。
- 今回の記事の本筋ではないが、注意点として、GitHooksは標準入力を利用しないので、処理の中で入力を待ちたい場合はターミナルからリダイレクションする必要あり。
背景
前の記事で、gitアカウントを自動で切り替えるために
git clone
前に処理をする必要があったので、cd
とgit
のラッパー関数を作り、エイリアスで元のcd
とgit
を上書きして、cd
をフックにgit
コマンドが使用する変数を切り替えるようにしました。しかし、他のライブラリを利用してcd
以外でディレクトリ移動するケースを考えるとやはり汎用性に欠け、取り急ぎとはいえ筋が良くなかったので、潔くgit clone
を直接フックすることにしました。意外にも
git clone
だけをフックする方法に関する記事を見かけなかったので書きました。記事がないということは全く必要とされていないのか、それとも記事にならないほどもっと楽な方法があるのか、知ってる人が書いてないだけなのか。ちなみに、GitHooksとは、というお話は以下を参照。
git hook はじめの一歩
git hookでできること問題
Git Hooksで
git clone
をフックしたいとき、post-checkout
を使う必要がありますが、これだとgit checkout
のときにも実行されます。また、clone先ディレクトリに応じて処理を分岐させるので、共通テンプレートを設定するだけでは実現できません。
解決策
環境
macOS
sw_vers ProductName: Mac OS X ProductVersion: 10.14.5 BuildVersion: 18F132Git
git --version git version 2.23.0
Bash
bash --version GNU bash, version 5.0.11(1)-release (x86_64-apple-darwin18.6.0)
git clone
の実行を検知するGist: .bash_hooksとして置いておきました。使い方はGist冒頭に書いてあります。このGistには、ディレクトリ移動の検知や、コマンド実行前だけでなくコマンド実行後に実行される処理もまとめて書いているのですが、今回の記事に関わるポイントは以下の3点です。
- 各コマンドの実行前に
__hooks__before_each_command
が実行されるようにするtrap '__hooks__before_each_command' DEBUG
__hooks__before_each_command
内でBASH_COMMAND
で直前のコマンド名(=叩かれたコマンド名)を取得- フックがアクティベートされていたら(この上記Gistの最後でアクティベートしてます)
__hooks__set_git_clone_flag
に直前のコマンド名を渡して実行function __hooks__before_each_command() { local last_command=( $BASH_COMMAND ) if [ -z "$__HOOKS__ACTIVATED" ]; then return fi # before each command __hooks__set_git_clone_flag "${last_command[@]}"; if [ -z "$__HOOKS__EXECUTING_LINE" ]; then return fi unset __HOOKS__EXECUTING_LINE # before each first command of a comamnd line }
- 直前に叩かれたコマンド名が
git clone
だった場合、__hooks__set_git_clone_flag
内で__HOOKS__ON_GIT_CLONE
フラグを立てるfunction __hooks__set_git_clone_flag() { if [ 'git' = "$1" ] && [ 'clone' = "$2" ]; then echo "Setting __HOOKS__ON_GIT_CLONE=true in $filename" export __HOOKS__ON_GIT_CLONE=true fi }
post-checkout
内でフラグをチェックして処理するGist: post-checkoutとして置いておきました。
.gitvariables
というファイルを置いてgitアカウントの情報をロードするようにして、そのファイル自体は~/.gitignore
に登録してトラックしないようにしてあります。
- ここでフラグをチェックして、フラグが立ってなかったら
exit
してます。if [ -z "$__HOOKS__ON_GIT_CLONE" ]; then exit fi
- 処理の最後にフラグを倒します。
unset __HOOKS__ON_GIT_CLONE
GitHooks中でユーザの入力を待ちたいときの注意点
オフトピックですが注意点として、GitHooksは標準入力を利用しないので、処理の中で入力を待ちたい場合はターミナルからリダイレクションする必要があります。ちょっとハマりました。
read -rp 'Type anything you like:' < /dev/ttyまとめ
コードが散在することと、暗示的にフックすることでハマったりしないように、多用には注意が必要ではありますが、cdとgit上書きより汎用的かつ拡張しやすくなった感はあります。
ちなみに、Bashのコマンドの実行前後をフックする方法の解説はChuan Ji: DEBUG trap and PROMPT_COMMAND in Bashの記事がわかりやすいです。
参考
- 投稿日:2019-11-27T18:36:34+09:00
Git Hooksのpost-checkoutでgit cloneだけをフックする
やりたいこと
git clone
実行後だけリポジトリディレクトリに対して特定の処理がしたい。TLDR
trap DEBUG
でgit clone
を叩いたことを検知して、コマンド実行前にフラグを立てる。- post-checkoutスクリプト内でフラグをチェックして分岐させる。
- 今回の記事の本筋ではないが、注意点として、GitHooksは標準入力を利用しないので、処理の中で入力を待ちたい場合はターミナルからリダイレクションする必要あり。
背景
前の記事で、gitアカウントを自動で切り替えるために
git clone
前に処理をする必要があったので、cd
とgit
のラッパー関数を作り、エイリアスで元のcd
とgit
を上書きしました。他のライブラリを利用していてcd
以外でディレクトリ移動するケースを考えるとやはり汎用性に欠け、取り急ぎとはいえ筋が良くなかったので、潔くgit clone
を直接フックすることにしました。
意外にもgit clone
だけをフックする方法に関する記事を見かけなかったので書きました。記事がないということは全く必要とされていないのか、それとも記事にならないほどもっと楽な方法があるのか、知ってる人が書いてないだけなのか。問題
Git Hooksで
git clone
をフックしたいとき、post-checkout
を使う必要がありますが、これだとgit checkout
のときにも実行されます。解決策
環境
macOS
sw_vers ProductName: Mac OS X ProductVersion: 10.14.5 BuildVersion: 18F132Git
git --version git version 2.23.0
Bash
bash --version GNU bash, version 5.0.11(1)-release (x86_64-apple-darwin18.6.0)
git clone
の実行を検知するGist: .bash_hooksとして置いておきました。使い方はGist冒頭に書いてあります。このGistには、ディレクトリ移動の検知や、コマンド実行前だけでなくコマンド実行後に実行される処理もまとめて書いているのですが、今回の記事に関わるポイントは以下の3点です。
- 各コマンドの実行前に
__hooks__before_each_command
が実行されるようにするtrap '__hooks__before_each_command' DEBUG
__hooks__before_each_command
内でBASH_COMMAND
で直前のコマンド名(=叩かれたコマンド名)を取得- フックがアクティベートされていたら(この上記Gistの最後でアクティベートしてます)
__hooks__set_git_clone_flag
に直前のコマンド名を渡して実行function __hooks__before_each_command() { local last_command=( $BASH_COMMAND ) if [ -z "$__HOOKS__ACTIVATED" ]; then return fi # before each command __hooks__set_git_clone_flag "${last_command[@]}"; if [ "$PREVPWD" != "$PWD" ]; then # on changing directories export PREVPWD="$PWD" fi if [ -z "$__HOOKS__EXECUTING_LINE" ]; then return fi unset __HOOKS__EXECUTING_LINE # before each first command of a comamnd line }
- 直前に叩かれたコマンド名が
git clone
だった場合、__hooks__set_git_clone_flag
内で__HOOKS__ON_GIT_CLONE
フラグを立てるfunction __hooks__set_git_clone_flag() { if [ 'git' = "$1" ] && [ 'clone' = "$2" ]; then echo "Setting __HOOKS__ON_GIT_CLONE=true in $filename" export __HOOKS__ON_GIT_CLONE=true fi }
post-checkout
内でフラグをチェックして処理するGist: post-checkoutとして置いておきました。
.gitvariables
というファイルを置いてgitアカウントの情報をロードするようにして、そのファイル自体は~/.gitignore
に登録してトラックしないようにしてあります。
- ここでフラグをチェックして、フラグが立ってなかったら
exit
してます。if [ -z "$__HOOKS__ON_GIT_CLONE" ]; then exit fi
- 処理の最後にフラグを倒します。
unset __HOOKS__ON_GIT_CLONE
GitHooks中でユーザの入力を待ちたいときの注意点
オフトピックですが注意点として、GitHooksは標準入力を利用しないので、処理の中で入力を待ちたい場合はターミナルからリダイレクションする必要があります。ちょっとハマりました。
read -rp 'Type anything you like:' < /dev/ttyまとめ
コードが散在することと、暗示的にフックすることでハマったりしないように、多用には注意が必要ではありますが、拡張しやすくなった感はあります。
ちなみに、Bashのコマンドの実行前後をフックする方法の解説はChuan Ji: DEBUG trap and PROMPT_COMMAND in Bashの記事がわかりやすいです。
参考
- 投稿日:2019-11-27T18:36:34+09:00
Git Hooksでgit cloneだけをフックする
やりたいこと
言わば、
post-clone
フックです。git clone
実行後だけリポジトリディレクトリに対して特定の処理がしたい。その際、clone先ディレクトリに応じて処理を分岐させたい。つまり、共通テンプレートを設定しておくだけではうまくいかない。結論
trap DEBUG
でgit clone
を叩いたことを検知して、コマンド実行前にフラグを立てる。- post-checkoutスクリプト内でフラグが立っているときだけ処理を行い、処理後フラグを倒す。
- 今回の記事の本筋ではないが、注意点として、GitHooksは標準入力を利用しないので、処理の中で入力を待ちたい場合はターミナルからリダイレクションする必要あり。
背景
前の記事で、gitアカウントを自動で切り替えるために
git clone
前に処理をする必要があったので、cd
とgit
のラッパー関数を作り、エイリアスで元のcd
とgit
を上書きして、cd
をフックにgit
コマンドが使用する変数を切り替えるようにしました。しかし、他のライブラリを利用してcd
以外でディレクトリ移動するケースを考えるとやはり汎用性に欠け、取り急ぎとはいえ筋が良くなかったので、潔くgit clone
を直接フックすることにしました。意外にも
git clone
だけをフックする方法に関する記事を見かけなかったので書きました。記事がないということは全く必要とされていないのか、それとも記事にならないほどもっと楽な方法があるのか、知ってる人が書いてないだけなのか。ちなみに、GitHooksとは、というお話は以下を参照。
git hook はじめの一歩
git hookでできること問題
Git Hooksで
git clone
をフックしたいとき、post-checkout
を使う必要がありますが、これだとgit checkout
のときにも実行されます。また、clone先ディレクトリに応じて処理を分岐させるので、共通テンプレートを設定するだけでは実現できません。
解決策
環境
macOS
sw_vers ProductName: Mac OS X ProductVersion: 10.14.5 BuildVersion: 18F132Git
git --version git version 2.23.0
Bash
bash --version GNU bash, version 5.0.11(1)-release (x86_64-apple-darwin18.6.0)
git clone
の実行を検知するGist: .bash_hooksとして置いておきました。使い方はGist冒頭に書いてあります。このGistには、ディレクトリ移動の検知や、コマンド実行前だけでなくコマンド実行後に実行される処理もまとめて書いているのですが、今回の記事に関わるポイントは以下の3点です。
- 各コマンドの実行前に
__hooks__before_each_command
が実行されるようにするtrap '__hooks__before_each_command' DEBUG
__hooks__before_each_command
内でBASH_COMMAND
で直前のコマンド名(=叩かれたコマンド名)を取得- フックがアクティベートされていたら(この上記Gistの最後でアクティベートしてます)
__hooks__set_git_clone_flag
に直前のコマンド名を渡して実行function __hooks__before_each_command() { local last_command=( $BASH_COMMAND ) if [ -z "$__HOOKS__ACTIVATED" ]; then return fi # before each command __hooks__set_git_clone_flag "${last_command[@]}"; if [ -z "$__HOOKS__EXECUTING_LINE" ]; then return fi unset __HOOKS__EXECUTING_LINE # before each first command of a comamnd line }
- 直前に叩かれたコマンド名が
git clone
だった場合、__hooks__set_git_clone_flag
内で__HOOKS__ON_GIT_CLONE
フラグを立てるfunction __hooks__set_git_clone_flag() { if [ 'git' = "$1" ] && [ 'clone' = "$2" ]; then echo "Setting __HOOKS__ON_GIT_CLONE=true in $filename" export __HOOKS__ON_GIT_CLONE=true fi }
post-checkout
内でフラグをチェックして処理するGist: post-checkoutとして置いておきました。
.gitvariables
というファイルを置いてgitアカウントの情報をロードするようにして、そのファイル自体は~/.gitignore
に登録してトラックしないようにしてあります。
- ここでフラグをチェックして、フラグが立ってなかったら
exit
してます。if [ -z "$__HOOKS__ON_GIT_CLONE" ]; then exit fi
- 処理の最後にフラグを倒します。
unset __HOOKS__ON_GIT_CLONE
GitHooks中でユーザの入力を待ちたいときの注意点
オフトピックですが注意点として、GitHooksは標準入力を利用しないので、処理の中で入力を待ちたい場合はターミナルからリダイレクションする必要があります。ちょっとハマりました。
read -rp 'Type anything you like:' < /dev/ttyまとめ
コードが散在することと、暗示的にフックすることでハマったりしないように、多用には注意が必要ではありますが、cdとgit上書きより汎用的かつ拡張しやすくなった感はあります。
ちなみに、Bashのコマンドの実行前後をフックする方法の解説はChuan Ji: DEBUG trap and PROMPT_COMMAND in Bashの記事がわかりやすいです。
参考
- 投稿日:2019-11-27T15:21:42+09:00
ローカルのタグを上書きする
$ git fetch -t -f or $ git fetch --tags --force
- 投稿日:2019-11-27T12:57:02+09:00
Technology Radar 2019のピックアップ
Technology Radarから気になったものをピックアップし、軽く説明を添えてみました。
社内で共有したところ、反響が良かったのでQiitaにも投稿します。(自分と似た技術スタックの方に刺さるのではないかと考えています)
ピックアップの観点
「自社の技術スタックとマッチしてるか」、「自分の技術スタックとマッチしているか」の観点からピックアップしています。
筆者は現在web系の企業のSREチームに所属しており、業務や趣味で触れる技術/言語としては下記のとおりです。
- Ruby on Rails
- Node.js / Vue.js / Nuxt.js
- AWS + Terraform
- Go/python/Firebase/GCP
一方で下記技術は興味が無い/専門じゃない等の理由でスルーしていますのでご注意ください。
- モバイルアプリ系
- ML系
- JVM系
Technology Radarとは
要は今年のイケてる技術の紹介です。
4段階で導入のおすすめ度合いが評価されているので、毎年重宝しています。TECHNOLOGY RADERとはThoughtWorks社が発表している技術トレンド分析の調査結果になります。 年1-2回発表しており、2016年は4月と11月に発表されました。
ユニークな点は、技術トレンドの分析を
Techniques(開発手法) / Tools(ツール) / Platforms (プラットフォーム) / Languages & Frameworks(言語とフレームワーク)
の4分野に分けているところです。
また、評価結果も ADOPT / TRIAL / ASSESS / HOLDの4つに分けているところです。ADOPT : プロジェクトにマッチするならば、採用を強くおすすめしている。
TRIAL : プロジェクトでリスクを管理できればやる価値はある。
ASSESS: どのような影響をあたえるか理解するために採用するときがある。(今後のために採用するときがある)
HOLD : 採用する場合は慎重に進める必要がある。引用元:https://allabout-tech.hatenablog.com/entry/2017/02/15/093000
気になった技術
それぞれの領域ごとに概要と所感を記載しています。
Techniques
Container security scanning (ADOPT)
もはやコンテナのセキュリティスキャンは必須の時代です。
CI/CDパイプライン内でスキャンを実施しましょう。所感:ECRのscan on pushやtrivyで簡単に実現できそうなのでやっていきたい。
Pipelines for infrastructure as code (ADOPT)
ソフトウェアのCI/CDパイプラインによるデプロイが主流になってきました。
Chef/Puppet/Ansible、Packer、Terraform等の登場により、インフラレイヤーもCI/CDを実現することが可能です。
インフラレイヤーもCI/CD化することで、実行元の一元管理や、実行前のエラー検知ができるようになるので、是非やりましょう。所感:Lint/validationやplan結果の表示もできるのでやりたい。stg/prdのapplyタイミングを踏まえて設計する必要があるのでちょっと大変かも。Dockerfileも現在はCIにかかってないので回すようにしたい。
security policy as code (TRIAL)
セキュリティポリシーをコード化し管理していきましょう。
Open Policy AgentやIstio等であれば、ポリシー定義と実施メカニズムを提供しています。所感:明文化してGit管理を開始したので、適用を強制したり検知する仕組みもあわせて実施していけるといい感じかも。
Tools
Commitizen (ADOPT)
http://commitizen.github.io/cz-cli/
対話形式でGitのコミットメッセージをサポートしてくれるツールです。
コミットの種類とか関連するIssueの有無とかbreaking changeの有無とか聞いてくれていい感じにメッセージを組み立ててくれます。
所感:個人のリポジトリはコミットメッセージ英語なので、これを導入することで良さげなリポジトリに見えるようになりそう。
jib (TRIAL)
https://github.com/GoogleContainerTools/jib
Java用のコンテナイメージ作成ツールです。
MavenやGradleに対応しており、DockerfileやDockerデーモンを必要とせずにイメージをビルドします。所感:使うことはまあ無いだろうけど、デーモン無しにイメージを作成できる技術は気になる。
Trivy (TRIAL)
https://github.com/aquasecurity/trivy
コンテナイメージのセキュリティスキャンツールです。所感:今ではかなり有名なやつ。使っていきたい。
Twistlock (TRIAL)
https://www.twistlock.com/
Twistlockは、コンテナ環境向けセキュリティ製品です。開発環境から実行環境まで、包括的なセキュリティを提供します。
NIST/CISベンチマークなど、業界のベストプラクティスに沿った対策が可能です。
所感:金額次第だが、セキュリティ要件厳しいサービスを運用する際にはいいかも。ただし、融通が利くかどうかは重要。
asdf-vm (ASSESS)
https://asdf-vm.com/#/
複数の言語のバージョンを管理できるコマンドラインツールです。
RVMやnvmのようにバージョンを管理できますが、複数の言語をこのツール1つで管理できるのが特徴です。所感:ruby以外もバージョン固定して利用するプロジェクトでは良さそう。個人の環境は全部これに乗せ替えたい。
AWSume (ASSESS)
https://github.com/trek10inc/awsume
AssumeRoleをいい感じにやってくれるCLIツール
所感:社内のエンジニアには基本的にassum roleして利用するIAMユーザーを配ってるので、これを標準の手順にしてみてもよさそう。(現在、MFAを利用していることもあり、AssumeRoleするユーザーでawscliを使う手順がやや面倒)
Pumba (ASSESS)
https://github.com/alexei-led/pumba
PumbaはDockerのためのchaos testingとネットワークエミュレーションのツールです。
ネットワークをエミュレートし、遅延、パケット損失、帯域幅レート制限などのさまざまなネットワーク障害をシミュレートすることもできます。所感:chaos testingはやったこと無いので挑戦してみたい。
Platforms
Crux (ASSESS)
https://opencrux.com/
bitemporal graph queryを備えたドキュメントデータベースです。
bitemporalとは、履歴を持ったデータのこと不変のトランザクションレコードも保持しながら、ビジネスの真の履歴を記録します。これがバイテンポラリティの本質です。開発者およびアプリケーションユーザーとして、時間をかけて効率的にクエリを実行する機能のロックを解除します。 Cruxを使用すると、遡及修正を作成し、履歴データの移行を簡素化し、異常なイベントデータの統合ビューを構築できます。
所感:特許で見たことあるような。履歴を持ち、かつそれを遡及して修正するシステムは本当に辛いので、これがマッチするなら使うのが良さそう。
Hydra (ASSESS)
https://www.ory.sh/hydra/
OAuth2、OpenID connect providerを簡単にホストすることができるOSSです。所感:micro serviceをk8s上で構築する際に使えそう。認証系の自前メンテは辛いので、こういうものを活用していきたい。
Teleport (ASSESS)
https://gravitational.com/teleport/
『Gravitational Teleportは、SSHまたはKubernetes API経由でLinuxサーバーのクラスタへのアクセスを管理するためのゲートウェイです。従来のOpenSSHの代わりに使用することを目的としています。』
所感:中規模以上のk8sを利用している場合に効果を発揮しそう。自前でteleportのクラスタを構築し、ライセンスも必要なプロダクトなので、導入するのはけっこうな大事。GitHubや任意のSSO連携可能なサービスのアカウントで、ロールに基づいたsshができるのはまさに我々が求めていたものである。
Languages & Frameforks
jest-when (TRIAL)
https://www.npmjs.com/package/jest-when
when(fn).calledWith(args).thenReturn(value)
のような感じでモック関数の引数に対するレスポンスを定義できるプラグインです。所感:地味に便利で記述量を少なくできるので良さそう。
NestJS (ASSESS)
https://nestjs.com/
TypeScript製のserver side Node.jsフレームワークです。
GraphQL、Websocket、ORMライブラリなどのプロトコルをサポートしています。参考記事:Nest.jsは素晴らしい
所感:発想はRailsに近いように思える(レールに乗ることでスタイルが統一され楽に開発できる等)。expressとの2択になりそう。
Paged.js
https://www.pagedmedia.org/paged-js/
HTMLで書籍等の印刷物を作る場合に必要なページカウンターやヘッダー、フッター等を描画できるポリフィルとCSSモジュールを生成してくれるライブラリです。所感:本を作る機会があれば使ってみたいかも。前職であれば仕様書は謎に文書形式である必要があったので、Markdownで書いた場合でもヘッダーやフッターを頑張ってつけてたから、それにも使えそう。
まとめ
個人的に気になった技術をいくつかピックアップして紹介してみました。
よくあるツール紹介でごめんなさい。
でも、元が英語だから許してね。
- 投稿日:2019-11-27T12:28:29+09:00
【Git】特定のファイルをGit管理したいときの手順(~/.vimrc, ~/.zshrcをバックアップ)
はじめに
これまでディレクトリ全体、
git add .
とかgit add -A
ばかり使用していたので、調べました。特定のファイルだけをGit管理するときの手順をまとめています。
今回は以下2点のファイルを管理したい場合を例にしています。
~/.vimrc
vimの設定ファイル~/.zshrc
zshの設定ファイルこの記事が役に立つ方
- 特定のファイルをGit管理したい方
この記事のメリット
- 特定のファイルだけをGit管理する方法が分かる
環境
- macOS Catalina 10.15.1
- zsh: 5.7.1
【準備】
GitHubなどでリモートリポジトリを事前に作成しておく。
※今回自分で管理したかったのは設定ファイルなので、リモートリポジトリはpublicでなく、privateにしておきました。
【手順】
1.
init
cd該当ファイルのある場所(今回はホームディレクトリ)に移動。
git initGit管理するためにローカルリポジトリを作成。
2.
add
git add .vimrc .zshrc半角スペース区切りで複数ファイルを一度に
add
可能。ファイル名に共通項があるのであれば、以下のようなコマンドでも問題なし。
git add .*rc
*
がワイルドカードなので、隠しファイルで末尾がrcで終わるファイルが全て対象になる。git add -n .*rc
-n
オプションをつけると、どのファイルがadd
されるかを確認することが可能。(実際はadd
されない)
3.
commit
git commit -m "first_commit"適当なコミットメッセージをつけてローカルリポジトリに保存。
4.
push
まずリモートリポジトリの設定をします。
git remote add リポジトリ名 リモートリポジトリURL
- リポジトリ名:任意で設定。
- リモートリポジトリURL:GitHubなどで事前に作成しておいたものを使用。URLをコピペする。
git push essentials masterこれで
push
して完了です。大事なファイルなのでリモートリポジトリ名は"essentials"としました。
5. 確認
git ls-files現在Git管理されているファイル一覧が出る。
ちゃんと管理したかったファイル名が表示されていればOK。
6. 次回からの
add
git add -u
2回目からは
add
はこのコマンドで対応可能。
-u
オプションをつけるとGit管理されているファイルのみを対象としてadd
してくれる。おわりに
最後まで読んで頂きありがとうございました
エディタはvim、シェルはzshを愛用していて、この2つの設定ファイルが一度消えて超ショックだったので、バージョン管理することにしました。
出来れば上書き保存したら勝手に
git add
→git push
されるように自動化していきたい。Guardとシェルスクリプトとか活用すれば出来そうな感覚はあるんですが...また挑戦します。
もし実際に自動化してるよ!という方がいれば教えて頂きたいです
- 投稿日:2019-11-27T11:12:21+09:00
git リポジトリを構造を保ったまま分割する
リポジトリの一部だけを残したい
あるリポジトリを構造を保ったまま別リポジトリとして独立させたいと考えた。そんなことはよくある作業だと思ったが、ぴったりな記事がなかったので書いておく。
やりたいのは greple というコマンドの標準モジュールのひとつ (subst) を、外部モジュールとして独立させることだ。なぜ、そうしたかったかというと、依存する特有のモジュールが増えて、それを本体の依存関係に入れたくなかったからだ。
ちなみに、App::Greple::subst は原稿の校正用モジュールで、用語統一のために使っている。以前から使っていたものだが、今回はこれを大幅に改造して使いやすくした。詳細についてはまた改めて。
というわけなので、リポジトリのディレクトリ構造はそのままにして、こういう構造から:
. ├── Build.PL ├── Changes ├── Example.md ├── LICENSE ├── MANIFEST ├── MANIFEST.SKIP ├── META.json ├── README.md ├── cpanfile ├── lib/ │ └── App/ │ ├── Greple/ │ │ ├── Common.pm │ │ ├── Filter.pm │ │ ├── Grep.pm │ │ ├── Pattern/ │ │ │ └── Holder.pm │ │ ├── Pattern.pm │ │ ├── PgpDecryptor.pm │ │ ├── Regions.pm │ │ ├── Util.pm │ │ ├── colors.pm │ │ ├── debug.pm │ │ ├── dig.pm │ │ ├── find.pm │ │ ├── line.pm │ │ ├── perl.pm │ │ ├── pgp.pm │ │ └── subst.pm │ └── Greple.pm ├── script/ │ └── greple* ...特定のファイルを切り出したいだけだ:
. └── lib/ └── App/ └── Greple/ └── subst.pmメタファイルは新しく作るので必要ないが、ヒストリーは維持したい。その必要がなければ、単に新しいリポジトリを作ってコピーすればいいだけだ。
新しいブランチを作る
とりあえず、元のリポジトリで作業用の新しいブランチを作る。まず clone する例が多いような気がするが、使いもしないデータをわざわざコピーする必要もなかろう。
また、後になって今回の作業を何度か再現してみたが、そのためには元のリポジトリに作業用ブランチが残っていた方が何かと便利だった。
git checkout -b subst
filter-branch --subdirectory-filter は使えない
とりあえず、リポジトリを書き換えるには
filter-branch
コマンドを使うのが王道であることには間違いなさそうだ。よく出てくるのが
filter-branch --subdirectory-filter
を使う方法だ。リポジトリのディレクトリの一部を独立したリポジトリにしたいことはよくあるのだろう。しかし、先に書いたように、今回は全体の構造を保ったまま分割したいので、これは使えない。filter-branch --tree-filter を使う
--subdirectory-filter
が適さない場合には、--tree-filter
を使う方法が紹介されていることが多い。大概、間違って登録してしまったファイルを歴史から抹殺するというような使い方だ。これはかなり乱暴なコマンドで、コミットヒストリーを一つ一つファイルシステム上に展開して、そこで指定したコマンドを実行した結果を再度登録していくというものだ。今回の場合、
subst.pm
というファイル以外をすべて削除すればいいのでfind
コマンドを使って、それ以外のファイルをすべて削除する。--prune-empty
というオプションは、空のコミットをなかったことにするものだ。git filter-branch -f --prune-empty --tree-filter 'find . -not -name subst.pm -delete'コミットヒストリが500近くあると、実行に4分半かかった。
real 4m25.242s user 2m8.542s sys 1m12.992sfilter-branch --index-filter を使う
ファイルの内容を書き換えるような修正をしたい場合には
--tree-filter
が必要だが、今回の場合はファイルを消したいだけなので、ファイルそのものにアクセスできる必要はない。その場合には--index-filter
というオプションが使えることがわかった。これはステージングされたインデックスを操作するので、ファイルを消去するためには
git rm --cached
コマンドを使用する。git ls-files
で取得したリストからsubst.pm
を除いてすべて削除する。git filter-branch --prune-empty -f --index-filter 'git rm --cached -f `git ls-files | sed "/subst.pm/d"`' HEADこうすることで、先の
--tree-filter
と同じ結果が得られる。ファイルを展開しないので、1分強で実行は終わった。ファイル名に空白が含まれている場合には、このままではうまく行かないかもしれないのでご注意を。real 1m8.790s user 0m25.648s sys 0m29.289s--index-filter が一番なのか?
ここまでの結果では
filter-branch --index-filter
を使うのが一番よさそうだ。しかし、できれば残したいファイルを指定できた方が理にかなっているし、git mv
した場合にはそれを辿ってくれた方が嬉しい。もっといい方法があったら教えてください。新しいリポジトリを初期化する
ここからは、使う環境によって違う話だ。今回は Perl のリポジトリを Minilla で初期化する。
minil new App::Greple::substこうすると新しい git リポジトリを作って commit する前の状態で止まる。
lib
以下は必要ないので reset して消去してしまおう。cd App-Greple-subst/ git reset lib rm -fr libこの状態で commit してもいいのだが、このままにして次に進む。
気持ち悪ければ、全体を reset してしまって、後で add しても構わない。元のリポジトリを merge する
今回は、隣のディレクトリに元のリポジトリがあるので、そこを remote に指定する。
git remote add greple ../greple/そして、ブランチを指定して fetch すると最小限のデータだけを持ってくるので、それを merge する。
git fetch greple subst git merge greple/substこれで過去のヒストリがコピーされた。この時点で Minilla で作成したファイルを commit してあげると、きれいなヒストリができる。
git commit -m 'minil new App::Greple::subst'先にコミットしてしまうと merge に失敗する。その場合は
--allow-unrelated-histories
を指定する。終わったら remote を削除して縁を切る。
git remote remove grepleまとめ
- git リポジトリの一部ファイルだけを残したい場合には、それ以外のファイルを削除するしか方法はなさそう。
- 本当か?
- コミットヒストリを修正するには
git filter-branch
を使用する。- ファイルの内容にアクセスする必要がなければ
--tree-filter
よりも--index-filter
オプションを使用した方が高速。- 特定ファイル以外を削除するには
git ls-files
の結果を加工する。
- 若干苦し紛れ感あるので、もっといい方法が望まれる。
- 対象ファイルを減らすと何も変更しないコミットができるので、それを削除するためには
--prune-empty
を使用する。
- 投稿日:2019-11-27T10:45:49+09:00
【Mac】Gitコマンドが使えるまでの準備
Gitインストール方法
下記のどちらかの方法でインストール可能。
・公式サイトからダウンロード→インストール
・homebrewを使用してインストール公式サイトからダウンロード→インストール
①公式サイトよりダウンロードをクリック。
②インストーラを実行。
③以下のコマンドで、インストールを確認。※バージョンが表示されればOK
$ git --versionhomebrewを使用してインストール
①インストール
$ brew install git②(必要に応じて)Gitアップデート
$ brew upgrade git