
あなた
Gitって何となく使っているんだけどいまいち理解できないし、エラー出たら解決できないんだよなぁぁ…..

迷える君にここでは色々gitについて教えて行くぞ!

あなた
やった!師匠ありがとう!
Gitとは?
Gitとはバージョン管理システムのことです。
バージョン管理はいくつかファイルがあった際にそれがどの順番か、どれが最新かを履歴で整理し、容量を節約することができます。
例えば、○○, ○○_test, ○○_修正とかあると順序がわかりにくい。
またバージョンが新しくなると容量が倍になっていく。
Gitは好きなタイミングでファイルを記録可能です。以前の状態すぐに戻せる。
またチームで開発できるようになります。複数人の共同編集はエラーがでる可能性が高い。上書きの防止など色々メリットがあります。
GitHubで出来ること
コードの共有。公開設定。コードレビュー。OSSに参加。
無料!!
バージョン管理システムには分散型と集中型がある。
分散型はリポジトリの完全なコピーをローカルにもつ。集中型はサーバーなどに管理している。集中型の場合、誰かがあるファイルを使用しているとき、他の人は触ることができない。このため開発速度に差が出る。
Gitの準備
接続確認
公開鍵を登録した後に以下のコマンドを実行します。
$ ssh git@github.com
初回接続で「Are you sure you want to continue connecting (yes/no/[fingerprint])?」と出たらyesと入力してください。
「Hi 名前! You’ve successfully authenticated, but GitHub does not provide shell access. Connection to github.com closed.」が表示されれば成功です。
右上の+ボタンからNew repositoryを押す。

そして名前と公開設定などを決めて作成する。

作成後

Gitの仕組みや基礎的な使い方
ローカル[記録⇔反映]⇔(アップと取得)GitHub⇔他の人のローカル
初期化,ローカルリポジトリの新規作成
# アプリケーションをローカルリポジトリとして登録
$ git init
(出力) Reinitialized existing Git repository in /home/ec2-user/environment/アプリケーション名/.git/
ディレクトリの中に「.git」という隠しディレクトリが作成され,「.git」の中には,リポジトリに必要なファイルが格納されています。ls -aコマンドで.gitディレクトリがあるか確認できます。
フォルダ[ファイル]→フォルダ[ファイル,ローカルリポジトリ]
ユーザー情報登録
$ git config --global user.name "GitHub user name"
$ git config --global user.email メールアドレス
ローカルリポジトリとリモートリポジトリの紐づけ
リポジトリURL : リモートリポジトリとして登録したいGitHubのリポジトリのURLを指定する。
$ git remote add origin リポジトリURL

