「Git」の版間の差分
細 (→オプション) |
(PR後のブランチ名変更) |
||
| (同じ利用者による、間の33版が非表示) | |||
| 16行目: | 16行目: | ||
GitHubではREADME系ファイルを描画表示してくれる。READMEとREADME.*が対象。index.html系はだめ。 | GitHubではREADME系ファイルを描画表示してくれる。READMEとREADME.*が対象。index.html系はだめ。 | ||
==== PR ==== | ==== PR+issue ==== | ||
Pull Request。第三者の修正を、本体側でgit pull (取り込む) ことのリクエスト・要請。 | Pull Request。第三者の修正を、本体側でgit pull (取り込む) ことのリクエスト・要請。 | ||
| 25行目: | 25行目: | ||
そうしないと、マージ先だけ反映されてしまって、想定していない差分が大量に表示される。 | そうしないと、マージ先だけ反映されてしまって、想定していない差分が大量に表示される。 | ||
===== PR後のブランチ名変更 ===== | |||
できない。ブランチ名を変更すると、別のPRにするしかない。 | |||
[https://web.archive.org/web/20250919111740/https://stackoverflow.com/questions/20007578/renaming-a-branch-while-on-pull-request git - Renaming a branch while on pull request - Stack Overflow] | |||
===== Web UIでの編集 ===== | ===== Web UIでの編集 ===== | ||
| 43行目: | 48行目: | ||
ファイル自体にコメントするには、右上のコメントマーク。 | ファイル自体にコメントするには、右上のコメントマーク。 | ||
===== マージ後修正 ===== | |||
[https://dev.classmethod.jp/articles/whether-merged-pr-can-be-merged-again/ GitHubでMerge済みのPull requestにCommitを追加して再度Mergeできるのか確認してみた | DevelopersIO] | |||
一度マージされたら、同じブランチに追加コミットしても、再マージはできない。 | |||
PRの作成が必要。 | |||
===== マージロック ===== | |||
右上の [Reviewers] のところの [Convert to draft] で下書きにできる。この状態だとマージ不能になる。 | |||
一番下の [No conflicts with base branch] あたりの [ready for review] で元に戻せる。 | |||
===== リモートブランチ削除後復元 ===== | |||
[https://docs.github.com/ja/repositories/configuring-branches-and-merges-in-your-repository/managing-branches-in-your-repository/deleting-and-restoring-branches-in-a-pull-request pull request 中のブランチの削除と復元 - GitHub Docs] | |||
マージ済みブランチの整理中に間違えて、削除してしまった。 | |||
リモートブランチを削除すると、PRがあったらclosedになる。 | |||
復元するには以下の手順を取る。 | |||
# 元ブランチを復元 | |||
# PR一覧画面を出してチェックしてステータス変更 | |||
===== 添付ファイルの削除 ===== | |||
[https://tech.coincheck.blog/entry/2022/10/21/113906 GitHubのIssueやPull requestsにアップロードした画像の削除 - Coincheck Tech Blog] | |||
issue+pull requestに添付したファイルは、外部のアップローダーを使っており、URLは公開されている。 | |||
削除は専用フォームから依頼が必要で面倒。 | |||
アップロードは注意する。 | |||
==== Other ==== | |||
===== remote: Support for password authentication was removed on August 13, 2021. ===== | |||
git pushすると以下のようなエラーが出る。 | |||
remote: Support for password authentication was removed on August 13, 2021. | |||
remote: Please see <nowiki>https://docs.github.com/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls</nowiki> for information on currently recommended modes of authentication. | |||
fatal: Authentication failed for '<nowiki>https://github.com/senooken/dotfile/'</nowiki> | |||
2021-08-13からパスワード認証が使用不能になった。 | |||
[https://docs.github.com/ja/get-started/git-basics/about-remote-repositories#cloning-with-https-urls%20for%20information%20on%20currently%20recommended%20modes%20of%20authentication リモートリポジトリについて - GitHub Docs] | |||
アクセストークンを使う。 | |||
「[https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens 個人用アクセス トークンを管理する - GitHub Docs]」に設定方法がある。 | |||
必要な権限が明記されていなくてややこしい。 | |||
https://chatgpt.com/share/682ac434-8598-800b-aaad-de73b48a337d | |||
[Fine-grained tokens]と[Classic token]とで違う。 | |||
# [Settings]-[Developer settings]-[Personal access token] | |||
# Tokens (classic) (https://github.com/settings/tokens<nowiki>)-[Generate new token]</nowiki> | |||
## ☑️ repo | |||
# [Fine-grained tokens] (https://github.com/settings/personal-access-tokens) -[Generate new token] | |||
## Repository access: ◉ All repositories | |||
## Permissions | |||
### Account Repository permissions: | |||
#### Contents=Read and write | |||
これで生成されたパスワードを入力すればOK。 | |||
===== WSLに認証情報保存 ===== | |||
[https://web.archive.org/web/20250618024058/https://zenn.dev/toccasystems/articles/wsl2-git-credential-manager WSL2でGit認証を毎回聞かれないようにする] | |||
[https://portablecode.info/2023/05/06/git-credential-manager-windows-wsl2-linux/ Git Credential Manager (GCM) でGithubへの認証をセキュアに実現する (Windows, WSL2, Linux) – Portablecode.info] | |||
Githubにpush/pullしようとすると、通常であれば、認証マネージャーが起動して、そこの認証情報を流用してくれる。ただ、WSLを使っている場合、設定が必要。 | |||
Git for Windowsをインストールしていれば、それに同梱されている。パスの設定だけ行う。 | |||
git config --global credential.helper "/mnt/c/Program\ Files/Git/mingw64/bin/git-credential-manager.exe" | |||
== Server == | |||
[https://git-scm.com/book/ja/v2/Git%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc-%e3%83%97%e3%83%ad%e3%83%88%e3%82%b3%e3%83%ab Git - プロトコル] | |||
Gitで自前のサーバー、リモートリポジトリーを設置する方法がある。 | |||
いくつか考慮事項がある。どのプロトコルを使うかが重要。 | |||
https://grok.com/share/c2hhcmQtMw%3D%3D_2b4fcc61-0d45-4d12-abac-6b29246b3716 | |||
基本事項として、あくまでgitサーバーはリポジトリー機能のみの提供。Web表示は別。 | |||
閲覧には、gitweb/cigt/tracなどの別ソフトを使う。 | |||
リポジトリー機能+閲覧を一緒にやりたければ、gitlab/phorgeとか専用のソフトが必要。だけど、VPSが必要になる。 | |||
CGIの範囲で、レンタルサーバーで完結させたければ、git server+tracのような組み合わせがほぼ必須。 | |||
=== プロトコル === | |||
[https://git-scm.com/book/ja/v2/Git%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc-%e3%83%97%e3%83%ad%e3%83%88%e3%82%b3%e3%83%ab Git - プロトコル] | |||
Gitサーバーを設置する際、プロトコルに応じて、方法が大きく異なる。 | |||
* Local: リモートリポジトリーを全員がアクセス可能なディスク上に配置。file://でアクセス。 | |||
* HTTP: HTTPを使う方法。一般的。ただ、v1.6.5までは読取だけだった。v1.6.6からSmart HTTPが登場して、書き込みも可能になった。 | |||
* SSH: 匿名アクセス不能。読込専用でも。自分専用。非公開。 | |||
* Git: 最高速。ただし、認証の仕組みがない。独自のデーモンが必要で用意が大変。 | |||
Smart HTTPほぼ一択。 | |||
==== サーバー用Gitの取得 ==== | |||
[https://git-scm.com/book/ja/v2/Git%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc-%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e7%94%a8%e3%81%ae-Git-%e3%81%ae%e5%8f%96%e5%be%97 Git - サーバー用の Git の取得] | |||
Gitサーバー用のリポジトリーを用意する。基本は既存のGitリポジトリーだが、サーバー用に作業ファイルのないリポジトリーにする。 | |||
既存リポジトリーをエクスポートして作成する。git clone --baseで他のローカルgitリポジトリーから作る。 | |||
$ git clone --bare my_project my_project.git | |||
このコマンドはおおざっぱには以下のコマンドと同じ。 | |||
$ cp -Rf my_project/.git my_project.git | |||
==== Smart HTTP ==== | |||
[https://git-scm.com/book/ja/v2/Git%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc-Smart-HTTP Git - Smart HTTP] | |||
Smart HTTPによる設置方法。基本はGit付属のCGIスクリプトとサーバー、認証設定のみ。 | |||
git-http-backendスクリプトを使う。 | |||
===== Model ===== | |||
Apache HTTP Serverでの設置手順の場合。 | |||
mod_cgi/mod_alias/mod_env/mod_rewriteを有効にする。 | |||
$ sudo apt-get install apache2 apache2-utils | |||
$ a2enmod cgi alias env rewrite | |||
gitの管理ルートディレクトリー (例: /opt/git) をwww-dataのグループに変更して、httpdから読書可能にする。 | |||
$ chgrp -R www-data /opt/git | |||
/gitパスアクセス時に、git-http-backendを割り当てる。 | |||
SetEnv GIT_PROJECT_ROOT /opt/git | |||
SetEnv GIT_HTTP_EXPORT_ALL | |||
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/ | |||
他に、GIT_PROJECT_ROOTでgitの管理ルートディレクトリーを設定。GIT_HTTP_EXPORT_ALLを設定して、書き込み可能にする。これを設定しない場合、クライアントからは読込専用で、git-daemon-export-okファイルが保存されたリポジトリーのみ (git daemonと同じ挙動)。 | |||
最後にgit-http-backendへのアクセス許可の設定と、書き込み認証を設定する。 | |||
RewriteEngine On | |||
RewriteCond %{QUERY_STRING} service=git-receive-pack [OR] | |||
RewriteCond %{REQUEST_URI} /git-receive-pack$ | |||
RewriteRule ^/git/ - [E=AUTHREQUIRED] | |||
<Files "git-http-backend"> | |||
AuthType Basic | |||
AuthName "Git Access" | |||
AuthUserFile /opt/git/.htpasswd | |||
Require valid-user | |||
Order deny,allow | |||
Deny from env=AUTHREQUIRED | |||
Satisfy any | |||
</Files> | |||
order/deny/satisfyを使わない場合、以下だと思う。 | |||
RewriteEngine On | |||
RewriteCond %{QUERY_STRING} service=git-receive-pack [OR] | |||
RewriteCond %{REQUEST_URI} /git-receive-pack$ | |||
RewriteRule ^/git/ - [E=AUTHREQUIRED] | |||
<Files "git-http-backend"> | |||
AuthType Basic | |||
AuthName "Git Access" | |||
AuthUserFile /opt/git/.htpasswd | |||
Require valid-user | |||
Require not env AUTHREQUIRED | |||
</Files> | |||
これの意味。git push時 (service=git-receive-pack /git-receive-pack) はパスワード認証が必要だが、それ以外はパスワード不要 (require not envにマッチ) という意味 (https://grok.com/share/c2hhcmQtMw%3D%3D_826f3cbf-b07d-434a-a573-a921b8eee6ea<nowiki/>)。 | |||
さらに、対象ユーザー全員のパスワードが記述された.htaccessファイルを用意。ユーザーschaconを追加する場合以下を実行する。 | |||
$ htpasswd -c /opt/git/.htpasswd schacon | |||
https://grok.com/share/c2hhcmQtMw%3D%3D_059bbb94-5e7b-4f02-99bb-1303b51d62a9 | |||
Digest認証もできるが、複雑になるだけで、あまり意味がないのでBasic認証でやるのがよさそう。 | |||
* [https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-%E8%BB%A2%E9%80%81%E3%83%97%E3%83%AD%E3%83%88%E3%82%B3%E3%83%AB Git - 転送プロトコル] | |||
* [https://zenn.dev/hirokihello/articles/d5866bc64f13e3f3b8c7 git pushの裏側で何が起こっているのか。~javascriptでgitをリバースエンジニアリングで実装する(4)~] | |||
git-receive-packがいきなり登場して混乱した。このパスはgit push時に使っている模様。 | |||
git pushすると以下を通信して、リモートリポジトリーに書き込む模様。 | |||
# GET /push-test.git/info/refs?service=git-receive-pack | |||
# POST /push-test.git/git-receive-pack | |||
なので、これらのパスへのアクセスに認証をかけている模様。 | |||
=== Gitolite === | |||
==== About ==== | |||
* https://grok.com/share/c2hhcmQtMw%3D%3D_461ea368-264f-4d96-b203-fdd120722ec6 | |||
* https://grok.com/share/c2hhcmQtMw%3D%3D_270a9b75-83a8-47d9-ade9-d3b1d8a44b41 | |||
* [https://yunwuxin1.gitbooks.io/git/content/ja/a1ed4f4c6948f27fef097ffaf08a545b/b60cff70126a55243f738debc93cae75.html Gitolite · git] | |||
* [https://gitolite.com/gitolite/ Gitolite] | |||
git-http-backendを使う場合、apacheのbasic認証を使う。と、アカウント管理が面倒になる。 | |||
gitoliteを使うとそのあたりカバーされるらしい。基本はsshだけど、httpでもできるとか。 | |||
gitolite-admin.gitという、専用のgitリポジトリーで管理しているとか。 | |||
==== Auth ==== | |||
ただ、gitoliteはもともとSSH前提。HTTPもいけるがその場合apacheのbasic認証との併用で、basic認証のユーザーとsshのユーザーが対応している。 | |||
その都合、basic認証とssh認証の二重管理が必要。アカウント管理を楽にしたかったのに、二重管理になってしまい本末転倒。やっぱり、git-http-backend+apacheで構築するのがベスト。 | |||
アカウント管理が必要なら、自分で管理用のツール・スクリプトを作ったほうがよさそう。 | |||
https://grok.com/share/c2hhcmQtMw%3D%3D_e86d9e67-edfa-4a60-88f4-6537a0b06742 | |||
あるいは、自作するほかに、oauthやldapの外部認証を使う方法がある。外部認証でいけるなら、これが確実かも。ただ、この外部認証を自分でホストする必要があって、今の段階だとこれを考えるのが面倒くさい。当面は手動管理でいく。 | |||
==== Install ==== | |||
* [https://gitolite.com/gitolite/quick_install.html (unix/ssh experts) quick install and setup - Gitolite] | |||
* [https://gitolite.com/gitolite/http.html HTTP mode install - Gitolite] | |||
== View == | == View == | ||
| 150行目: | 368行目: | ||
rebase --root [branch] でブランチの第一コミットも参照して改変可能。 | rebase --root [branch] でブランチの第一コミットも参照して改変可能。 | ||
ファイルを間違えて追加してしまった場合は、git rm -r --cached で削除してコミットし直せばいい。 | |||
=== コミットログの文字化け === | === コミットログの文字化け === | ||
| 196行目: | 416行目: | ||
git add -Aとgit add .はほぼ同じ。Git 2.0以降ではgit add -Aがデフォルトになっているらしい (https://chatgpt.com/c/67f4e2c7-a240-800b-8084-9650ef61a47e<nowiki/>)。 | git add -Aとgit add .はほぼ同じ。Git 2.0以降ではgit add -Aがデフォルトになっているらしい (https://chatgpt.com/c/67f4e2c7-a240-800b-8084-9650ef61a47e<nowiki/>)。 | ||
=== ammendの打消し === | |||
[https://qiita.com/s_horikoshi/items/21f6bc12dfb98ebdfcb9 間違えて実行したgit commit --amendを元に戻す方法 #Git - Qiita] | |||
[https://mz-kb.com/blog/2018/07/12/git-commit-amend-how-to-cancel/ git commit -amendを取り消すorキャンセルする方法 - まさかろぐ] | |||
コミット中に間違いに気づいた場合、コミットメッセージの入力中に、メッセージを空にすると中断できる。 | |||
git reset --soft HEAD@{1} | |||
これで直前のコミットの状態に戻せる。あるいは、git reflogで修正前のコミットを探すとか。 | |||
== branch == | == branch == | ||
[https://git-scm.com/docs/git-branch Git - git-branch Documentation] | [https://git-scm.com/docs/git-branch Git - git-branch Documentation] | ||
=== 先頭アスタリスクの除去 === | |||
[https://stackoverflow.com/questions/51696931/list-all-local-git-branches-without-an-asterisk git branch - List all local git branches without an asterisk - Stack Overflow] | |||
git branchを実行すると現在ブランチの先頭に*のアスタリスクのマークがつく。これが邪魔。git branch -rだとつかない。除去したい。 | |||
あまりいい方法はない。 | |||
git for-each-ref --format='%(refname:short)' refs/heads/ | |||
git branch --format='%(refname:short)' | |||
git branch | cut -c 3- | |||
2番目の方法が綺麗。 | |||
=== 誤ったブランチへのコミットの付け直し === | === 誤ったブランチへのコミットの付け直し === | ||
| 210行目: | 450行目: | ||
# cherry-pickで変更コミットだけ別ブランチに抽出。 | # cherry-pickで変更コミットだけ別ブランチに抽出。 | ||
# git checkoutとreset --hardで分離: 現在の状態を一旦別ブランチにしてコピー。その後、元ブランチはgit reset --hardで打ち消す。 | # git checkoutとreset --hardで分離: 現在の状態を一旦別ブランチにしてコピー。その後、元ブランチはgit reset --hardで打ち消す。 | ||
# git rebase --onto <別ブランチ> 起点コミット | # git rebase --onto <別ブランチ> 起点コミット でコミットを付け替えて、ブランチを削除、改名して元のブランチの名前にする。付け替え場、起点コミットで元のベースブランチにする。 | ||
git rebase --ontoがきれい。 | git rebase --ontoがきれい。 | ||
| 224行目: | 464行目: | ||
* git branch -u|--set-upstream-to <upstream>: リモートトラッキングブランチを指定。 | * git branch -u|--set-upstream-to <upstream>: リモートトラッキングブランチを指定。 | ||
* git branch --unset-upstream: 設定済みのリモートトラッキングブランチの対応を解除。 | * git branch --unset-upstream: 設定済みのリモートトラッキングブランチの対応を解除。 | ||
=== マージ済みブランチの一括削除 === | |||
放置すると、マージ済みブランチが残る。うざい。 | |||
* [https://qiita.com/ucan-lab/items/97c53a1a929d2858275b Git マージ済みのブランチを一括削除する #Bash - Qiita] | |||
* [https://qiita.com/y-hys/items/a21df6ebb15cecbe8948 【git】マージ済のremoteブランチを一括で削除する方法 #Git - Qiita] | |||
2個目の記事が特に良かった。 | |||
基本的な考え方がいくつかある。 | |||
## ローカルブランチの削除 | |||
git branch -d <branch> | |||
## リモートブランチの削除 | |||
git push -d origin <branch> | |||
## 削除済みリモートブランチの、リモートトラッキングブランチの削除 | |||
git fetch -p | |||
## マージ済みローカルブランチの一覧 | |||
git branch --merged[=origin/develop] | |||
## マージ済み全ブランチの一覧 | |||
git branch --merged[=origin/develop] -r | |||
ローカルブランチの場合、git branch --mergedの一覧に対して、git branch -d を実行していくイメージ。ついでに、git push -dもしてもいいかも。 | |||
ただし、main/master/developなど削除から除外したいブランチはあるだろう。 | |||
git branch --mergedには引数を指定可能で、マージ先のブランチを指定できる。これを指定しないと、途中の集約用ブランチへのマージもマージ済みと認識されるので、必須だろう。 | |||
git branch -rでリモートブランチもリストに含められる。 | |||
これらを組み合わせてシェルスクリプトを作る。 | |||
## ローカルブランチのローカル・リモートの一括削除 | |||
git branch --format='%(refname:short)' --merged origin/develop | | |||
grep -v -e '^master' -e '^main' -e '^develop' | | |||
xargs -I {} sh -c 'git branch -d {} && git push -d origin {}' | |||
## リモートブランチの一括削除 | |||
git branch --format='%(refname:short)' --merged origin/develop -r | | |||
grep -v -e '^origin/master' -e '^origin/main' -e '^origin/develop' | | |||
sed 's@^origin/@@' | | |||
xargs -I {} sh -c 'git branch -d {} ; git push -d origin {}' | |||
== Merge == | == Merge == | ||
| 293行目: | 572行目: | ||
基本は機能ブランチ (feature branch) のマージでは、--no-ffを使う。こうすることで、いつマージされたかが明確になる。 | 基本は機能ブランチ (feature branch) のマージでは、--no-ffを使う。こうすることで、いつマージされたかが明確になる。 | ||
== | == Customize == | ||
=== | === Git config === | ||
[https:// | [https://git-scm.com/book/ja/v2/Git-%e3%81%ae%e3%82%ab%e3%82%b9%e3%82%bf%e3%83%9e%e3%82%a4%e3%82%ba-Git-%e3%81%ae%e8%a8%ad%e5%ae%9a Git - Git の設定] | ||
==== .netrc ==== | |||
https://social.senooken.jp/conversation/1573147#notice-2217499 | |||
Gitのパスワード入力の省略方法に~/.netrcがある。 | |||
しかし、man netrcするとわかるけど、これはもともとFTPのためのもの。なぜGitで使えるんだ?Gitの文書で言及がない。 | |||
In conversation Thursday, 21-Feb-2019 10:58:47 JST from web permalink | |||
せのお (妹尾 賢)せのお (妹尾 賢) in reply to | |||
理由が分かった。 | |||
1. Gitはhttpとhttpsの通信にcURLを使っている。 | |||
https:/ | <nowiki>https://github.com/git/git/blob/master/INSTALL#L141</nowiki> | ||
2. cURLが.netrcにも対応しているから。 | |||
https:/ | <nowiki>https://ec.haxx.se/usingcurl-netrc.html</nowiki> | ||
=== core.autocrlf === | ==== core.autocrlf ==== | ||
warning: in the working copy of 'docker/README.md', LF will be replaced by CRLF the next time Git touches it | |||
Windowsでは改行にCR+LFを使うが、mac/LinuxはLFのみ。これの違いの処理のための設定がcore.autoclrlf | |||
* true=コミット時にCRLFをLFに自動変換。チェックアウト時に逆。Windows向けの設定。 | * true=コミット時にCRLFをLFに自動変換。チェックアウト時に逆。Windows向けの設定。 | ||
| 332行目: | 608行目: | ||
わかりにくい。基本はfalseで良いと思われる。 | わかりにくい。基本はfalseで良いと思われる。 | ||
=== gitkの文字化け対策 === | ==== gitkの文字化け対策 ==== | ||
[https://www.pistolfly.com/weblog/2010/02/gitk.html gitkのエンコーディングを設定する - Pistolfly] | [https://www.pistolfly.com/weblog/2010/02/gitk.html gitkのエンコーディングを設定する - Pistolfly] | ||
gitkはシステムのデフォルトエンコーディングで表示しようとするので、文字エンコーディングを指定しておく。 | gitkはシステムのデフォルトエンコーディングで表示しようとするので、文字エンコーディングを指定しておく。 | ||
git config --global gui.encoding utf-8 | git config --global gui.encoding utf-8 | ||
WSLなどで、日本語が表示されない場合、フォントが入っていない可能性が高い。 | |||
=== ファイル名などの文字化け対策 === | 以下のコマンドで日本語対応フォントをインストールする。 | ||
sudo apt install -y fonts-noto-cjk fonts-noto-cjk-extra fonts-ipafont | |||
==== ファイル名などの文字化け対策 ==== | |||
[https://qiita.com/kumazo/items/2169e1ee7be278f82b94 Git for Windows で日本語を使いたい #Vim - Qiita] | [https://qiita.com/kumazo/items/2169e1ee7be278f82b94 Git for Windows で日本語を使いたい #Vim - Qiita] | ||
git config --global | git config --global gui.encoding utf-8 | ||
git config --global | git config --global core.quotepath false | ||
==== core.editor ==== | |||
* [https://qiita.com/AX2DdNTkgzNx/items/91ebb5b428dfb88f41a5 defaultがNanoでVimに変えた話 #Git - Qiita] | |||
* [https://qiita.com/pyon_kiti_jp/items/e4963d84585dffc7716d gitのデフォルトエディタをnanoからviに変更 #Git - Qiita] | |||
git commitなどで使用するデフォルトのエディター設定。 | |||
以下の優先順位になっている。 | |||
* core.editor | |||
* VISUAL環境変数 | |||
* EDITOR環境変数 | |||
* システムデフォルト | |||
- | core.editorを指定するのがいい。 | ||
git config --global core.editor vi | |||
=== | ==== proxy ==== | ||
PROXY=<nowiki>http://example.com:8080</nowiki> | |||
git config --global http.proxy $PROXY | |||
git config --global https.proxy $PROXY | |||
git config --global url."https://".insteadOf git:// | |||
=== gitignore === | ==== gitignore ==== | ||
[https://git-scm.com/docs/gitignore Git - gitignore Documentation] | [https://git-scm.com/docs/gitignore Git - gitignore Documentation] | ||
| 362行目: | 653行目: | ||
これで指定していないと、git addすると管理対象に入るし、untracked fileで表示が出る。git add .やディレクトリー指定で一括で管理したい場合に混ざっていると邪魔。 | これで指定していないと、git addすると管理対象に入るし、untracked fileで表示が出る。git add .やディレクトリー指定で一括で管理したい場合に混ざっていると邪魔。 | ||
==== File ==== | ===== File ===== | ||
* .gitignore: ディレクトリー内。 | * .gitignore: ディレクトリー内。 | ||
* $GIT_DIR/info/exclude: リポジトリー固有のローカル。 | * $GIT_DIR/info/exclude: リポジトリー固有のローカル。 | ||
* core.excludesFile: ~/.gitconfig内で指定するgitignoreファイル。通常、$XDG_CONFIG_HOME/git/ignoreか$HOME/.config/git/ignore。 | * core.excludesFile: ~/.gitconfig内で指定するgitignoreファイル。通常、$XDG_CONFIG_HOME/git/ignoreか$HOME/.config/git/ignore。 | ||
==== Format ==== | ===== Format ===== | ||
記述方法を整理する。 | 記述方法を整理する。 | ||
| 397行目: | 687行目: | ||
## /foo/* | ## /foo/* | ||
## !/foo/bar | ## !/foo/bar | ||
==== 空ディレクトリーの維持 ==== | |||
===== 空ディレクトリーの維持 ===== | |||
[https://stackoverflow.com/questions/115983/how-do-i-add-an-empty-directory-to-a-git-repository How do I add an empty directory to a Git repository? - Stack Overflow] | [https://stackoverflow.com/questions/115983/how-do-i-add-an-empty-directory-to-a-git-repository How do I add an empty directory to a Git repository? - Stack Overflow] | ||
| 403行目: | 694行目: | ||
logなど維持したい空ディレクトリーに、以下の内容の.gitignoreを置く。 | logなど維持したい空ディレクトリーに、以下の内容の.gitignoreを置く。 | ||
* | |||
!.gitignore | !.gitignore | ||
.gitignore以外を無視する。これで.gitignoreのみがあるので管理できる。 | .gitignore以外を無視する。これで.gitignoreのみがあるので管理できる。 | ||
==== 指定ファイルのみ除外 ==== | ===== 指定ファイルのみ除外 ===== | ||
!.gitignore | !.gitignore | ||
ディレクトリーを残す以外 (.gitignore1ファイル以外) に、サンプルファイルなど複数ファイルを残したい場合は、上記のように*で最初に全部除外して指定ファイルのみ含める。/は必要に応じてつける。 | ディレクトリーを残す以外 (.gitignore1ファイル以外) に、サンプルファイルなど複数ファイルを残したい場合は、上記のように*で最初に全部除外して指定ファイルのみ含める。/は必要に応じてつける。 | ||
| 431行目: | 720行目: | ||
* delta | * delta | ||
* encoding | * encoding | ||
=== Git hook === | === Git hook === | ||
| 471行目: | 754行目: | ||
== Other == | == Other == | ||
=== submodule === | === submodule === | ||
| 537行目: | 799行目: | ||
** git-completion.bash | ** git-completion.bash | ||
** git-prompt.sh | ** git-prompt.sh | ||
=== 復元 === | |||
[https://qiita.com/generosity-naman/items/237338f8fe5b7e3b9a76 Git Stashの復元: 誤って削除されたスタッシュの復元方法 #Git-Stash - Qiita] | |||
git stash drop実行時に、削除したコミットのSHA1が表示される。 | |||
そのSHA1をapplyで指定すれば、取り込める。 | |||
git stash apply [stash_hash] | |||
=== 改名と修正 === | |||
* [https://qiita.com/yukimura1227/items/fbb076db61a2e43a32e3 gitでrename&modifyしたファイルのログを追跡できるようにしたい場合 #Git - Qiita] | |||
* [https://zenn.dev/yoichi/articles/how-git-handles-renaming Gitはファイルのリネームをどう扱うか] | |||
改名と修正を同時にすると、改名を検知できない。 | |||
-Mオプションを指定すると、類似度で同時も検知できる。が、基本はリネーム・改名と修正は別コミットにしたほうがよさそう。 | |||
=== squash === | |||
squashすると、squash対象コミットが、対象の直前のコミットに含められる。 | |||
=== ファイルのインデックスのみ削除 === | |||
git rmは単独だと、gitの履歴とローカルファイルからも削除する。追跡対象から削除のみで、ローカルファイルとして残したい場合、--cachedを指定する。 | |||
git rm --cached | |||
== Remote == | |||
=== リモート === | |||
[https://qiita.com/mather314/items/a1536c52a2eb0426b2b5 gitの不要なブランチを消すコマンド #Git - Qiita] git fetch -p/--prune リモートの削除済みブランチをローカルに同期する。 | |||
=== リモートの最新タグ === | |||
https:/stackoverflow.com/questions/20734181/how-to-get-list-of-latest-tags-in-remote-git | |||
git ls-remote --tag --sort=taggerdate | |||
date関係のsortはオブジェクトへのアクセスが必要なので、ローカルにないとダメとか。 | |||
https:/git-scm.com/docs/git-ls-remote.html | |||
https:/stackoverflow.com/questions/10649814/get-last-git-tag-from-a-remote-repo-without-cloning | |||
git rev-listでいけそう。 | |||
https:/gist.github.com/rponte/fdc0724dd984088606b0 | |||
=== push時リモートブランチ作成 === | |||
$ git push | |||
fatal: The current branch branch has no upstream branch. | |||
To push the current branch and set the remote as upstream, use | |||
git push --set-upstream origin branch | |||
To have this happen automatically for branches without a tracking | |||
upstream, see 'push.autoSetupRemote' in 'git help config'. | |||
$ git config --global push.autoSetupRemote true | |||
デフォルトだとgit push -t origin branchなどのように、リモートブランチを明示する必要がある。が、リモートとローカルのブランチ名は同じことがほとんど。 | |||
push.autoSetupRemoteの設定があると、ローカルのブランチ名でリモートブランチも作ってくれる模様。昔はこういうオプションなかった気がする。 | |||
2025年10月30日 (木) 15:47時点における最新版
Host
GitHub
Account
Username may only contain alphanumeric characters or single hyphens, and cannot begin or end with a hyphen. ユーザー名は、英数字と-のみが使用可能。
組織別にアカウントを分けるなら、かぶらないように末尾に-組織名のようなサフィックスがあるとよいだろう。
README
https://chatgpt.com/c/6779ea86-96e4-800b-ba81-eeca2793d397
GitHubではREADME系ファイルを描画表示してくれる。READMEとREADME.*が対象。index.html系はだめ。
PR+issue
Pull Request。第三者の修正を、本体側でgit pull (取り込む) ことのリクエスト・要請。
PR後のブランチ更新
PR作成後にブランチの内容を更新する場合は注意が必要。
マージ元ブランチはPR作成時のバージョンで固定される。マージ元とマージ先の両方にたとえばdevelopなどの共通の修正を取り込んだ場合、GitHubの画面でマージ元ブランチも選択し直して、参照バージョンを更新しておく。
そうしないと、マージ先だけ反映されてしまって、想定していない差分が大量に表示される。
PR後のブランチ名変更
できない。ブランチ名を変更すると、別のPRにするしかない。
git - Renaming a branch while on pull request - Stack Overflow
Web UIでの編集
素人の私でもわかる「Webブラウザだけでgithubのプルリクをする方法」 #GitHub - Qiita
他の人のリポジトリーで修正箇所を見つけたら、そのファイルの編集ボタンで編集して、ボタン操作で自動でフォークしてPRを作れる。
レビュー指摘が来た場合、自分の該当ブランチを開いて、編集したらそのままコミットできる。
1ファイル1コミットの場合、Web UIで完結できる。修正が少ない場合、悪くない。
範囲選択
プルリクエストで提案された変更をレビューする - GitHub Docs
[Pull requests]-[File changed] で変更ファイルについてコメントする形でレビューする。
この際、行部分をドラッグすると、行を指定してブロックでコメントできる。
ファイル自体にコメントするには、右上のコメントマーク。
マージ後修正
GitHubでMerge済みのPull requestにCommitを追加して再度Mergeできるのか確認してみた | DevelopersIO
一度マージされたら、同じブランチに追加コミットしても、再マージはできない。
PRの作成が必要。
マージロック
右上の [Reviewers] のところの [Convert to draft] で下書きにできる。この状態だとマージ不能になる。
一番下の [No conflicts with base branch] あたりの [ready for review] で元に戻せる。
リモートブランチ削除後復元
pull request 中のブランチの削除と復元 - GitHub Docs
マージ済みブランチの整理中に間違えて、削除してしまった。
リモートブランチを削除すると、PRがあったらclosedになる。
復元するには以下の手順を取る。
- 元ブランチを復元
- PR一覧画面を出してチェックしてステータス変更
添付ファイルの削除
GitHubのIssueやPull requestsにアップロードした画像の削除 - Coincheck Tech Blog
issue+pull requestに添付したファイルは、外部のアップローダーを使っており、URLは公開されている。
削除は専用フォームから依頼が必要で面倒。
アップロードは注意する。
Other
remote: Support for password authentication was removed on August 13, 2021.
git pushすると以下のようなエラーが出る。
remote: Support for password authentication was removed on August 13, 2021. remote: Please see https://docs.github.com/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication. fatal: Authentication failed for 'https://github.com/senooken/dotfile/'
2021-08-13からパスワード認証が使用不能になった。
アクセストークンを使う。
「個人用アクセス トークンを管理する - GitHub Docs」に設定方法がある。
必要な権限が明記されていなくてややこしい。
https://chatgpt.com/share/682ac434-8598-800b-aaad-de73b48a337d
[Fine-grained tokens]と[Classic token]とで違う。
- [Settings]-[Developer settings]-[Personal access token]
- Tokens (classic) (https://github.com/settings/tokens)-[Generate new token]
- ☑️ repo
- [Fine-grained tokens] (https://github.com/settings/personal-access-tokens) -[Generate new token]
- Repository access: ◉ All repositories
- Permissions
- Account Repository permissions:
- Contents=Read and write
- Account Repository permissions:
これで生成されたパスワードを入力すればOK。
WSLに認証情報保存
Git Credential Manager (GCM) でGithubへの認証をセキュアに実現する (Windows, WSL2, Linux) – Portablecode.info
Githubにpush/pullしようとすると、通常であれば、認証マネージャーが起動して、そこの認証情報を流用してくれる。ただ、WSLを使っている場合、設定が必要。
Git for Windowsをインストールしていれば、それに同梱されている。パスの設定だけ行う。
git config --global credential.helper "/mnt/c/Program\ Files/Git/mingw64/bin/git-credential-manager.exe"
Server
Gitで自前のサーバー、リモートリポジトリーを設置する方法がある。
いくつか考慮事項がある。どのプロトコルを使うかが重要。
https://grok.com/share/c2hhcmQtMw%3D%3D_2b4fcc61-0d45-4d12-abac-6b29246b3716
基本事項として、あくまでgitサーバーはリポジトリー機能のみの提供。Web表示は別。
閲覧には、gitweb/cigt/tracなどの別ソフトを使う。
リポジトリー機能+閲覧を一緒にやりたければ、gitlab/phorgeとか専用のソフトが必要。だけど、VPSが必要になる。
CGIの範囲で、レンタルサーバーで完結させたければ、git server+tracのような組み合わせがほぼ必須。
プロトコル
Gitサーバーを設置する際、プロトコルに応じて、方法が大きく異なる。
- Local: リモートリポジトリーを全員がアクセス可能なディスク上に配置。file://でアクセス。
- HTTP: HTTPを使う方法。一般的。ただ、v1.6.5までは読取だけだった。v1.6.6からSmart HTTPが登場して、書き込みも可能になった。
- SSH: 匿名アクセス不能。読込専用でも。自分専用。非公開。
- Git: 最高速。ただし、認証の仕組みがない。独自のデーモンが必要で用意が大変。
Smart HTTPほぼ一択。
サーバー用Gitの取得
Gitサーバー用のリポジトリーを用意する。基本は既存のGitリポジトリーだが、サーバー用に作業ファイルのないリポジトリーにする。
既存リポジトリーをエクスポートして作成する。git clone --baseで他のローカルgitリポジトリーから作る。
$ git clone --bare my_project my_project.git
このコマンドはおおざっぱには以下のコマンドと同じ。
$ cp -Rf my_project/.git my_project.git
Smart HTTP
Smart HTTPによる設置方法。基本はGit付属のCGIスクリプトとサーバー、認証設定のみ。
git-http-backendスクリプトを使う。
Model
Apache HTTP Serverでの設置手順の場合。
mod_cgi/mod_alias/mod_env/mod_rewriteを有効にする。
$ sudo apt-get install apache2 apache2-utils $ a2enmod cgi alias env rewrite
gitの管理ルートディレクトリー (例: /opt/git) をwww-dataのグループに変更して、httpdから読書可能にする。
$ chgrp -R www-data /opt/git
/gitパスアクセス時に、git-http-backendを割り当てる。
SetEnv GIT_PROJECT_ROOT /opt/git SetEnv GIT_HTTP_EXPORT_ALL ScriptAlias /git/ /usr/lib/git-core/git-http-backend/
他に、GIT_PROJECT_ROOTでgitの管理ルートディレクトリーを設定。GIT_HTTP_EXPORT_ALLを設定して、書き込み可能にする。これを設定しない場合、クライアントからは読込専用で、git-daemon-export-okファイルが保存されたリポジトリーのみ (git daemonと同じ挙動)。
最後にgit-http-backendへのアクセス許可の設定と、書き込み認証を設定する。
RewriteEngine On
RewriteCond %{QUERY_STRING} service=git-receive-pack [OR]
RewriteCond %{REQUEST_URI} /git-receive-pack$
RewriteRule ^/git/ - [E=AUTHREQUIRED]
<Files "git-http-backend">
AuthType Basic
AuthName "Git Access"
AuthUserFile /opt/git/.htpasswd
Require valid-user
Order deny,allow
Deny from env=AUTHREQUIRED
Satisfy any
</Files>
order/deny/satisfyを使わない場合、以下だと思う。
RewriteEngine On
RewriteCond %{QUERY_STRING} service=git-receive-pack [OR]
RewriteCond %{REQUEST_URI} /git-receive-pack$
RewriteRule ^/git/ - [E=AUTHREQUIRED]
<Files "git-http-backend">
AuthType Basic
AuthName "Git Access"
AuthUserFile /opt/git/.htpasswd
Require valid-user
Require not env AUTHREQUIRED
</Files>
これの意味。git push時 (service=git-receive-pack /git-receive-pack) はパスワード認証が必要だが、それ以外はパスワード不要 (require not envにマッチ) という意味 (https://grok.com/share/c2hhcmQtMw%3D%3D_826f3cbf-b07d-434a-a573-a921b8eee6ea)。
さらに、対象ユーザー全員のパスワードが記述された.htaccessファイルを用意。ユーザーschaconを追加する場合以下を実行する。
$ htpasswd -c /opt/git/.htpasswd schacon
https://grok.com/share/c2hhcmQtMw%3D%3D_059bbb94-5e7b-4f02-99bb-1303b51d62a9
Digest認証もできるが、複雑になるだけで、あまり意味がないのでBasic認証でやるのがよさそう。
git-receive-packがいきなり登場して混乱した。このパスはgit push時に使っている模様。
git pushすると以下を通信して、リモートリポジトリーに書き込む模様。
- GET /push-test.git/info/refs?service=git-receive-pack
- POST /push-test.git/git-receive-pack
なので、これらのパスへのアクセスに認証をかけている模様。
Gitolite
About
- https://grok.com/share/c2hhcmQtMw%3D%3D_461ea368-264f-4d96-b203-fdd120722ec6
- https://grok.com/share/c2hhcmQtMw%3D%3D_270a9b75-83a8-47d9-ade9-d3b1d8a44b41
- Gitolite · git
- Gitolite
git-http-backendを使う場合、apacheのbasic認証を使う。と、アカウント管理が面倒になる。
gitoliteを使うとそのあたりカバーされるらしい。基本はsshだけど、httpでもできるとか。
gitolite-admin.gitという、専用のgitリポジトリーで管理しているとか。
Auth
ただ、gitoliteはもともとSSH前提。HTTPもいけるがその場合apacheのbasic認証との併用で、basic認証のユーザーとsshのユーザーが対応している。
その都合、basic認証とssh認証の二重管理が必要。アカウント管理を楽にしたかったのに、二重管理になってしまい本末転倒。やっぱり、git-http-backend+apacheで構築するのがベスト。
アカウント管理が必要なら、自分で管理用のツール・スクリプトを作ったほうがよさそう。
https://grok.com/share/c2hhcmQtMw%3D%3D_e86d9e67-edfa-4a60-88f4-6537a0b06742
あるいは、自作するほかに、oauthやldapの外部認証を使う方法がある。外部認証でいけるなら、これが確実かも。ただ、この外部認証を自分でホストする必要があって、今の段階だとこれを考えるのが面倒くさい。当面は手動管理でいく。
Install
View
log
- 逆順表示: --reverse
- 差分表示: -p
Other
親コミットの参照
Gitは自分より後ろ (新しい) コミットは参照しやすいが、その逆の先祖の履歴は参照しにくい。なくはない。
^Nと~Nで対象コミットのN番目の親コミットを参照できる。これで一応辿れる。
gitrevisions
Git - gitrevisions Documentation
Gitでは多くの方法でコミット (<rev>) を参照できる。
| 種類 | 例 | 説明 |
|---|---|---|
| <sha1> | dae86e1950b1277e545cee180551750029cfe735 dae86e | SHA!-1オブジェクト (40バイトの16進数)、またはリポジトリー内で一意の先頭部分文字列。 |
| <describeOutput> | v1.7.4.2-679-g3bee7fb | git describeの出力。タグ名など |
| <refname> | master、heads/master、refs/heads/master | シンボリック参照名。 |
refname
refnameはいろいろある。
diff
差分無視
git diffの--ignoreオプションにおけるスペース、タブ、改行の扱いを理解する #Git - Qiita
-wでインデント違いを無視してくれる。
差分ファイル抽出
情報源: gitで差分ファイルを抽出する #Git - Qiita。
git archiveとgit diffを組み合わせる。 git archive --format=zip --prefix=root/ HEAD `git diff --diff-filter=d --name-only HEAD^ HEAD` -o archive.zip ただし、この方法はファイル数がARG_MAX以下の場合だけ。ファイル数が多い場合だめ。
git diff --name-onlyで一覧を出力させて、1個ずつcp -pで階層を維持してコピーするしかないかも?
例:
mkdir -p archive
git diff --name-only new_base 44765_upgrade-base-version | xargs -i cp -p --parent "{}" archive/
オプション
差分ファイル一覧を出力するオプションがいくつかある。
- -z: 異常な文字があったときの扱い用。ファイルの区切りをNULにする。
- --name-only: ファイル名一覧。
- --name-status: ファイル名一覧+ステータス。
- --diff-filter=ACDMRTUXB: 差分表示のファイルを絞り込む。A=Added, C=Copied, D=Deleted=, M=Modified, R=Renamed, T=Type changed, U=Unmerged, X=Unkonwn, B=Broken, *=All。小文字にすると、除外 (ブラックリスト) になる。--diff-filter=ACMを覚えておくと、チェックで便利そう。
- --cached/--staged: git addした後のステージングのファイルと最新コミットを比較する。このオプションをつけない場合、git addしていない作業ファイルと最新コミットの比較になって、ステージングは除外される。--stagedは--cachedの別名だが、こちらのほうが覚えやすい。
Commit
コミットオプション
Git - git-commit Documentation
コミットメッセージ指定のためのオプションがある。
- -m|--message <message>: コミットを文字列で指定。複数指定可能で、その場合段落で区切ってくれる。2行目以後を書きたい場合などで使う。
- -C|--reuse-message <commit>: 指定したコミットのコミット情報を再使用する。
- -c|--reedit-message <commit>: -Cの同じだが、編集画面を表示してコミットメッセージを編集して再使用する。
- -F|--file=<file>: 指定したファイルをコミットメッセージに使う。-を指定すると標準入力を使う。
基本は-m。-mの複数指定。
過去コミットのメールアドレスの変更
- How can I change the author (name / email) of a commit? | Learn Version Control with Git
- Gitのcommitの名前やメールアドレスを過去からまとめて変更する
単一コミットのメールアドレスを指定する場合、commitに--authorを指定する。 git commit --author="John Doe <john@doe.org>" --amendと併用することで、過去コミットも変更できる。
数が少ないなら、rebase -iで1個ずつamendする。数が多いならfilter-branch。
第一コミットの変更
- [Git 最初のコミットを含めてrebase -iする方法 | DevelopersIO]
- Git - git-rebase Documentation
通常、第一コミットはammend以外では変更できない。
rebase --root [branch] でブランチの第一コミットも参照して改変可能。
ファイルを間違えて追加してしまった場合は、git rm -r --cached で削除してコミットし直せばいい。
コミットログの文字化け
Git コミットログの文字化けではまる - wadahiroの日記
git commitやgit commi --amend実行時のコミットログがgit logで文字化けすることがある。
これは、git commit時に実行しているテキストエディター (vim) の文字エンコーディング設定が由来の可能性が高い。
gitはデフォルトでutf-8なので、以下のような内容を~/.vimrcに書いておいて、utf-8にしておけば解消する。
"" Encoding
set encoding=utf-8
set fileencodings=ucs-bom,iso-2022-jp,utf-8,euc-jp,cp932,cp1252
set fileformats=unix,dos,mac
augroup main
autocmd!
augroup END
"" Fix 'fileencoding' to use 'encoding' if the buffer only ASCII characters.
autocmd main BufReadPost *
\ if &modifiable && !search('[^\x00-\x7F]', 'cnw')
\ | setlocal fileencoding=utf-8
\ | endif
コミット同士の比較
コマンドで綺麗にはできない。git diffはブランチ同士の比較でコミット以外の過去の状態も比較する。
コミット同士で比較するなら、git showの出力結果をファイルに出力してdiff -uで比較するしかない。
git show sha1 >old.diff git show sha1 >new.diff diff -u old.diff new.diff
別のディレクトリーへの修正適用
https://chatgpt.com/c/67bea3ff-56c4-800b-ae92-d40299ad5ade
あるディレクトリーに適用した修正を、ルートのディレクトリー名だけが異なる別ファイルに適用したいことがある。
修正内容の差分をgit format-patch/git diff/git showでファイルに出力して、ファイル内のパスを変更して、そのファイルを使ってgit applyするとうまく取り込める。
add
gitでファイルを管理下のステージングに追加する方法がいくつかある。
- git add -A: リポジトリーツリーの、新規、削除、修正を全て取り込む。
- git add .: 現在ディレクトリー以下。削除は無視される。
git add -Aとgit add .はほぼ同じ。Git 2.0以降ではgit add -Aがデフォルトになっているらしい (https://chatgpt.com/c/67f4e2c7-a240-800b-8084-9650ef61a47e)。
ammendの打消し
間違えて実行したgit commit --amendを元に戻す方法 #Git - Qiita
git commit -amendを取り消すorキャンセルする方法 - まさかろぐ
コミット中に間違いに気づいた場合、コミットメッセージの入力中に、メッセージを空にすると中断できる。
git reset --soft HEAD@{1}
これで直前のコミットの状態に戻せる。あるいは、git reflogで修正前のコミットを探すとか。
branch
Git - git-branch Documentation
先頭アスタリスクの除去
git branch - List all local git branches without an asterisk - Stack Overflow
git branchを実行すると現在ブランチの先頭に*のアスタリスクのマークがつく。これが邪魔。git branch -rだとつかない。除去したい。
あまりいい方法はない。
git for-each-ref --format='%(refname:short)' refs/heads/ git branch --format='%(refname:short)' git branch | cut -c 3-
2番目の方法が綺麗。
誤ったブランチへのコミットの付け直し
- [初心者向け Gitで間違ったブランチにしたコミットを別ブランチに付け替える | DevelopersIO]
- [Git誤ったブランチで実施した変更を正しいブランチに移動する | DevelopersIO]
ブランチを変えずに作業していて、コミット量が増えたので、別ブランチにしておけばよかったということがあったりする。
いくつか方法がある。
- cherry-pickで変更コミットだけ別ブランチに抽出。
- git checkoutとreset --hardで分離: 現在の状態を一旦別ブランチにしてコピー。その後、元ブランチはgit reset --hardで打ち消す。
- git rebase --onto <別ブランチ> 起点コミット でコミットを付け替えて、ブランチを削除、改名して元のブランチの名前にする。付け替え場、起点コミットで元のベースブランチにする。
git rebase --ontoがきれい。
他のブランチとの同一化
git diff HEAD master | patch -p 1
patchの他にgit applyでもいい。
remote
リモートトラッキングブランチという概念。
gitのpush/pull時の対象リモートリポジトリーのブランチのローカルの対応ブランチ。リモートブランチのデータのローカルの管理用。
- git branch -u|--set-upstream-to <upstream>: リモートトラッキングブランチを指定。
- git branch --unset-upstream: 設定済みのリモートトラッキングブランチの対応を解除。
マージ済みブランチの一括削除
放置すると、マージ済みブランチが残る。うざい。
2個目の記事が特に良かった。
基本的な考え方がいくつかある。
## ローカルブランチの削除 git branch -d <branch> ## リモートブランチの削除 git push -d origin <branch> ## 削除済みリモートブランチの、リモートトラッキングブランチの削除 git fetch -p ## マージ済みローカルブランチの一覧 git branch --merged[=origin/develop] ## マージ済み全ブランチの一覧 git branch --merged[=origin/develop] -r
ローカルブランチの場合、git branch --mergedの一覧に対して、git branch -d を実行していくイメージ。ついでに、git push -dもしてもいいかも。
ただし、main/master/developなど削除から除外したいブランチはあるだろう。
git branch --mergedには引数を指定可能で、マージ先のブランチを指定できる。これを指定しないと、途中の集約用ブランチへのマージもマージ済みと認識されるので、必須だろう。
git branch -rでリモートブランチもリストに含められる。
これらを組み合わせてシェルスクリプトを作る。
## ローカルブランチのローカル・リモートの一括削除
git branch --format='%(refname:short)' --merged origin/develop |
grep -v -e '^master' -e '^main' -e '^develop' |
xargs -I {} sh -c 'git branch -d {} && git push -d origin {}'
## リモートブランチの一括削除
git branch --format='%(refname:short)' --merged origin/develop -r |
grep -v -e '^origin/master' -e '^origin/main' -e '^origin/develop' |
sed 's@^origin/@@' |
xargs -I {} sh -c 'git branch -d {} ; git push -d origin {}'
Merge
rebase時のマージコミット維持
git rebase -iはマージコミットを削除してしまう。マージコミットを残したいなら、-rを指定する。昔は-pだった。
-rを忘れてしまった場合、git reflogでリベース前のコミットを探してgit reset --hardでそのコミットに戻してからやり直す。
マージコミット後のコミット追加
マージコミット後に次の開発作業を始めることが多い。が、直後の初回のコミットを追加したい場合困る。
git rebase -iにすると、コミットが残るから。編集はできるが、その直前にコミットの追加ができない。マージコミットは扱いが特殊で直接rebaseで編集できない。
しかたないので、該当コミットでブランチを作成して、コミット。その後、既存の修正ブランチをrebaseでそのコミットの後にくっつける。これでいける。
マージコミットの打ち消し
マージコミットは扱いがやや特殊。
git revert -m 1 マージコミット git reset --hard HEAD~1 # マージコミット前
どちらか。
https://chatgpt.com/c/679983bc-a96c-800b-9d8c-a15873d1d068
git revert -mは1か2の数字を指定する。これは、マージはマージ元とマージ先の親ブランチが2個あり、どちらを基準にリバートするかを指定するためにある。
基本はマージ元 (mainやdevelopブランチ) の1を指定する。マージ先のfeatureブランチは2だがこちらを指定することはあまないだろう。
git checkoutなしのmerge
- https://chatgpt.com/c/677f6038-4fa8-800b-9efb-fae4d2a4ab91
- checkoutせずにmergeする #Git - Qiita
- Merge, update, and pull Git branches without using checkouts - Stack Overflow
- Merging Branches Without Checkout (Example)
gitでブランチをマージする場合、基本はマージの取り込み元ブランチに移動してから、対象ブランチを取り込む必要がある。
これは、3wayマージなどのために、マージの元ファイルが必要だからとのこと。
ただ、毎回切り替えるのが面倒くさい。ブランチ同士でのマージが一応可能。
git fetch . src:dst
ただし、このコマンドはfast-fowardsマージの場合だけ。rebase相当。それ以外は上書きされるので、手動マージが必要。注意が必要。
スクリプトの自動処理などで使う感じ。
cherry-pick後のmergeで重複コミット
github - Git でCherry-pick 後に Mergeすると同じCommitの履歴が複数できてしまう - スタック・オーバーフロー
ブランチが2個あって、ブランチでコミット・pushした後、間違えたブランチだと気づいて、別ブランチでcherry-pick。その後、ブランチの内容を取り込むためにまたmergeしたら、cherry-pickのコミットのマージができる。
コミット履歴が残っているから、それを素直に取り込んだだけで、残るのは仕方ない。rebaseやreset --hardで消すしかないが、pushしているから、一人とかじゃないとだめ。
重複コミットは諦めるしかない。
マージコミット前後の比較
MC=cf128108e43b0d614528d2ab04fc9fa4188761e1
git diff ${MC}~ $MC
~でマージコミットの1個前のコミットを参照して差分をとればいい。
git merge --no-ff
https://chatgpt.com/c/67ec9d0c-5cd0-800b-80f3-7905e157fa9f
git mergeすると、デフォルトでfast forwardになる。マージコミットがなくて、履歴は綺麗になる。が、どのブランチがどのタイミングでマージされたかが、履歴でわかりにくい。
基本は機能ブランチ (feature branch) のマージでは、--no-ffを使う。こうすることで、いつマージされたかが明確になる。
Customize
Git config
.netrc
https://social.senooken.jp/conversation/1573147#notice-2217499
Gitのパスワード入力の省略方法に~/.netrcがある。
しかし、man netrcするとわかるけど、これはもともとFTPのためのもの。なぜGitで使えるんだ?Gitの文書で言及がない。
In conversation Thursday, 21-Feb-2019 10:58:47 JST from web permalink
せのお (妹尾 賢)せのお (妹尾 賢) in reply to
理由が分かった。
1. Gitはhttpとhttpsの通信にcURLを使っている。
https://github.com/git/git/blob/master/INSTALL#L141
2. cURLが.netrcにも対応しているから。
https://ec.haxx.se/usingcurl-netrc.html
core.autocrlf
warning: in the working copy of 'docker/README.md', LF will be replaced by CRLF the next time Git touches it
Windowsでは改行にCR+LFを使うが、mac/LinuxはLFのみ。これの違いの処理のための設定がcore.autoclrlf
- true=コミット時にCRLFをLFに自動変換。チェックアウト時に逆。Windows向けの設定。
- false=変換しない。
- input=コミット時にCRLFをLFに自動変換のみ。mac/Linux向け。Windowsではチェックアウト時にCRLFになるが、mac/LinuxはLFになる。
わかりにくい。基本はfalseで良いと思われる。
gitkの文字化け対策
gitkのエンコーディングを設定する - Pistolfly
gitkはシステムのデフォルトエンコーディングで表示しようとするので、文字エンコーディングを指定しておく。
git config --global gui.encoding utf-8
WSLなどで、日本語が表示されない場合、フォントが入っていない可能性が高い。
以下のコマンドで日本語対応フォントをインストールする。
sudo apt install -y fonts-noto-cjk fonts-noto-cjk-extra fonts-ipafont
ファイル名などの文字化け対策
Git for Windows で日本語を使いたい #Vim - Qiita
git config --global gui.encoding utf-8 git config --global core.quotepath false
core.editor
git commitなどで使用するデフォルトのエディター設定。
以下の優先順位になっている。
- core.editor
- VISUAL環境変数
- EDITOR環境変数
- システムデフォルト
core.editorを指定するのがいい。
git config --global core.editor vi
proxy
PROXY=http://example.com:8080 git config --global http.proxy $PROXY git config --global https.proxy $PROXY git config --global url."https://".insteadOf git://
gitignore
gitの管理対象外のファイル。ログや一時ファイルなど。
これで指定していないと、git addすると管理対象に入るし、untracked fileで表示が出る。git add .やディレクトリー指定で一括で管理したい場合に混ざっていると邪魔。
File
- .gitignore: ディレクトリー内。
- $GIT_DIR/info/exclude: リポジトリー固有のローカル。
- core.excludesFile: ~/.gitconfig内で指定するgitignoreファイル。通常、$XDG_CONFIG_HOME/git/ignoreか$HOME/.config/git/ignore。
Format
記述方法を整理する。
- 空行は無視。
- #始まりの行はコメント扱い。
- 終端スペースは無視。
- !接頭辞はパターン否定。つまり、除外ではなく含める。以前除外された一致を再び含める。ただし、親ディレクトリーが除外されている場合、以下のファイルは含められない。パフォーマンス上の理由。順番に注意する。
- /はディレクトリー区切りとして使用。先頭、中間、末尾で登場する。
- 先頭と中間の/は相対パスを意味する。
- それ以外、末尾の/と/なしの場合、現在以下のディレクトリーにもマッチする。
- 末尾が/で終わる場合、ディレクトリーのみに一致。/がない場合、ディレクトリーとファイルの両方に一致。
- *は/以外にマッチ。?は/以外の任意の1文字にマッチ。[a-zA-Z] の範囲記法も使用可能。fnmatch(3) FNM_PATHNAMEフラグのパス名展開に準じる。
- **は特殊な意味がある。
- **/=全ディレクトリー。**/fooは配下の全fooにマッチ。**/foo/barはfoo以下の全barにマッチ。
- /**=配下のすべてにマッチ。
- a/**/b=a/b a/x/b a/x/y/bのすべてにマッチ。
後は特に明記がないが、上から順番に評価されて、最後のマッチが優先されるので、記述の順番に注意する。
反転の!と/の扱いに特に注意が必要。
先頭スラッシュをつけないと、再帰的になる。
$ cat .gitignore
- ディレクトリ foo/bar 以外のすべてを除外
- /*
- !/foo
- /foo/*
- !/foo/bar
空ディレクトリーの維持
How do I add an empty directory to a Git repository? - Stack Overflow
gitは空ディレクトリーを履歴管理できない。何かファイルが必要。
logなど維持したい空ディレクトリーに、以下の内容の.gitignoreを置く。
* !.gitignore
.gitignore以外を無視する。これで.gitignoreのみがあるので管理できる。
指定ファイルのみ除外
!.gitignore ディレクトリーを残す以外 (.gitignore1ファイル以外) に、サンプルファイルなど複数ファイルを残したい場合は、上記のように*で最初に全部除外して指定ファイルのみ含める。/は必要に応じてつける。
gitattributes
Git - gitattributes Documentation
gitignoreに似ていて、パターンにマッチしたパスに対する設定を行える。
- text
- eol
- working-tree-encoding
- ident
- filter
- diff
- merge
- conflict-marker-size
- whitespace
- export-ignore: git archiveなどに含めないことをマーク。
- export-subst
- delta
- encoding
Git hook
特定アクションでカスタムスクリプトを実行する仕組み (hook) がある。クライアントとサーバーとで2のグループになる。クライアントサイドはコミット、マージなどの操作時、サーバーサイドはプッシュコミットの受け取り、ネットワーク操作時に実行される。テスト、リント、デプロイなどいろんな目的に使える。
フックをインストールする
フックはgitのhooksディレクトリー (.git/hooks) に格納されている。git initで同梱スクリプトのサンプル類がここに格納される。.git/hooksに実行可能なファイルを適切な名前 (pre-commit などの拡張子なしのフック名) で配置すれば、以降呼び出される。
クライアントサイドフック
クライアントサイドフックは、リポジトリーのクローン時にはコピーされない。フックを強制したい場合、クライアントサイドではなく、サーバーサイドで行う方がいい。
クライアントサイドフックは多くの種類がある。が、典型的なパターンが3種類ある。
- コミットワークフローフック
- Eメールワークフロースクリプト
- その他
コミットワークフローフック
- pre-commit: コミットメッセージの入力前に実行。コミット前の検査・確認目的で使用する。0以外の値を返すとコミットを中断する。ただし、git commit --no-verifyでスキップできる。静的解析にうってつけのフック。
hookの管理
https://chatgpt.com/c/67fe029c-9ce0-800b-9397-8e1d7f18b303
なお、git hooks自体はgitで管理されていない。プロジェクト内にhooksディレクトリーを配置して、内容を管理して、シンボリックリンクで配置したらいい。README.mdに配置方法を記載したらいい。専用コマンドでもいいけど、どうせ1行だし。
# hooks/pre-commit ln -fs ../../hooks/pre-commit .git/hooks/pre-commit
差分ファイル一覧
hookではコミット対象ファイルなどが変数に入ったりはしない。自分でgitコマンドの結果などで一覧などを取得して処理する。
## 削除以外の追加・修正ファイル git diff --staged --name-only --diff-filter=ACM
Other
submodule
https://git-scm.com/docs/git-submodule
foreach
サブモジュールの全部を一括処理する。 foreach [--recursive] <command> <command>部分では$sm_pathでパスを参照できる。 git submodule foreach 'echo $sm_path `git rev-parse HEAD`'
Entering 'XXX' XXX hash submoduleの中に入ってから実行することに注意する。
便利なコマンド。 git submodule foreach 'git reset --hard'
gitk
problem
ブランチ名が長いと、右クリックしにくい
clean
git未管理のファイルを削除するためのコマンド。間違えると復元不能なので注意する。
必ず-nで削除対象を確認してから、-nの本実行を試すこと。
-x/-Xでgitignoreによる無視ファイルも削除できる。
Mac
- /Library/Developer/CommandLineTools/usr/bin/git
- /Library/Developer/CommandLineTools/usr/libexec/git-core/
上記2箇所がMac標準のgit関係の格納場所。
特に重要な補完ツールは以下にある。
- /Library/Developer/CommandLineTools//usr/share/git-core/
- git-completion.tcsh
- git-completion.zsh
- git-completion.bash
- git-prompt.sh
復元
Git Stashの復元: 誤って削除されたスタッシュの復元方法 #Git-Stash - Qiita
git stash drop実行時に、削除したコミットのSHA1が表示される。
そのSHA1をapplyで指定すれば、取り込める。 git stash apply [stash_hash]
改名と修正
改名と修正を同時にすると、改名を検知できない。
-Mオプションを指定すると、類似度で同時も検知できる。が、基本はリネーム・改名と修正は別コミットにしたほうがよさそう。
squash
squashすると、squash対象コミットが、対象の直前のコミットに含められる。
ファイルのインデックスのみ削除
git rmは単独だと、gitの履歴とローカルファイルからも削除する。追跡対象から削除のみで、ローカルファイルとして残したい場合、--cachedを指定する。
git rm --cached
Remote
リモート
gitの不要なブランチを消すコマンド #Git - Qiita git fetch -p/--prune リモートの削除済みブランチをローカルに同期する。
リモートの最新タグ
https:/stackoverflow.com/questions/20734181/how-to-get-list-of-latest-tags-in-remote-git
git ls-remote --tag --sort=taggerdate
date関係のsortはオブジェクトへのアクセスが必要なので、ローカルにないとダメとか。
https:/git-scm.com/docs/git-ls-remote.html
https:/stackoverflow.com/questions/10649814/get-last-git-tag-from-a-remote-repo-without-cloning
git rev-listでいけそう。
https:/gist.github.com/rponte/fdc0724dd984088606b0
push時リモートブランチ作成
$ git push
fatal: The current branch branch has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin branch
To have this happen automatically for branches without a tracking
upstream, see 'push.autoSetupRemote' in 'git help config'.
$ git config --global push.autoSetupRemote true
デフォルトだとgit push -t origin branchなどのように、リモートブランチを明示する必要がある。が、リモートとローカルのブランチ名は同じことがほとんど。
push.autoSetupRemoteの設定があると、ローカルのブランチ名でリモートブランチも作ってくれる模様。昔はこういうオプションなかった気がする。
