色んな人のqmk_firmwareをGitでちゃんとまとめて管理する

改訂版を書きました。

https://mogira-jubeat.hatenadiary.org/entry/2020/10/24/172137


自作キーボードでよく使われるqmk_firmwareですが、キーボードの作者がforkしてQMK公式にmergeせず、個別に自分のリポジトリに持っていることがよくあります。

QMK公式にmergeするのって結構大変そうですし、他人のソースコードの管理に関してとやかく言う気はないですが、純粋にユーザーとして見ると、ほぼ同じソースコードを別のディレクトリで管理したり、新しくcloneしたらディレクトリ名変えてmake submodule~とかやってると「Gitとは…?」という気持ちが湧いてきます。

 

というわけで今回は『公式を含む色んな人のqmk_firmwareを、Gitの機能をちゃんと使ってまとめて管理しよう』という趣旨の記事です。

最終的に、色んな人のqmk_firmwareをブランチとしてgit switchで切り替えられるようになるのを目指します。また、ローカルに持ってきた時にmasterというブランチ名が被りまくって面倒なのでこの辺も弄って、あとは他人のリポジトリに誤pushしないように、とかも設定します。

私はあんまりGitに詳しくないので色々調べながらやってましたが、リポジトリとかブランチとかのremote/upstream/local辺りの話をちゃんと理解してる人なら悩むこともないと思います。(というか自作キーボードの人達はみんな既にやってそう……)

よく分からない人にはこの記事が分かりやすいです。

 

注:

この記事は『元々Gitはなんとなく使ってて、もう少しGitを便利に使ってみたくなった自作キーボード製作者』辺りを想定して書いていますので、比較的ハードルが高いと思います。
開発中のコードが消えても私は一切責任を取りません。自身が無い方は挑戦する前に必ずバックアップを取っておきましょう。

 

それではやっていきます。なお、執筆当時の私のGitはv2.28.0です。 

 

Part 1

まずは公式であるqmk/qmk_firmwareをcloneしてきて中に入ります。

$ git clone https://github.com/qmk/qmk_firmware.git
$ cd qmk_firmware

f:id:mogira_jubeat:20201013130323p:plain


次に「もう理解しないままgit pullなんてしないぞ!」という強い意志と共にqmk/qmk_firmwareをoriginの座から引きずり下ろします。※この操作後もgit pullは普通にできます。
リモート名(originとかのことって何て呼ぶんですかね?)は、origin改めofficialとでもしておきましょう。

$ git remote
origin
$ git remote rename origin official
$ git remote
official

f:id:mogira_jubeat:20201013130520p:plain



ついでにローカルのmasterというブランチ名が非常にややこしいので、QMK公式のmasterなのでofficial_masterとでも変えておきます。

$ git branch
* master
$ git branch --move master official_master
$ git branch
* official_master

f:id:mogira_jubeat:20201013130645p:plain



ここに自分のgithubリポジトリ(mogira/qmk_firmware)を新しくリモートリポジトリとして追加します。リモート名(?)はmogiraとでもしておきます。

$ git remote
official
$ git remote add mogira https://github.com/mogira/qmk_firmware.git
$ git remote
official
mogira

f:id:mogira_jubeat:20201013130946p:plain


この状態でgit fetch --allしてからbranchを一覧すると、official(qmk/qmk_firmware)とmogira(mogira/qmk_firmware)に含まれる全branchが表示されます。

$ git fetch --all
$ git branch --all
remotes/mogira/~
...
remotes/official/~
...

f:id:mogira_jubeat:20201013131434p:plain



ここまで来たら、弄りたいブランチをローカルにswitch -c(checkout -b)しましょう。ここではmogira/masterをmogira_masterというブランチ名でswitch -cします。

$ git branch
* official_master
$ git switch -c mogira_master mogira/master
$ git branch
* mogira_master
  official_master

f:id:mogira_jubeat:20201013131637p:plain



