🐙
Git再入門と運用検討
なんとなく使用していたGitを色々調べて自分なりに理解しました。Gitの基本的な構成要素と各コマンドが構成要素をどのように変化させるのかを理解することで、ある程度自分がやりたいことをコマンド群に変換することができるようになったと思います。
それと同時に普段使用する主なコマンドを取捨選択して余計なことを考えずに済むようにしました。そのための簡単な運用等も含めた備忘録です。
基本的な構成要素
- blobオブジェクト
- treeオブジェクト
- commitオブジェクト
- tagオブジェクト
- HEAD
- ブランチ
- リモート追跡ブランチ
- 作業ツリー (working directory, working tree, etc.)
- ステージ (staging area, index, cache, etc.)
- ローカルレポジトリ
- リモートレポジトリ
普段使うGitのフェーズ
以下の3つのフェーズに分けて考え、それぞれのフェーズで使用するコマンドを取捨選択する。
- コミットグラフのノード作成
- ファイル等の編集からコミットまでの作業
- コミットグラフの操作
- ブランチの移動やコミット同士のマージ等の作業
- リモートとのグラフ同期
- ローカルとリモートのリポジトリ同期作業
コミットグラフのノード作成
概要図
使用コマンド
- 編集
-
git add <TARGET_PATH>
: TARGET_PATHをステージに追加 -
git add -p <TARGET_PATH>
: TARGET_PATHの変更ブロック(hunk)を個別でステージに追加 -
git restore --staged <TARGET_PATH>
: TARGET_PATHをステージから削除 -
git restore <TARGET_PATH>
: 作業ツリーのTARGET_PATHをステージのTARGETに上書き -
git mv <SOURCE_PATH> <DESTINATION_PATH>
: 履歴を引き継いでファイル名変更/移動 -
git rm --cached -r <TARGET_PATH>
: TARGET_PATHを管理対象から除外 -
git commit -m "Commit message."
: ステージ内容をコミット -
git stash <SAVE_NAME>
: 作業ツリーとステージの内容を一時保存コミット -
git stash pop
: 一時保存コミットから作業ツリーとステージの内容を上書き
-
- 確認
-
git status -sb
: ステージ,未ステージ,管理外ファイルを表示 -
git diff
: 作業ツリーとステージの差分表示 -
git diff --name-only
: 作業ツリーとステージの差分ファイル表示 -
git diff --staged
: ステージとHEADの差分表示 -
git diff HEAD
: 作業ツリーとHEADの差分表示
-
詳細と備考
-
git add
時にblobオブジェクトが生成される -
git add
時にtreeオブジェクトファイルは生成されずindexファイルの中で管理される -
git commit
時にtree,commitオブジェクトが生成されハッシュが埋め込まれる - blobオブジェクトの実体はファイル名がハッシュのファイル
- 元のファイル名はtreeオブジェクトで管理されblobオブジェクトにはない
- treeオブジェクトはディレクトリに対応
- blobオブジェクトは差分ではなくスナップショットとして保持
- blobオブジェクトはzlibを用いて元のファイルを圧縮したファイル
- ハッシュの計算はSHA-1だが、近々SHA-256になっていく
- ファイル変更後の
git add
は変更ファイルのみblobオブジェクトが生成される - ファイル変更後のtreeオブジェクトは変更ファイルに関するもののみ生成される
- 対象ファイルのハッシュをポインタのようにして取り扱っている
-
git stash
はcommitオブジェクトが生成される - Git管理下ファイルを管理から除外する場合は以下コマンドを用いる
#---最初に.gitignoreに追記---# # 全てを管理対象から外した後に全てを対象に含める cd <PROJECT_DIR> git rm --cached -r . git add . git commit -m "Add ignored objects."
コミットグラフの操作
概要図
使用コマンド
- 編集
-
git branch <BRANCH_NAME>
: BRANCH_NAMEブランチを作成 -
git branch -d <BRANCH_NAME>
: BRANCH_NAMEブランチを削除 -
git branch --merged|egrep -v '\*|main'|xargs git branch -d
: マージ済ブランチ削除 -
git branch <NAME1> <NAME2>
: ブランチ名をNAME1からNAME2に変更 -
git switch <BRANCH_NAME>
: HEAD,ステージ,作業ツリーをNAMEブランチに変更 -
git reset --hard <COMMIT_ID>
: HEAD,ブランチ,ステージ,作業ツリーをCOMMIT_IDに変更 -
git reset --mixed <COMMIT_ID>
: HEAD,ブランチ,ステージをCOMMIT_IDに変更 -
git reset --soft <COMMIT_ID>
: HEAD,ブランチをCOMMIT_IDに変更-
git reset --soft HEAD^
: HEAD,ブランチを1つ前のコミットに変更
-
-
git checkout <COMMIT_ID>
: HEAD,ステージ,作業ツリーをCOMMIT_IDに変更- HEADのみを移動させるため基本的にdetached HEADになる
-
git revert <COMMIT_ID>
: COMMIT_IDを打消すコミットを生成 -
git merge <BRANCH_NAME>
: BRANCH_NAMEをHEADにマージ -
git tag <TAG_NAME> <COMMIT_ID>
: COMMIT_IDを指す軽量タグTAG_NAMEを作成 -
git tag -a <TAG_NAME> -m "Tag message."
: COMMIT_IDに注釈タグTAG_NAMEを作成
-
- 確認
-
git diff HEAD^
: HEADと直前コミットの差分表示 -
git log --all --oneline --graph
: コミットグラフ簡易表示 -
git show <COMMIT_ID>
: COMMIT_IDの内容表示 -
git tag -n
: タグ一覧表示 -
git describe
: HEADまでの最新の注釈タグ,何番目か,ハッシュ値を表示 -
git reflog
: 操作履歴表示
-
詳細と備考
- HEADはコミットグラフ上のカレントコミット(作業中のコミット)のイメージ
- ブランチはcommitオブジェクトを指すポインタ
- ブランチの実体はファイルとして存在する
- ブランチファイルの中にcommitオブジェクトのハッシュを保存
- HEADはブランチ又はコミットを指す特別なポインタ
- HEADの実体はファイルとして存在する
- ブランチ以外を指すHEADはdetached HEADと呼ぶ
- HEADがブランチを指す場合はブランチファイルのパスをHEADファイルに保存
- HEADがdetached HEADの場合はcommitオブジェクトのハッシュをHEADファイルに保存
- HEADの指し先を変更した時は基本的にステージ,作業ツリーも連動して変化する
- 軽量タグはブランチと同様コミットを指すポインタで本質的に同一
- 注釈タグはtagオブジェクトが生成される
- 注釈タグはcommitオブジェクト以外に対しても作成可能
- 注釈タグはリリース用途、軽量タグはローカル又は一時的な用途
- fast-forward mergeはブランチが存在したという情報が失われる
-
git reset
はHEADが指すブランチを移動させ、結果HEADも移動したように見える - commitオブジェクトは
git reset
でHEAD移動やgit revert
で打消しても消えない -
git reset
等で消えたと思っているcommitオブジェクトは宙に浮いたコミットとして残る- 宙に浮いたコミットのことをdangling commitと呼ぶ
- dangling commitはハッシュを指定してHEAD移動すれば参照可能
リモートとのグラフ同期
概要図
使用コマンド
- 編集
-
git remote add <REMOTE> <URI>
: URIをリモートリポジトリREMOTEとして登録 -
git push <REMOTE> <BRANCH_NAME>
: REMOTEにBRANCH_NAMEをアップロード -
git fetch <REMOTE> <BRANCH_NAME>
: REMOTEのBRANCH_NAME変更履歴をダウンロード -
git pull <REMOTE> <BRANCH_NAME>
: REMOTEのBRANCH_NAMEをHEADにマージ-
git pull
は内部的にgit fetch
の後git merge
が実行されている
-
-
git clone <URI> <DIR_PATH>
: DIR_PATHを初期化しURIリポジトリをコピー
-
- 確認
-
git diff HEAD..FETCH_HEAD
:git fetch
とHEADの差分表示
-
詳細と備考
-
git fetch
でコミットグラフが同期されるがブランチは変更されない -
git fetch
時にリモート追跡ブランチが移動する - リモート追跡ブランチはHEADが指せないポインタ
- リモート追跡ブランチはディレクトリとファイルが実体
- origin/masterはoriginディレクトリ内のmasterファイル
-
git merge
することでリモート追跡ブランチの指すコミットまでブランチを進める- fast-forwardであればコミットグラフはリモートと同じ形のままブランチのみ移動で済む
運用
小規模のための簡単な運用方針
- 普段使用するコマンドは以下のために決めておく
- 覚える量を減らす
- 同じ処理内容は同じコマンドにして明確にする
- 普段想定外のことが発生しないようにする
- GitHub flowを基にしてブランチを運用する
- 個人開発のためプルリクエストは使用しない
-
git rebase
は以下理由により使用しない- 小規模かつ個人のためコミットの絶対数が少なくグラフ整理の必要性が薄い
- 過去のコミットを追跡確認する場面は多くないと想定される
- 考慮すべき事柄が増えることによる操作ミスというデメリットの方が大きい
-
git cherry-pick
は考慮すべき事柄が増えるため使用しない -
git checkout
はトラブルの元になりやすいため過去コミットの参照にのみ使用する -
git merge
はgit pull
時以外non-fast-forwardでマージする -
git add
時にblobオブジェクトが生成されるため安易に実行しない -
git worktree
は便利そうだが必要になるまで使用しない - プロジェクトの純粋な成果物テキストファイルのみを管理対象とする
- 認証情報などgitで管理すべきでない情報をどう扱うか最初に決める
初期設定
- Git設定
# 初期設定 git config --global user.name "NAME" git config --global user.email "FOO@BAR.BAZ" git config --global color.ui auto # merge時のデフォルトをnon-fast-forwardに指定 git config --global --add merge.ff false # pull時のmergeをfast-forwardに指定 git config --global --add pull.ff only # fetch時にマージ済みブランチを削除 git config --global fetch.prune true # push時に注釈タグを反映 git config --global push.followTags true
- GitHubを用いるプロジェクト初期化
#---ここでGitHubでリポジトリ作成---# cd ~/projects/ git clone https://github.com/XXXX/XXXXXX.git
- ローカルのみのプロジェクト初期化
# DIR_PATHの.gitディレクトリを初期化 git init <DIR_PATH> #---ここでファイル作成---# git add . git commit -m "Initial commit."
参考文献
- git - Reference
- GitのHEADとは何者なのか
- gitのcheckoutコマンドには3つ使い方がある
- git merge解説
- git fetch解説
- A successful Git branching model を翻訳しました
- gitのmerge --no-ff のススメ
- Git rebase は使えなくてもいい。あとGit cherry-pick と Git merge --squash も
- Gitでマージ済みブランチを一括削除
- Git マージ済みのブランチを一括削除する
- git: Is an unannotated tag worse than a tag with a bad annotation?
- git pushでtagも同時にoriginへ反映する
- gitで最後に付けられたタグを確認する
- Gitのブランチの実装
- Gitのインデックスの中身
- Gitのオブジェクトの中身
- たぶんもう怖くないGit ~Git内部の仕組み~
- [git reset (--hard/--soft)]ワーキングツリー、インデックス、HEADを使いこなす方法
- 【図解】git-flow、GitHub Flowを開発現場で使い始めるためにこれだけは覚えておこう
- git status -s でちょっと幸せになれる
- gitコマンドの使い方 ~ git log ~
- Gitの使い方、よく使うGitコマンド
- Gitなにもわからない
- git stashの仕組みが面白い
- GitのWorking TreeとIndexが分かる記事
- fetchとpullと、リモート追跡ブランチ
- Git で「追跡ブランチ」って言うのやめましょう
- 【Gitをしっかり理解】追跡ブランチとリモートブランチは別物!
- git pullは、fetchしてmergeするのと同じなのか?
- 【Git】リモートからの取得とリモートへの反映で行っていること(fetch,pull,push)
- Git の仕組み (1)
- Git が内部でデータを取り扱う方法
Discussion