20191127のGitに関する記事は8件です。

Git Hooksでgit cloneだけをフックする(共通テンプレートだけでは不十分なケース)

やりたいこと

言わば、post-cloneフックです。git clone実行後だけリポジトリディレクトリに対して特定の処理がしたい。その際、clone先ディレクトリに応じて処理を分岐させたい。つまり、共通テンプレートを設定しておくだけでは不十分。

結論

  • trap DEBUGgit cloneを叩いたことを検知して、コマンド実行前にフラグを立てる。
  • post-checkoutスクリプト内でフラグが立っているときだけ処理を行い、処理後フラグを倒す。
  • 今回の記事の本筋ではないが、注意点として、GitHooksは標準入力を利用しないので、処理の中で入力を待ちたい場合はターミナルからリダイレクションする必要あり。

背景

前の記事で、gitアカウントを自動で切り替えるためにgit clone前に処理をする必要があったので、cdgitのラッパー関数を作り、エイリアスで元のcdgitを上書きして、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:   18F132

Git

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の記事がわかりやすいです。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Git Hooksのpost-checkoutでgit cloneだけをフックする

やりたいこと

git clone実行後だけリポジトリディレクトリに対して特定の処理がしたい。

TLDR

  • trap DEBUGgit cloneを叩いたことを検知して、コマンド実行前にフラグを立てる。
  • post-checkoutスクリプト内でフラグをチェックして分岐させる。
  • 今回の記事の本筋ではないが、注意点として、GitHooksは標準入力を利用しないので、処理の中で入力を待ちたい場合はターミナルからリダイレクションする必要あり。

背景

前の記事で、gitアカウントを自動で切り替えるためにgit clone前に処理をする必要があったので、cdgitのラッパー関数を作り、エイリアスで元のcdgitを上書きしました。他のライブラリを利用していて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:   18F132

Git

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の記事がわかりやすいです。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Git Hooksでgit cloneだけをフックする

やりたいこと

言わば、post-cloneフックです。git clone実行後だけリポジトリディレクトリに対して特定の処理がしたい。その際、clone先ディレクトリに応じて処理を分岐させたい。つまり、共通テンプレートを設定しておくだけではうまくいかない。

結論

  • trap DEBUGgit cloneを叩いたことを検知して、コマンド実行前にフラグを立てる。
  • post-checkoutスクリプト内でフラグが立っているときだけ処理を行い、処理後フラグを倒す。
  • 今回の記事の本筋ではないが、注意点として、GitHooksは標準入力を利用しないので、処理の中で入力を待ちたい場合はターミナルからリダイレクションする必要あり。

背景

前の記事で、gitアカウントを自動で切り替えるためにgit clone前に処理をする必要があったので、cdgitのラッパー関数を作り、エイリアスで元のcdgitを上書きして、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:   18F132

Git

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の記事がわかりやすいです。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ローカルのタグを上書きする

$ git fetch -t -f
or
$ git fetch --tags --force
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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 AgentIstio等であれば、ポリシー定義と実施メカニズムを提供しています。

所感:明文化してGit管理を開始したので、適用を強制したり検知する仕組みもあわせて実施していけるといい感じかも。

Tools

Commitizen (ADOPT)

http://commitizen.github.io/cz-cli/
対話形式でGitのコミットメッセージをサポートしてくれるツールです。
コミットの種類とか関連するIssueの有無とかbreaking changeの有無とか聞いてくれていい感じにメッセージを組み立ててくれます。
commitizen

所感:個人のリポジトリはコミットメッセージ英語なので、これを導入することで良さげなリポジトリに見えるようになりそう。

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ベンチマークなど、業界のベストプラクティスに沿った対策が可能です。
twistlock

所感:金額次第だが、セキュリティ要件厳しいサービスを運用する際にはいいかも。ただし、融通が利くかどうかは重要。

asdf-vm (ASSESS)

https://asdf-vm.com/#/
複数の言語のバージョンを管理できるコマンドラインツールです。
RVMやnvmのようにバージョンを管理できますが、複数の言語をこのツール1つで管理できるのが特徴です。

所感:ruby以外もバージョン固定して利用するプロジェクトでは良さそう。個人の環境は全部これに乗せ替えたい。

AWSume (ASSESS)

https://github.com/trek10inc/awsume
AssumeRoleをいい感じにやってくれるCLIツール
AWSume

所感:社内のエンジニアには基本的に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で書いた場合でもヘッダーやフッターを頑張ってつけてたから、それにも使えそう。

まとめ

個人的に気になった技術をいくつかピックアップして紹介してみました。

よくあるツール紹介でごめんなさい。
でも、元が英語だから許してね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【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 init

Git管理するためにローカルリポジトリを作成。


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してくれる。

おわりに

最後まで読んで頂きありがとうございました:bow_tone1:

エディタはvim、シェルはzshを愛用していて、この2つの設定ファイルが一度消えて超ショックだったので、バージョン管理することにしました。

出来れば上書き保存したら勝手にgit addgit pushされるように自動化していきたい。

Guardとシェルスクリプトとか活用すれば出来そうな感覚はあるんですが...また挑戦します。

もし実際に自動化してるよ!という方がいれば教えて頂きたいです:relaxed:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.992s

filter-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 を使用する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Mac】Gitコマンドが使えるまでの準備

Gitインストール方法

下記のどちらかの方法でインストール可能。
・公式サイトからダウンロード→インストール
・homebrewを使用してインストール

公式サイトからダウンロード→インストール

公式サイトよりダウンロードをクリック。

②インストーラを実行。

③以下のコマンドで、インストールを確認。※バージョンが表示されればOK

$ git --version

homebrewを使用してインストール

①インストール

$ brew install git

②(必要に応じて)Gitアップデート

$ brew upgrade git
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む