リポジトリURLの確認方法 : GitHubのリポジトリの画面を開くと,上の画像のような画面になります。 HTTPSとSSHがありますが,今回はSSHを選択します。SSHを選択後,すぐ右の部分がリポジトリURLとなります。
ローカルリポジトリとリモートリポジトリの紐付けができているか確認する場合は以下のコマンドを実行します。
$ git remote -v
(出力)origin git@github.com:ユーザ名/git-practice.git (fetch)
origin git@github.com:ユーザ名/git-practice.git (push)
デフォルトブランチをMainに変更
## mainブランチを作成していない場合
$ git branch -M main
デフォルトブランチをMainに設定する.
$ git config --global init.defaultBranch main
GithubにPushするまで
記録
ワークツリー→(add)ステージ→(commit)→リポジトリ
git add 変更箇所(".もしくは -A"の場合は全変更ファイル)
これはコミットしたいファイルをindexに追加している。下記コマンドでindexを確認できる。
git ls-files --stage
(出力)ファイルの種類 blobハッシュ コンフリクトフラグ ファイル名
blobハッシュはファイル情報が入っている。オブジェクトはgit/objectsの中にzipで圧縮されて保存されている。blobオブジェクトは差分ではなく中身そのまま保存している。git addはindexの更新とblobの作成をしている。
他のオブジェクト
commitオブジェクトはコミットの情報が入っている。treeオブジェクトはディレクトリの情報が入っている。
blogオブジェクトはadd、treeオブジェクトはcommitの時に生成される。
commit
git commit -m "コミットメッセージ(変更内容)"
commitをするとindexからtreeオブジェクトを作成する。その後commitオブジェクトを作成し、HEADを新しいcommitハッシュにする。下記コマンドでtreeコマンドを確認できる。
git cat-file -p <object id>
(出力)ファイル種類 blob blobハッシュ ファイル名
commitすると全ディレクトリ分のtreeを作成する。その後commitオブジェクトを作成する。commit時のリポジトリを再現できるようになる。commitオブジェクトの構造はルートディレクトリのtreeハッシュ、親コミットハッシュ、comitterとauthorのデータ、メッセージになっている。親コミットハッシュを含めることで改ざんに強くなっている。一部を変えたらその後のコミット全て別物になる。
状況確認
リポジトリ⇔(diff)ワークツリー→(diff)ステージ
git diff リポジトリとワークツリーの差分をチェック
git diff -staged リポジトリとステージの差分をチェック
git status 変更ファイルを確認
履歴の確認
リポジトリ[変更2,変更1]
git log 変更履歴を確認
元に戻す
リポジトリ(restore)←ワークツリー(restore)←ステージ
git restore <ファイル名> ワークツリーの変更を取り消す
git restore -staged <ファイル名> ステージに挙げた変更をワークツリーに戻す
refs
特定のコミットを示す存在。tag,branch,HEADなど。light weight tagは特定のcommitを指している。annotated tagはコメントをつけられるtag。branchは書き換わるlight weight tag。HEADは現在のコミットを指しているrefs
gitでの開発
別の時間軸による管理
gitは別の軸でもバージョン管理できます。別に別に管理したものを統合することができます。別の軸をbranch、統合をmergeと呼びます。少し体験してみます。
①(フォルダ作成) mkdir practice
②(移動) cd practice
③(git) git init
④(ファイル追加)practice1.txt(中身も何か書いておく)を適当に作ってpracticeフォルダに追加してください。
⑤(add) git add practice1.txt
⑥(commit) git commit -m "first"
⑦(log) git log
logが出てればOK。出来たらbranch確認してみましょう。
git branch
(出力)* master
デフォルトで作られるmasterブランチにいることが分かります。*現在位置です。昨今masterは不適切という指摘もあり、デフォルトブランチをmaster以外にすることが多いです(mainとか)。以下のコードでgit init時のデフォルトブランチを変更できます。
git config --global init.defaultBranch ブランチ名(main)
ブランチ:分岐して開発
ブランチ作成
git branch develop(ブランチ名)
git branch 「ブランチの一覧表示」
(出力)develop
* master
「git branch ブランチ名」ではブランチは作られますが移動はしていないので注意してください。「git branch -a」はGithub全てのブランチを表示。
git checkout develop(ブランチ名)
git branch
(出力) * develop
master
git switch <ブランチ名> ブランチを切り替える
git switch -c <ブランチ名> ブランチを新規作成して切り替える
masterに戻って一旦変更してみます。
git checkout master
echo 'master' > master.txt
git add .
git commit -m "master"
echo 'master' > practice1.txt
git add .
git commit -m "master2"
git log --oneline
git checkout develop
echo 'develop' => develop.txt
git add .
git commit -m "develop"
echo 'develop' > practice1.txt
git add .
git commit -m "develop"
git log --oneline
変更のマージ
それぞれの変更をmergeしていきます。mergeするブランチをtheir、mergeされるブランチをoursと呼ぶ。mergeはoursの方(master)で行う。
git merge develop
(出力)warning: Cannot merge binary files: practice1.txt (HEAD vs. develop)
Auto-merging practice1.txt
CONFLICT (content): Merge conflict in practice1.txt
Automatic merge failed; fix conflicts and then commit the result.
git merge リモート名/ブランチ名
上記のようにコンフリクトが起きると思います。
コンフリクト
今回はtheirsとoursで同じ個所を変更していたため、自動で変更出来なかった。コンフリクトは手動で解決するしかない。
git status(コンフリクト箇所を見つける)
(出力)On branch master ~省略~
Changes to be committed:
new file: develop.txt
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: practice1.txt
both modifiedがコンフリクト箇所。修正箇所を丁寧に確認してから解消作業に移る。まずはブランチ分岐から確認する。その後、コンフリクトファイルにどのような変更を加えてか確認する。
git merge-base master develop
(出力)aaf11758e0fb4c0c3a8bdaeb52b2b4d2f1c0aed5
git diff --text aaf11758e0fb4c0c3a8bdaeb52b2b4d2f1c0aed5 develop practice1.txt
(出力)diff --git a/practice1.txt b/practice1.txt
index 029e230..fa7a041 100644
--- a/practice1.txt
+++ b/practice1.txt
@@ -1 +1,2 @@
-よろしくお願いいたします。
\ No newline at end of file
+<FF><FE>m^@a^@s^@t^@e^@r^@^M^@
+^@
\ No newline at end of file
git diff --text aaf11758e0fb4c0c3a8bdaeb52b2b4d2f1c0aed5 master practice1.txt
(出力)diff --git a/practice1.txt b/practice1.txt
index 029e230..fa7a041 100644
--- a/practice1.txt
+++ b/practice1.txt
@@ -1 +1,2 @@
-よろしくお願いいたします。
\ No newline at end of file
+<FF><FE>m^@a^@s^@t^@e^@r^@^M^@
+^@
\ No newline at end of file
文字化けしてますが、よろしくお願いいたしますが別の文字になっています。ファイルを開いて修正する。
git merge --continue
コンフリクトは手動で解決するのでミスが起きる可能性がある。出来るだけ起きないようにする。もしmasterを変更した後に別branchで変更してmergeするとfast-forward mergeと呼ばれるコンフリクトが起きないmergeになる。
checkout
特定のコミットが参照しているtreeをワークツリーに展開しindexをワークツリーと同期させる。HEADを指定したコミットにする。
プッシュ
git push origin main
プル
git pull origin main
git pull 省略可
情報取得,ワークツリーまでは反映しない
git fetch origin
fetch+merge
git merge
reset
git reset | HEAD | index | ワークツリー |
–soft | 書き換える | ||
–mixed | 書き換える | 書き換える | |
–hard | 書き換える | 書き換える | 書き換える |
resetはコミットをなかったことにしたり、addの取り消しをする。
ちなみにresetはcommitオブジェクトを削除しない。どこからも参照されないcommitができるがgit goというコマンドが走って削除される。
ちなみにgit pullの時、ファイルをいじって変更がうまく反映されないことがある。その場合は以下のコマンドを実行する。
// 1) リモートの最新を取ってきておいて・・
$ git fetch origin develop
// 2) ローカルのmasterを、リモート追跡のdevelopに強制的に合わせる!
$ git reset --hard origin/develop
rebase
ブランチの分岐元を変更する。通常のmergeからfast-forward mergeにできる。push前で行うとよい。普段はmergeを使う方が良い。もしpushしていた場合、強制pushが必要になる。使い方として開発ブランチで変更中にメインブランチも作業があった場合にmaster→develop→mergeでコンフリクトが起きないでmergeできる。これはmasterをdevelopにmergeすれば解決する。もしマージコミットを残したくない場合はrebaseを使う。強制pushをしたくなく、他の人と共有とする場合にはmergeを使う。
また別ブランチ1からブランチ2を分け、ブランチ2をmasterにmergeするとたとえブランチ1を既にmergeしていてもコミットにブランチ1が出現してしまう。もしrebaseを使うとブランチ1をmergeしたmasterブランチから分岐した状態に改変できる。その場合mergeコミットがブランチ2のみになる。
またコミット履歴の修正が出来る(並べ替え、合体、変更、過去修正)。
git rebase -i HEAD~3
修正コミットと修正コマンドを選ぶ。完了したら以下コマンド。
git rebase --continue
強制プッシュ
プッシュは通常コミットを追加するときのみ可能。rebaseはコミット改変なので普通のコミットはできません。この場合強制プッシュ(git push -f)を行う。
出来ればgit push –force-with-leaseを使うべき。もしローカル履歴がリモート履歴よりも新しいときに強制プッシュします。
Gitのコマンド
stash
変更を一時的に退避させる。「stash list」でスタッシュ一覧を見れる。「stash apply 番号」でを復元できる。「stash pop」で直近stashの復元と削除を行う。
revert
特定コミットを打ち消すコミットを作る。resetはコミットの履歴が改変される。
bisect
バグが混じったコミットを特定するコマンド。
git bisect start <bad> <good>
cherry-pick
特定のコミットと同じ内容のコミットを現在いるブランチに作る。
submodule
別のリポジトリを使用する際に用いる。
log-graph
コミット履歴の可視化
Gitの開発Flow
masterの先頭が最新のプロダクトリリースとなる。開発はdevelopで行う。ある特定の機能を作る際にはdevelopからブランチを切って、開発後mergeする。「1機能=1feature」。管理がわかりやすく、コンフリクトが起きにくい。もし大きな機能の場合、featureからfeatureでブランチを切ってもよい。
releaseはdevelopからmasterへ統合する際に準備として用意するブランチ。このブランチでは新機能などは追加しない。hotfixは、バグが発生した際に緊急性の高いものを修正する際のブランチ。ちなみにdevelop以外で唯一masterからブランチを切れる。
Githubについて
初期設定
git remote add origin url [リポジトリ追加]
プルリクエスト
- mainを最新状態にする
- ブランチ作成
- ファイル変更・コミット
- プッシュ
- プルリクエスト
- コードレビュー
- マージ
Issue
色々書き込める部分。タスクや相談事を整理したり、割り当てたりなんでもどうぞ。
Pull Request(PR)
特定のブランチや元のリポジトリに変更を取り込むようにリクエストする。PRはできるだけ小さな単位で出すほうがコードレビューする側も楽だし、時間もかからない。ちなみに時間がかかることがやばいのは他のPRがmergeされてコンフリクトが起きることである。もし巨大になるときはfeatureからfeatureを切る的な感じで細かくしよう。またログはきれいに残したほうがよく、場合によってはgit rebase -iで整理するのもあり。
PR見る側はセキュリティや法律の面で問題ないかチェック。また設計や計算量なども重要。
Actions
CI/CD環境。
Projects
タスク管理ツール
Wiki
自由に記事追加
Security
Security policyは脆弱性報告。Security advisoriesはクローズドな問題が対策されたあとに公開。Dependabotは脆弱性を見つけたらアラートを飛ばしてくれる。
Insights
リポジトリの活動を確認できる。コミットや差分をグラフで確認できる。
Settings
リポジトリの設定をするところ。
チーム開発の流れ
ローカル[ブランチ](プッシュ)⇔(プル)Github(プルリクエスト)⇔ローカル