↑でgit switch -cしたときに上流ブランチ(upstream branch)を指定しているので、git branch -vvで確認してもmogira_masterにはきちんと上流ブランチが設定されていると思いますが、この段階のmogira_master上で何気なくgit pushしようとすると「上流ブランチとブランチ名が違うよ!」と怒られてpushできないはずです。
これはGit 2.0からpush.default(push時のデフォルト動作に関する設定項目)のデフォルト値が"simple"(設定されている上流ブランチと現在のブランチ名が合っているときのみpush)になっているのが原因なので、これを"upstream"(ブランチ名をチェックせずに、設定されている上流ブランチにpush)に変更します。

$ git branch -vv
* mogira_master ~ [mogira/master] ~~
  official_master ~ [official/master] ~~
$ git push
fatal: The upstream branch of your current branch does not match the name of your current branch.
...
$ git config push.config upstream
$ git push
Username for 'https://github.com': mogira
Password for 'https://mogira@github.com':
Everything up-to-date

 

↑で設定したpush.defaultはこのgit全体にかかってしまっています。この設定を忘れて他人のリポジトリに誤pushすると辛いので、pushする予定のないリモートリポジトリはpush時のurlを適当な値(↓の例では"no-push")に変更しておきます。こうすることで間違って他人のリモートリポジトリを指定したままpushしても、エラーになるだけで済みます。

$ git remote -v
mogira  https://github.com/mogira/qmk_firmware.git (fetch)
mogira  https://github.com/mogira/qmk_firmware.git (push)
official        https://github.com/qmk/qmk_firmware.git (fetch)
official        https://github.com/qmk/qmk_firmware.git (push)
$ git remote set-url --push "no-push"
$ git remote -v
mogira  https://github.com/mogira/qmk_firmware.git (fetch)
mogira  https://github.com/mogira/qmk_firmware.git (push)
official        https://github.com/qmk/qmk_firmware.git (fetch)
official        no-push (push)
$ git switch official_master
$ git push -v
Pushing to no-push
fatal: 'no-push' does not appear to be a git repository

f:id:mogira_jubeat:20201013131911p:plain


 

最後に、push-urlを変更したリポジトリに対してもgit fetch/pullは可能なことと、自分のリポジトリに対しては問題なくgit push/fetch/pullができることを確認しておきましょう。

$ git switch official_master
$ git fetch -v
From https://github.com/qmk/qmk_firmware
...
$ git pull -v
...
From https://github.com/qmk/qmk_firmware
...
$ git switch mogira_master
$ git push -v
Pushing to https://github.com/mogira/qmk_firmware.git
Username for 'https://github.com': mogira
Password for 'https://mogira@github.com':
To https://github.com/mogira/qmk_firmware.git
 = [up to date]          mogira_master -> master
updating local tracking ref 'refs/remotes/mogira/master'
Everything up-to-date
$ git fetch -v
From https://github.com/qmk/qmk_firmware
...
$ git pull -v
...
From https://github.com/qmk/qmk_firmware
...

 

というわけで完成です。

これで、git switchで色んな人のqmk_firmwareを切り替えられて、自分のブランチにswitchした後pushすればいつも通り自分のリポジトリに反映でき、他人のリポジトリには操作を間違えてもpushされない状態にできました。あとは適宜ブランチを切り替えて使えばいいと思います。

分かってる人なら.git/configを直接エディタで編集しても良いのですが、説明が面倒なので今回は全部コマンドでやりました。一応以下に全コマンド打ち終わった後の.git/configを置いておきますので、設定漏れのチェックにでも使ってください。

