Git初心者が最初に知るべきチームでGitの使い方
皆さんはGitを問題なく使えているでしょうか?
時おり社内で「リポジトリが何だかおかしくなってるんです~」と相談を受けることがあります。 コミットログが思ってたのと違う状態になっていて、さらに元に戻そうとアレコレやって状況悪化。 最終的に、どうにもならなくなっちゃったって感じです。
たいていは単純にGitの操作ミスによるものです。でもGitについて正確に理解していれば、ちょっとした間違いはすぐに元に戻せるはず。 裏返せば、Gitの仕組みや概念を正確に理解できておらず、「なんとなく」Gitを使っている人が多いのでしょう。 Gitのコミットやブランチについて明確なイメージを頭の中に描けていないように思います。
ところがこの春、新型コロナの影響で、弊社も「基本的にはテレワーク」と指示が出まして不安が的中。既にちらほら問題が発生してます。
ということで「Gitが不安、難しい」と思っている人たちのために、最初にキチンと理解しておいて欲しいことや、基本的な使い方を書いておきます。 ちなみに、Gitを難なく使っている人にとっては当たり前のことしか書いていません。
- masterブランチで作業しないで
- いろんな変更を詰め込まないで
- masterブランチをpushしないで
- 他人のワーキングブランチにコミットしない
- rebaseしないでmergeして
- プルリクのマージを急かさないで
- 勝手に安易にリファクタリングしないで
masterブランチで作業しないで
いちいち「この作業はブランチを切って行えばよいですか?」って聞いてくる人がいますが、これ当たり前なんですよね。 なにか作業するにはワーキングブランチを作成して、そのブランチで行ってください。
ワーキングブランチのベースをどこにするかは、採用しているフローに依存します。 弊社では GitHub Flow でやりましょうとなっているのでベースは必ず master です。 この点についてはチーム内で取り決めがあるはずですし、なければ取り決めておくべきですね。
GitHub Flowでは、作業内容を具体的に表す名前をワーキングブランチに付けるべきだとなっています。 そして早い段階で(コードを変更していなくても)リモートにpushしておきます。 これによって、チーム内に「自分が何をしようとしているかを知らせる」ためです。
いろんな変更を詰め込まないで
たくさんのコードを変更して、一発巨大なコミットをぶちかますのはやめてください。 また、ひとつのワーキングブランチで、色んな種類のコミットを積み重ねるのもやめてほしい。ワーキングブランチの変更内容は首尾一貫している必要があります。
その時の作業に無関係な部分で「あら、ここのインデントおかしいやん」とたまたま発見しても、そのまま流れで修正しないでほしいのです。 これをやると、後のmergeやrebaseでCONFLICTが発生しやすくなって、割ととんでもない手間がかかります。 本筋から外れた問題を見つけたときは、忘れないようにIssueを書いて、本来の作業に戻りましょう。
これらを正しく行うには、キチンと作業の計画を立て、短期のゴールを見定めて、それに集中する必要がありますよ。
masterブランチをpushしないで
複数人のチームで開発しているとき、masterブランチを前に進めるのはプルリクだけに限定したい。 緊急のBugFixなどでは、この限りではありませんが、少しでも時間的に余裕があるならプルリク投げてマージしたい。
主な理由はレビューできないからですが、チーム内に「masterが前に進む」ということを周知できるのも理由のひとつ。
同じ場所で作業している場合に、声を掛け合ってワーキングブランチをローカルでmasterにマージして、pushするケースは確かにあります。プロジェクトの初期段階では特に。 でも、リモートワークでメンバーがバラバラな状況で、さらにGitの操作に慣れていない人がいる場合などでは、正統にプルリクを投げてレビューしてからマージするのが筋というものです。
複数のコミットが連なったブランチを直接(プルリクを投げないで)レビューする時、レビュアーはレビュー対象のブランチを手元にチェックアウトしてHEADとベースブランチの差分を確認する必要があります。 GitHubなどのサービスでは複数コミットの差分をまとめて確認しにくいので。
他人のワーキングブランチにコミットしない
他の人のワーキングブランチをチェックアウトするのは構いません。コードを確認したりするだけですから。 でも、そのブランチに変更を加えてコミットした上で、push しないで欲しいのですよ。
これって論外だと思うのですが、おそらくワーキングブランチとは何であるかを理解できていないのでしょうね。
ワーキングブランチは、それを作った人の責任においてコーディング作業が進んでいるものであって、途中から無言で他の人が別の変更を加えちゃうと、その時点で枝分かれしてしまいますよね。 ブランチのオーナーは最終的に複数のコミットをまとめようとしているかもしれませんし。 とにかくワーキングブランチは途中段階の中途半端な状態なので、本人から移譲されたのでない限り、勝手に変更を加えるようなものではありません。
他の人のワーキングブランチが自分にとって必要であるならば、きりの良いところでプルリクを投げてもらってmasterへマージしてもらうように依頼するべきです。 そして、そのプルリクがマージされたあとに、自分のワーキングブランチへマージするべきです。いずれにせよ無言でしれっとやるのはご法度です。
ワーキングブランチを早い段階でリモートにpushしておくのは「私はこういう作業をしていますよ」ということをチーム内に表明するためです。
今まで未遂も含めて何度か経験しています。 一度はそのブランチがmasterにマージされていて驚きました。 怖いよ初心者w。まあその後問題が出なかったので良かったけれど。
rebaseしないでmergeして
ワーキングブランチで作業中に、リモートのmasterが前に進んでいることがあります。 このとき自分の作業が終わってプルリク投げる時などに、新しいmasterにrebaseする(ワーキングブランチのベースブランチを新しいmasterに切り替える)のはやめて欲しいのです。
じゃあどうするか。その時点でコンフリクトが発生する可能性があったり、新しいmasterに加えられた変更が自分の作業に必要であったりするなら、新しいmasterをワーキングブランチへmergeすれば良いのです。 逆に、明らかにコンフリクトが発生しない場合や、自分の作業に無関係な変更であるなら、何もしなくても構いません。
コンフリクトが発生するかどうかの判断は、少し難しいかもしれません。 なので同じファイルを変更しているかどうかで判断すれば良いと思います。 同じファイルを変更しているなら良いタイミングで新しいmasterをワーキングブランチにmergeする。 そうでないなら何もしなくてOKです。
rebaseをやめて欲しい理由のひとつは「際限がない」からです。 複数人で開発している場合、作業中にどんどんリモートのmasterは進んでいくと思います。 その時に、いちいちrebaseするのは手間ですし、コンフリクトが発生しそうなときだけrebaseするという対応も、状況によってベースブランチが変わるなんて、おかしな話です。
ちなみにmasterとの間でコンフリクトが発生したら、その解消時に尊重されるべきなのはmasterブランチのコードです。 masterブランチに取り込まれた時点で、それは「みんなが認めた正統なコード」ですからね。
プルリクのマージを急かさないで
プルリク投げてマージを急かす人がいますけど、あれも困ります。
あとの作業にそのブランチがマージされる必要があると懇願されたことがあるのですが、それってプルリク投げるタイミングでないかもしれません。 切りの良いところで、一旦プルリクを投げておきたいのであれば、その後も同じブランチで作業すればよいのです。 そのブランチでの作業はまだ終わっていないということですから。
勝手に安易にリファクタリングしないで
全体の構成を変更したり、命名規則を修正したりするリファクタリングに類することは広範囲に影響を及ぼしますから安易にこっそりやるべきではありません。 チーム内に注意を促してタイミングを見計らう必要があります。
また個々のコミットの変更内容を、極力あとでリファクタリングする必要がないように気をつけるのも必要です。
React:非同期の副作用フック(useEffect)で正しくクリーンアップする
Reactの関数コンポーネントで非同期の副作用フックを正しく記述する方法を書いています。
非同期処理でコンポーネントを更新する場合には、副作用フックを使用する必要があり、この副作用フックからはクリーンアップ関数を返却しておく必要があります。 REST APIなどの非同期処理によってデータを取得し画面に反映する場合などには、非同期の結果待ちの間に更新先の画面がなくなっている(DOMがアンマウントされる)かも知れないためで、それに対処しなければなりません。
副作用フックに対して、更新先の画面がなくなったことを伝えるための関数がクリーンアップ関数で、このクリーンアップ関数は副作用フックが返却する関数オブジェクトです。 (なんだか話が前後しているようでややこしいですが、この動作機序を理解するには、JavaScriptの非同期処理の動作、関数オブジェクト、そしてクロージャについての知識が必要かと思います)
副作用フックについて
副作用フックは、関数コンポーネントの中で利用できるフックです。 DOMがマウントされて画面が更新されたあとに呼ばれる関数を登録します。
この関数内で、何らかの条件によって、コンポーネントのステートを更新すれば、再び画面が更新されるという仕組みです。
画面が更新されると、また同じ副作用フックを登録することになりますから、無限に更新を繰り返すことは避ける必要がありますね。
非同期動作する副作用フック
この関数内で、例えばREST APIを呼び出して、非同期でデータを取得してステートを更新すると、再び画面を更新することになるのですが、既にユーザー操作によって別の画面に遷移していると、更新すべきコンポーネントがなくなっているかもしれません。
アンマウントされたDOMに対してステートを更新すると「メモリリークしてるかも!」という警告が表示されます。
つまり、DOMがアンマウントされているときにはステート更新を行わないようにするべきなのです。
クリーンアップ関数でDOMのアンマウントを知る
そこでDOMがアンマウントされたことを知るために、副作用フックの「クリーンアップ関数」を使用します。 クリーンアップ関数は副作用フックが返す関数です。この関数は副作用フックが呼び出されたあと、DOMがアンマウントされた時に呼び出されます。
実行順序をざっくり書けば、
- 画面がマウントされ、
- 副作用フックが呼ばれ、
- 副作用フックがクリーンアップ関数を返し、
- DOMがアンマウントされたときに呼び出される
ということになります。
つまり、非同期動作を待っている(await中の)副作用フックに対して、既に返したクリーンアップ関数にDOMのアンマウントが通知されるということです。 非同期動作が完結したとき、既にクリーンアップ関数が呼ばれていたならDOMがアンマウントされているのでステート更新を行わなければよいのです。
正しくない非同期関数コンポーネント
副作用フックを使わない(動くけど正しくない)
一方、非同期でのステート更新は副作用フックでなくても一応動きます。 以下は副作用フックを使っていない不完全な非同期関数コンポーネントなんですが、一見正常動作は可能です。 しかし、既に上に書いたように、非同期処理が完了するまでの間にユーザー操作によって別の画面に遷移したとすると「メモリリークの可能性がある」という警告が出ます。
import React from "react"; export default function AsyncComponent() { //非同期で取得するデータ const [result, setResult] = React.useState(null); //非同期無名関数の即時呼び出し (async ()=> { //非同期でデータを取得し、ステート更新 const result = await getAsyncData();//架空の関数 setResult(result); })(); return ( <div> { result ? <p> { result } </p> : <p> loading... </p> } </div> ); };
関数コンポーネント自体をAsyncにしちゃう(動かない)
どこにも書いていなかったようなので、念の為に試してみたのですが、 関数コンポーネント自体をAsync関数にした場合、ビルド時エラーは出ませんが、まったく動きませんでした。
import React from "react"; export default async function AsyncComponent() { const [result, setResult] = React.useState(null); setResult(await getDataAsync()); return ( <div style={{textAlign: "left"}}> { markdown ? <article dangerouslySetInnerHTML={{__html: markdown}}/>: <p>loading...</p> } </div> ); };
副作用フックをAsyncにしちゃう(できない)
Async関数は必ずPromise オブジェクトが返します。 しかし先に書いたように、副作用フックはクリーンアップ関数を返さなくてはなりません。 だから副作用フックの関数自体をAsync関数にはできません。
正しい非同期副作用フックとクリーンアップ関数
コンポーネントがアンマウントされたかどうかを知るために副作用フックを使います。 副作用フックの戻り値は「クリーンアップ関数」と呼ばれる関数オブジェクトで、後にコンポーネントがアンマウントされたとき呼び出してもらえます。
以下のコードで示すように( React.useEffect
の部分)。
import React from "react"; //非同期関数コンポーネント export default function AsyncComponent() { //非同期で取得するデータ const [result, setResult] = React.useState(null); // 副作用フック React.useEffect(()=>{ let unmounted = false; //非同期無名関数の即時呼び出し (async()=>{ //非同期でデータを取得 const result = await getAsyncData();//架空の関数 //アンマウントされていなければステートを更新 if(!unmounted) { setResult(result); }; })(); //クリーンアップ関数を返す return ()=>{ unmounted = true; }; }); return ( <div> { result ? <p> { result } </p> : <p> loading... </p> } </div> ); };
副作用フックの最初で unmounted
という変数を初期値falseで宣言しています。
これは非同期処理中にコンポーネントがアンマウントされたかどうかを保持します。
最初の時点ではアンマウントされていません。
次に、関数の内部で無名のAsync関数を即時呼び出ししています。 この関数の中で非同期にデータを取得したあと、アンマウントされていなければステートを更新しています。
最初に宣言された unmounted
は、この副作用フックが返す「クリーンアップ関数」で true に更新されています。
つまり非同期処理が完了する前にコンポーネントがアンマウントされると、ステートは更新されませんから、メモリリークの心配はありません。
VS-Codeで「NPMスクリプトが見つかりません」の対処法
シーアンドアール研究所 (2019-09-27)
売り上げランキング: 22,236
テキストエディタはVim/GVimを使い続けてきましたが、ここ半年ほどで完全に Visual Studio Code へ移行しました(ただしVimの拡張機能は使っています)。
移行理由はNPMスクリプトをワンクリックで実行できる機能がとても楽なんですよねえ。
コードの編集中はたいていテストをwatchモードで走らせっぱなしです。
ところが「スクリプトが見つかりません」
ところが、ある時からサイドバーのnpmスクリプト一覧に「スクリプトが見つかりません」と表示され、まったく使えなくなってしまいました。
何かのスクリプト実行時に「なんだか動作が遅いから、なにかの設定をOffにする?」と、VsCodeがメッセージボックスを表示してきました。 信頼するVsCodeさんが言うことなので「それならば…」とAcceptだかYesだかOKだかのボタンを押してしまったんですね。うかつでした。
で、その時以来 サイドバーの NPM SCRIPTS に「スクリプトが見つかりません」と表示されて実行できなくなりました。 さらにそのOFFにした設定項目がなんだったのか忘れてしまって戻せない・・・。
設定項目「タスク自動検出」のせいでした
この現象を検索しても復旧方法がわかりません。こういう状況に陥っているのは自分だけなのかとチョット孤独。 ほぼ同じ機能の拡張機能があるので、仕方なくそれを利用していましたが、少々使い勝手が違っていて、少し不便なんですよねえ。 そう思いながら半年ぐらい使い続けていたのですが、先日、設定項目を眺めていると「これ?」というのを見つけました。
それが「タスク自動検出(Task: Auto Detect)」でした。初期値はONらしいのですが、これがOFFになっていました。 基本的な設定はよっぽどでないと初期設定から書き換えないで使うので発見できた。
ということで「タスク自動検出(Task: Auto Detect)」をONにしてみると、見事解決しました。
「タスク自動検出(Task: Auto Detect)」の設定方法
メインメニューから [File]-[Preferences]-[Settings] と辿って、設定項目の検索ボックス([Settings]の[Search settings])に「task auto detect」などと入力すると「Task: Auto Detect」が表示されます。
これを on に変えて、NPMスクリプト一覧の更新ボタンをクリックすると、 問題なくnpm scripts を見つけてくれるようになりました。
おめでたい。
あとがき
メッセージボックスによる通知や提案って、ありがたくて便利なのですけど、慎重に内容を検討しないと、あとからそれが何だったのかわからなくなりますね。
VsCodeはとても便利ですが、いろんな局面で不意にポップアップが表示されて少しおせっかいだと感じることがあります。 そのおせっかいが標準なのか拡張機能のせいなのか?とか、どこかの設定でどうにかなるの?というのもわかりにくい。
まあ、愚痴っていても仕方がないから、時間のある時に設定項目などをじっくり眺めてみるのが良いのかもしれないですね。
これってなにが悪いんだろうね。よくわからないままOFFにしちゃった自分も悪いのは確かなんだけど、UI的に問題ありそうにも思ってる。
npm scripts で eslint-watch を実行するには npx が必要だった
コードの編集中にeslint のチェック機能を継続的に実行してくれる eslint-watch というパッケージを見つけたので、早速 npm scripts から使ってみようとしたのだが、なぜか「そんなコマンドありません」ってエラーになった。
PowerShellの出力は:
PS C:\Users\????\Git\list-it> npm run lint-watch > list-it@1.0.6 lint-watch C:\Users\????\Git\list-it > eslint-watch --watch 'eslint-watch' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。 npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! list-it@1.0.6 lint-watch: `eslint-watch --watch` npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the list-it@1.0.6 lint-watch script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\????\AppData\Roaming\npm-cache\_logs\2020-02-06T21_11_23_927Z-debug.log PS C:\Users\????\Git\list-it> npm run lint-watch > list-it@1.0.6 lint-watch C:\Users\????\Git\list-it > npx eslint-watch --watch ✓ Clean (6:13:00)
Windowsでやっていますが、Linuxでも呼び出せません。VS-CodeのBashからでも同じでした。
ところが、ターミナルから npx を使うと問題なく動きます。 本来 package.json ではあえて npx と書かなくても動くはずだがなにやってんだろ?
と、いくら調べても情報がなく埒が明かない。
はたと気が付き、妙な対策だと思いながら、npm scripts で npx を使うように書き直したら、あっさり動いた。
package.json:
・・・ "scripts": { "lint": "eslint .", "lint-watch": "npx eslint-watch --watch", "mocha-watch": "mocha -- --watch", "test": "eslint . && mocha" }, ・・・
何が悪さをしているのか一切不明。 本質的には解決していないのだけど、とりあえずOK。 しかし、こういうことがあるんだなあ。
新EdgeでIEモードを使うため「Microsoft Edge ポリシー設定を構成する」
前の記事でChromiumベースの新Microsoft Edgeをインストールして、IEモードを使うための設定手順を書いていますが、自宅PC(Windows 10 Home 64bit)ではうまくいきませんでした。
Edge自体の設定や起動オプションの指定などすべては順調でしたが、最終的に「IEモード」でウェブページを開こうとすると、エラーページが表示(500番台だったかな)されていました。
以下のマイクロソフトのウェブページを詳しく読むと、Edge自体の設定の他に「Microsoft Edge ポリシー設定を構成する」必要があるとわかりました。 会社貸与のPCで問題が出なかったのはアクティブディレクトリのドメインに参加しており、既にドメインでグループポリシーが構成されていたのでしょう。
ドメインに参加していない自宅PCではローカルグループポリシーでの設定が必要なのですが、そのためにはローカルグループポリシーエディタ(以下の説明ではgpeditと記述します)を使えるようにする必要もありました。
すったもんだで最終的に、自宅PCでもキチンと新EdgeでIEモードが使えるようになりました。 ただ、上記マイクロソフトのウェブページなんですが、よくわからない言葉がイキナリ出てきて頭を抱えて別のページと行ったり来たり。 そもそも英語で説明されているので目の前の画面とは表示内容が若干違っていて、とってもややこしかったので、以下に手順を書いておきます。
※ あくまでも自分の自宅PCでの話なので、状況が違うと合致しないこともあるかと思いますが、まあその辺はご容赦を。
前回記事の「新EdgeのインストールとIEモードの設定手順」はコチラです↓ takamints.hatenablog.jp
売り上げランキング: 172
- 事前準備:ローカルグループポリシーエディターを使える状態にしておきましょう
- IEモードを使うための前提条件
- Microsoft Edge ポリシー設定を構成する
- 管理用テンプレートをダウンロード
- 管理用テンプレートを設定する
- ローカルグループポリシーエディタでIEモードのグループポリシーを設定
事前準備:ローカルグループポリシーエディターを使える状態にしておきましょう
後の作業でローカルグループポリシーエディターを使いますので、ちゃんと実行できることを確認しておきましょう。 Windows 10 Home では初期状態で使えませんからここで使えるように設定しておきましょう。 ワタシは必要な時点で設定したりで大いに混乱しましたから。
ローカルグループポリシーエディターの起動を確認
ローカルグループポリシーエディターを起動するには、[Windowsキー]+[R]で「ファイル名を指定して実行」ウィンドウを開き gpedit.msc
と入力して「OK」ボタンをクリックします。
このときローカルグループポリシーエディターが開けば問題はありません。
もしもエラーが表示される場合、以下のページを参考にして使える状態に設定してください。メモ帳を使いますがコピペできれば大丈夫です。
IEモードを使うための前提条件
Use Microsoft Edge with IE mode というページを開きます。
2020年2月現在、日本語のページは無いようです。
「Prerequisites」に「IEモード」を使うための前提条件が記載されています。
「1.最低限必要なOSのバージョン」、「2.Microsoft Edge管理ポリシーテンプレート」、そして「3.Windowsの機能としてIE11が有効になっていること」と書かれています。
1と3は簡単に理解できましたが2の「Microsoft Edge管理ポリシーテンプレート」が、よくわかりません。 「さらなる情報はConfigure Microsoft Edge を見よ」とありますのでリンクをたどると、次の Windows 用に Microsoft Edge を構成する | Microsoft Docs が表示されました。
Microsoft Edge ポリシー設定を構成する
なんだか少し読みにくい日本語ですが・・・
新EdgeでIEモードを使うには「WindowsでMicrosoft Edgeポリシー設定を構成する」必要があり、「アクティブディレクトリのドメインに参加していない Windows 10 Home」では、Microsoft Edgeの規則と設定を追加するための管理用テンプレート をダウンロードして、コンピュータのポリシー定義テンプレートフォルダーに、インストールする必要があります。
管理用テンプレートをダウンロード
「Microsoft Edge Enterprise ランディング ページ」へ移動して Microsoft Edge ポリシー テンプレートファイル (MicrosoftEdgePolicyTemplates.cab) をダウンロードします。
Microsoft Edge Enterprise ランディング ページ
「CHANNEL/BUILD」でEdgeのバージョンを選び「PLATFORM」からOSを選んで、ポリシーファイルをダウンロードします。
Edgeのバージョンなどを確認してから「GET POLICY FILES」のリンクをクリックすると、プライバシーステートメントを読まされます。
ちゃんと読んでから「ACCEPT and DOWNLOAD」を押したらポリシーファイルをダウンロードできました。
管理用テンプレートを設定する
ダウンロードしたポリシーファイルは「MicrosoftEdgePolicyTemplate.cab」というキャビネットファイルです。 これをすべて展開し、展開されたファイルの中で以下の特定のファイルをコンピュータのポリシー定義テンプレートフォルダーへコピーします。
MicrosoftEdgePolicyTemplate/ windows/ admx/ 1) msedge.admx` ⇒ C:/Windows/PolicyDefinitions/ 2) en-US/msedge.adml ⇒ C:/Windows/PolicyDefinitions/en-US/ 3) ja-JP/msedge.adml ⇒ C:/Windows/PolicyDefinitions/ja-JP/
※ 3番目のja-JPのファイルはウェブページでは指定されていませんでしたが、ファイルがあったので一応コピーしておきました。
ポリシー設定の確認
上でコピーしたポリシーが正しく読み込まれたかどうかは、gpeditの左側のツリーで コンピューターの構成>管理用テンプレート>Microsoft Edge
を選択し、ツリーや右側のペインに複数のMicrosoft Edgeに関する項目があることで確認できるそうです。
何らかのエラーがある場合はgpeditが開けずエラーが表示されるらしい。
ローカルグループポリシーエディタでIEモードのグループポリシーを設定
gpeditで、コンピューターの構成>管理用テンプレート>Microsoft Edge
を選択し、右側のペインから「Internet Explorer統合を構成する」という設定項目を探します。
たくさんあるので見つけにくいのですが、ざっくり以下の画面の右端のスクロールバーの位置を参考にしてください。
この項目をダブルクリックするか、設定の説明が表示されている部分の「ポリシー設定」のリンクをクリックして設定ウィンドウを開き、左上にあるラジオボタンの「有効」を選択します(最初は「未構成」になっているはず)。
次に、オプションの下のドロップダウンリストから、「Internet Explorer モード」を選択します。
ポリシー設定ウィンドウをOKボタンで閉じれば、設定完了。お疲れさま。
以下の記事で書いているEdgeの設定ができているなら、この時点で新EdgeでIEモードが使えるようになっているはずです。 まだ設定していないなら是非どうぞ↓