[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
[remote "official"]
	url = https://github.com/qmk/qmk_firmware.git
	fetch = +refs/heads/*:refs/remotes/official/*
	pushurl = no-push
[branch "official_master"]
	remote = official
	merge = refs/heads/master
[remote "mogira"]
	url = https://github.com/mogira/qmk_firmware.git
	fetch = +refs/heads/*:refs/remotes/mogira/*
[branch "mogira_master"]
	remote = mogira
	merge = refs/heads/master
[push]
	default = upstream

 

Part 2

Twitterで「私はこんな感じで管理してるよ」というのを教えてもらったので、紹介してみます。

f:id:mogira_jubeat:20201014080241p:plain

私のと違う点を挙げてみます。

  1. qmk/masterをローカルにcheckoutしていない
  2. masterブランチは自分のリポジトリのmasterを指すようにして、その他のリポジトリでmasterがあっても、別の名前でcheckoutする
  3. masterブランチは基本的にqmk/masterをmergeするためだけに使う
  4. 編集/開発作業は開発用のブランチ上(↑では適当にhogeとしている)で行う

まず1ですが、実は私の方でも要りません。なぜPart 1でわざわざ作ってたかというと、qmkと自分以外のレポジトリから持ってくることも想定して、"<remote name>_<branch name>"というローカルブランチの命名規則を説明するために、敢えてcheckoutしていました。

次の2がシンプルで良いなと思ったのでこれを紹介するに至りました。
私はこの作業をやり始めた時に「今ローカルにあるmasterってどこのリモートリポジトリのmasterだ!?」と混乱したので、Part 1のやり方をやって頭を整理してましたが、2の案を採用すると、ローカルブランチ名がmasterになるので、push.defaultについて特別な設定をする必要がなくなります。

3,4は割と当たり前というか、よく見かけるGitのワークフローです。私は全然理解していないので各自git-flowとかGitHub Flowとかでちゃんと調べて欲しいのですが、てきとーに説明すると『masterブランチというのは即時利用可能な状態にしておくべきなので、masterブランチには開発中のコードのコミットを入れずに、別途開発用のブランチを作れ』という運用のルールがあります。私は(小規模開発で使うくらいならいいんじゃないの…)とか思ってしまっているので、多分ちゃんと理解できていないです。

※ 3,4 については「masterブランチには直接コミットするな。別に開発ブランチを作れ」(意訳)というQMK公式の運用ルールがありました。なお、qmk/developブランチはQMKコアへの破壊的な変更を含むPRを投げるためのブランチらしいので、個人の開発用ブランチ(図中のhogeブランチ)はdevelop以外の名前が良いそうです。

あとは、他人のGitHubリポジトリはそもそもPermissionをもらわないとPushできないので基本的には誤Pushは気にしなくていいそうです。私も試したことはなかったので予防策として設定していましたが、無くても良さそうですね。

 

おしまい

そういえばTwitterで別の方から言われてハッとしたのが、『そもそも自作キーボード界隈ってGitよく分からん人が結構いるから、こういう複雑なことすると事故るのでは?』という懸念です。言われてみれば、自作キーボード界隈はガリガリにコードを書いてGitをバリバリ使いこなす人から、「黒い画面いじるの怖いから、あのキーボードはやめて半田付けだけで作れるこっちのにしよ!」って人まで、幅広い層の人がいます。

そう考えると、(冒頭にも注意書きを追記しましたが)この記事は自作キーボード界隈では割とハードルが高いものかもしれません。普通に別ディレクトリで持っていれば安全なので無理にやる必要はないです。Gitは開発を便利にするためのものであって、Git自体が開発の足枷になるのであればやらない方がいいと思います。それこそGitの操作ミスって開発中のコードが消えたとか目も当てられないですからね……

あと、Part 2追加したときに「この図に至るまでのコマンド全部書こうか。でも元の図から移行するためのコマンドもあったほうが良いな。でも両方書くと混乱するかな…(私みたいに説明書読まない奴だと)事故るのかも…」みたいな葛藤があったので、コマンドの記載はやめました。必要なコマンド(ブランチ名の変更、リモート名?の変更等)は既に紹介しているので、話を理解してくれた人なら図を見て出来るでしょう……