これは、筆者の「2025振り返り用ひとりアドカレ」記事の一つです。
はじめに
この記事は、gitやGitHubについて何となく理解したくらいの初心者から、実務で使っているものの不安な部分もまだあるという方々が、実際に使っていく中で詰まりそうな部分を筆者の独断と偏見でまとめたHowTo集になります。
自身が初心者の頃に知りたかったような部分をはじめ、触っていく中で気になったところなどを網羅的に書いていくつもりですが、捉え方には個人差もあるかと思いますのでそういった点はご了承ください。
新規または既存プロジェクトを自分の環境に取り込む(ローカル環境の作成)
GitHubの大きな利点の一つに「大本のデータから自身のローカル環境(使用PC)に同じものをダウンロードでき、それを自由にいじっても大本のデータには何も影響が出ない」上に「不具合があれば問題発生前の内容に差し戻せる」という点があります。
つまり、プロジェクトに関する設定やデータを簡単に共有および共同編集環境を用意できるわけですね。
自分で環境を用意するような新規プロジェクトと、既に用意されたものをローカルに落とす既存プロジェクトでは手順が異なるので説明していきます。
新規プロジェクト(GUIベース)
1. GitHubのページからGUIで新規リポジトリ作成
- ダッシュボード右上にある
+アイコン->New Repositoryで作成できます - 他人に見られたくないようなものは
Choose visibility欄でPrivateを選びましょう
2. 表示された初期設定コマンドを対象プロジェクトのターミナルに転記して実行
3. git checkout -b ブランチ名 -> git push -u origin ブランチ名でブランチを切ってリモートの当該リポジトリに接続
-
git checkout -b ブランチ名:元データをベースにブランチを新たに作成 -
git push -u origin ブランチ名:先ほど用意したブランチのローカルリモートリポジトリを作成して、それらをリンクさせる。※-uを付けることでリンクでき、git pushなど一部のコマンドを簡略化できます
4. git add . または git add ファイルパス -> git commit -m"コミットメッセージ" -> git pushでリモートリポジトリ(大本ファイルやデータ)にアップ
-
git add:ファイルやデータをステージングする -
git commit -m:ローカルリポジトリにコミットする際のメッセージを記述 -
git push:コミット済みの変更内容をリモートリポジトリに反映
5. プルリクエスト出して問題なければ merge する
リモートの主ブランチ(大本ファイルやデータ)に変更内容が取り込まれる。
6.(任意)作業していたブランチを削除
- GUI操作の場合、マージした後に Delete Branch を押下
- ローカルリポジトリで
git checkout 主ブランチ名(main)->git pull origin 主ブランチ名(main)->git branch -d 支ブランチ名(topic)を実施- 主ブランチに切り替えて、最新の内容をローカルに反映し、作業していた支ブランチを削除する
既存プロジェクト
1. git branch -aでブランチを確認
-
-a:allの略でローカル・リモートリポジトリにある全てのブランチを確認する
2. git pull origin mainで主ブランチの内容をローカルに反映
-
git pull:リモートリポジトリの最新の内容を取得し、それをローカルリポジトリに統合させる
大抵はgit pull origin ブランチ名で問題ありません。
例えば、事前に変更差分を把握したり、各ブランチ内容をチェックしてから変更を取り込んだりする場合はgit fetch origin ブランチ名 -> git merge origin/ブランチ名というように、最新の内容取得及び統合作業を分割して行うケースもあります。
-
git fetch origin ブランチ名:指定した(リモートリポジトリの)ブランチの最新の内容を取得 -
git merge origin/ブランチ名:指定した(リモートリポジトリの)ブランチの内容をローカルリポジトリに 統合(変更が競合しない場合スムーズに合併される) させる
3. 編集など実作業の実施
※この際にgit checkout -b ブランチ名で別ブランチに切っておくケースもあります。
4. 先の工程で別ブランチに切っていない場合
git checkout -b ブランチ名 -> git push -u origin ブランチ名でブランチを切ってリモートの当該リポジトリに接続
5. git branch -vvで今いるブランチを確認
※主ブランチへの誤push防止の観点から
6. git statusで変更内容を確認
必要に応じてgit restore ファイルパスで不要なファイルを省く
7. リモートリポジトリにアップ
問題なければ、git add . または git add ファイルパス -> git commit -m"コミットメッセージ" -> git pushでリモートリポジトリにアップ
8. プルリクエスト出して問題なければ merge する
9.(任意)作業していたブランチを削除
- GUI操作の場合、マージした後に Delete Branch を押下
- ローカルリポジトリで
git checkout 主ブランチ名(main)->git pull origin 主ブランチ名(main)->git branch -d 支ブランチ名(topic)を実施
既存プロジェクトを別環境で初めて利用
1. git clone リポジトリの cloneアドレスでプロジェクトをローカルインストール
2. 環境構築
例:フロントエンドの場合npm installで各種設定をインストール
3. 編集や確認など作業実施
※その後の変更・修正内容の反映方法はこれまで説明してきたフローと同じ。
-
git checkout -b ブランチ名でブランチを切って -
git branch -vvで今いるブランチを確認 -
git statusで変更内容を確認 - 問題なければ、
git add .またはgit add ファイルパス->git commit -m"コミットメッセージ"->git pushでリモートリポジトリにアップ - プルリクエスト -> マージ
- (任意)作業していたブランチを削除
- GUI操作の場合、マージした後に Delete Branch を押下
- ローカルリポジトリで
git checkout 主ブランチ名(main)->git pull origin 主ブランチ名(main)->git branch -d 支ブランチ名(topic)を実施
他に知っておくと便利なこと
変更・修正・編集ファイルやデータを更新する手順は先で説明した通りですが、ここではその更新作業を補助してくれるような情報を書いていきます。
変更・修正・編集内容の差分チェック
git diff
addされていないファイルとの差分を見ることができます。
- ステージングされた(addされた)ファイルの差分をみる
git diff --staged
- 最新のコミットとの差分をみる場合
git diff HEAD # 最新のコミット
git diff HEAD^ # 最新のコミットの1つ前
git diff HEAD^^ # 最新のコミットから2つ前
git diff HEAD~2 # HEAD^^(最新のコミットから2つ前)と一緒
- 特定のコミットの状態との差分チェック
git diff abc123 def456 # コミットIDの頭文字を使う
git diff main topic # ブランチごとの差分チェック
特定のファイルをアンステージ(addを取り消す)
-
git restore ファイルパス:ワーキングツリーから変更を破棄
# 指定したファイルを「最新のコミットの状態」に戻すことで変更を破棄
# ステージングエリアの状態はそのまま残る
git restore ファイルパス
-
git restore .:すべての変更を破棄する場合
# カレントディレクトリ以下のすべての変更を破棄
git restore .
全てのファイルをステージング(git add .)した後に、特定ファイルを対象外にしたい場合
git restore --stagedコマンドを使用します。
git statusで確認してからのrestore ファイルパスだと期待通りワーキングツリーから変更を破棄してくれます。
しかしgit add .で全てをステージングした後だと、restore --stagedで対象ファイルをアンステージングしないと追跡されてしまうのです。
# 1. 指定したファイルをインデックス(ステージングエリア)から外す
# ただし、ワークツリーの内容は変更されない。
git restore --staged ファイルパス
# 2. 作業ツリーの変更も元に戻す
git restore ファイルパス
ちなみに、git restoreはローカルの変更を破棄するだけで、リモートのリポジトリには影響を与えません。
ただし、破棄した変更は復元できないので、必要に応じて変更をstashに保存しておくほうが良いです。
# 修正内容を一時保存
git stash
stashについてはまた後述します。
commitやpushを取り消す場合
基本的にはgit resetコマンドか、(チーム開発の場合では)git revertコマンドを使用
git reset --hard # コミットとワークツリーの内容を完全に戻す(危険な操作)
git reset --soft # コミットだけを戻し、変更内容は維持
git revert # 新しいコミットとして戻す変更を作成(履歴が残るため安全)
- 具体例
# 直前のコミットを取り消してステージに戻す
git reset --soft HEAD~
# コミットと変更内容の両方を完全に取り消す(※変更内容が完全に消えるため取り戻せない)
git reset --hard HEAD~
※ 後述の救済措置を取り消せます。
コンフリクトが起きた時
コンフリクトとは、リモートリポジトリにある最新内容とローカルリポジトリになる最新内容で差分競合が起きている状況を指します。
どちらが正しいのか適切に対処する必要があるため、競合が発生している場合はpull時やmerge時にコンフリクトエラーが表示されます。
一般的なコンフリクト
例えば、最新の主ブランチの内容を反映せず(git pull origin mainやgit merge mainをせず)に、編集作業を行ってコンフリクトが発生したケースを想定します。
この場合はシンプルで、コンフリクト発生箇所を手動で逐次直して、git add ファイルパスまたはadd . -> git commit -m"コミットメッセージ" -> git pushするだけです。
少し厄介なコンフリクト(実務で起きがち)
既にステージングしてコミット、プッシュまで行ってコンフリクトしたと想定して進めます。
つまり、ここで紹介する手順は「実務で起きがちな事故」への対処法です。
- すでに
git commit→git pushまで完了している - プルリクエストを出した後に
- その間に main ブランチ側が先に進み
- その結果、履歴が衝突して通常の
pullやmergeが通らなくなった
先ほどの「通常のコンフリクト解消(手動でコードを直して add → commit)」とは異なります。
1. git statusで状態確認
- ※ 必要に応じて
git fetch origin mainで最新の状態を確認
2. git pull origin mainを実行してリモートのmainリポジトリ最新内容の反映を試みる
- ※
git checkout <他のブランチ>で上記を実行するのも可
3. Already up to dataと表示された場合git checkout <他のブランチ>でmainブランチまたはfeatureブランチなどに一旦切り替える
4. git logでログを確認して、最新のコミットIDを取得する
5. git reset --soft <コミットID>でコンフリクト前のデータやファイルを復元
- ※ または
git merge --abortでマージを中止し、クリーンな状態に戻す
6. git stashを行ってデータやファイルを一時退避
7. git pull origin mainを実行して最新内容が反映されているかを確認Already up to data.と表示されたらok
8. git stash popを実行して一時退避させていたデータやファイルを復元
- ※
git checkout <他のブランチ>でfeatureブランチなどにいる場合は、git push -u origin <ブランチ名>を行って「ローカルのブランチをリモートリポジトリにアップロードし、追跡ブランチを設定」する
9. git diffで変更内容を確認
10. あとは従来通りadd(ステージング)してcommit(ローカルリポジトリへ変更を記録)してpush(当該リモートリポジトリへ変更をアップ)する
11. プルリクエストを処理(マージまたはクローズ)
データ復元(addやcommit, push後の差し戻し方法)
1. git logで差し戻したいコミットIDを確認する
git log --oneline # 1行表示で見やすく
git log --graph # ブランチの分岐を視覚的に確認
2. git checkout -b <他のブランチ>などブランチを切る
手順1と2は逆でもokです。
3. git reset --hard <コミットID>またはgit reset --soft <コミットID>、またはgit revert <コミットID>
- 個人の場合:
git reset --hard <コミットID>またはgit reset --soft <コミットID>-
--hardの場合
-
# --hard オプション使用前に以下を推奨
git stash # 現在の作業内容を退避
git tag backup-YYYYMMDD # 現在の状態をタグとして保存
- チームの場合:
git revert <コミットID>
git reset --hard # コミットとワークツリーの内容を完全に戻す(危険な操作)
git reset --soft # コミットだけを戻し、変更内容は維持
git revert # 新しいコミットとして戻す変更を作成(履歴が残るため安全)
4. 再修正して再度、git add → git commit → git push
【救済措置】git reset --hard で削除した内容を復元する
git reflog # HEADの変更を確認する(※この記録は約30日間保持される)
# 上記の実行結果
e5f1c7b HEAD@{0}: reset: moving to 1a2b3c4
bf5f890 HEAD@{1}: commit: Fix login bug
# 間違ったresetを元に戻す(※ HEAD@{1} を指定)
git reset --hard HEAD@{1}
git revert
コミットの変更を取り消すための新しいコミットを作成します。
revertは新しいコミットとして変更を打ち消していくコマンドです。
# Eを打ち消す場合
git revert <EのコミットID>
# 結果: A -> B -> C -> D -> E -> E'
# さらにDも打ち消す場合
git revert <DのコミットID>
# 結果: A -> B -> C -> D -> E -> E' -> D'
注意事項として以下があります。
- 各コミットは独立して打ち消される(=コミットIDごとに
revertする必要がある) - 打ち消しも新しいコミットとして記録される
- 履歴が残るため、何を打ち消したのかが追跡可能
git rebase(コミット履歴を見やすく整理する)
コミット履歴の整理を行う(切ったブランチの分岐をまとめて一直線の履歴に修正する)コマンドです。
例: 作業ブランチ(feature)を、最新の主ブランチ(main)の先端に適用する(移動して再構成する)
これにより作業履歴が一直線になり、きれいに整理されます。
注意点としてgit rebaseでは、あくまで作業ブランチ側が変更されて(プッシュしてマージするまでは)主ブランチは変更されません。
- コンフリクト発生時のフロー
- コンフリクト発生時、
rebaseが一時停止 - 従来通り手動でコンフリクトを解消
-
git addでコンフリクト解消を記録 -
git rebase --continueで再開
必要に応じて2〜4を繰り返す
rebase後は変更履歴が書き換わるため強制プッシュが必要となります。
具体的には最後にプッシュする時は以下を実行します。
# 安全なフォースプッシュ
git push --force-with-lease origin feature
結局のところ処理結果(修正が反映されて管理できるか)という粒度で見ると、rebaseでしていることは「履歴の管理(見え方)が異なる」だけです。
一般的な手法で行うとすればgit add <変更ファイル>, git commit -m"featureブランチの変更をmainブランチにマージ(プルリク)", git pushしてマージするのと同じですね。
-
git rebase: ひとつにまとめる一元管理 -
git add→git commit→git push: 一般的なコミット履歴管理
注意事項
-
rebaseを使用する場合は、共有ブランチでないことを確認- ※コミット履歴が整理されてしまうことで「コードの編集記録が追えなくなって保守や運用に支障をきたすリスクがある」ほか「他のメンバーとの履歴がズレてリポジトリが壊れる」ため
-
--force-with-lease使用前に、他のメンバーが同じブランチで作業していないか確認 - プルリクエストのタイトル・説明文で「再修正版」であることを明記
git rebase --onto
上記で説明したフローをより端的に行えるgit rebase --ontoというものもあります。
git rebase --onto <新しいベース> <古いベース> <移動させたいブランチ>
具体例
# branch2 に移動(※ branch2 がすでにある前提)
git checkout branch2
# 近年は git switch がブランチ操作専用コマンドとして推奨されています
# branch2 の基点を branch1 から main に変える
# 1. branch1 のコミットのうち main に含まれていないものを特定する。
# 2. branch2 のコミットのうち branch1 由来のものを除外する。
# 3. branch2 の変更を main の先端に適用する。
git rebase --onto main branch1 branch2
git stash / git stash pop(作業の一時保存/復元)
例えば、実際の作業場所(デスク)があって、作業内容を一時保存できる箱があるとします。
途中で別の作業が入った場合など、**デスクで作業していた内容を箱に保存するのがstash**です。
そして別の作業が済んで、元の作業を行いたいときにstash popすると箱の中の直近の作業内容をデスクに取り出せます。
この時、すでに複数の作業内容が箱に入っている場合はstash pop {number}で特定の作業内容を取り出して復元することも可能です。
ただし、このとき指定した作業内容も削除されます。
git stash list # スタック内の作業内容を確認
git stash pop stash@{3} # 3番目の作業内容を取り出して削除
例えば、A~Eまで箱に入っていて、{3}を指定するとCの作業内容を復元し、箱からCの作業内容が削除されます。
注意点
git stash popは取り出した内容を適用しようとしますが、 適用できない場合(コンフリクト) が発生する可能性があります。
その場合、手動でコンフリクトを解消し、必要に応じて再度git stash dropを実行して該当のスタッシュを削除する必要が出てきます。
git stash apply stash@{3} # 特定の作業内容を取り出して適用(ただし削除しない)
git stash drop stash@{3} # 手動で特定のスタッシュを削除
コミット後にプルリクエストが拒否(close:Close pull request)された場合
以下の状況を前提として説明していきます。
- 主ブランチ(
main)から支ブランチ(topic)を切っている - 今回、下記修正を行ってコミットしている
- ファイル A, B, C, D, E の修正、ファイル F, G を新規作成
-
git add .->git commit -m"fix: 既存ファイルのリファクタリングと新機能の実装."->git pushという一般的なフローでプルリクエストを提出
- 上記プルリクエストがレビュー後に拒否(close:
Close pull request)された
状況
ローカルリポジトリでは(コミットしているので当然ですが)作業ディレクトリにuntracked files(未追跡ファイル)がない状態。
つまり、ステージング状況などはファイル修正前のnothing to commit, working tree cleanという状態です。
再度プルリクエストを出すまでの手順
# 1. mainブランチに切り替えて最新内容を取得
git checkout main
git pull origin main
# 2. 作業ブランチに移動
git checkout topic
# または another-topic ブランチを切って移動
# この場合、GitHub の GUI操作で リモートリポジトリの topic ブランチを削除しておく
git checkout -b another-topic
# 3.(任意)必要に応じてmainの変更を取り込む
# rebase(コミット履歴を整理するコマンド: 今回の場合、mainから分岐した topicを mainの最新コミット上に移動)
# チーム開発では推奨ルートだが強制プッシュ(`--force-with-lease`)が必要となるので注意する
git rebase main
# 念のため再度、mainの最新内容・変更差分を取り込む
git pull origin main
# または git merge main
# 4. 再修正作業を開始
# ファイルを編集...
# 5-A. 既存コミットに追加するルート
git add .
# 直前のコミットメッセージを修正
git commit --amend -m "修正内容(更新版)"
# 比較的安全な強制プッシュ処理
git push origin topic --force-with-lease
# 5-B. 通常のフロールート
git add .
git commit -m "修正内容"
git push origin topic
# または git push (事前に`-u`オプションを付けていた場合)
今回のおさらい
- ファイル A, B, C, D, E の修正、ファイル F, G を新規作成
-
git add .->git commit -m"fix: 既存ファイルのリファクタリングと新機能の実装."->git push - プルリクエストを出すもののマージ拒否(close:
Close pull request) - ローカルリポジトリで再修正(先の説明フロー)
- この時点で以前の内容(A, B, C, D, E, F, G)は処理完了(コミット)済み
- 修正後にコミットとプルリクエストの実施
- 追加修正ファイル(H, I)がある場合は当該ファイル(H, I)のみ新たに処理(コミット)される
- 以前の修正ファイルを再修正すると新たにA1, C1というような再修正verとして処理(コミット)される
-
pushした内容 = 今回のプルリクエストには以前の内容(A, B, C, D, E, F, G)と、追加修正ファイル(H, I)、以前の修正ファイルの再修正ver(A1, C1)が含まれる=プルリクエストで見える最終的な変更内容:A1(修正版), B(変更なし), C1(修正版), D(変更なし), E(変更なし), F(変更なし), G(変更なし), H(新規), I(新規)
- あとは GitHub の GUI でマージまたは拒否の操作を実施
Squash Merge
細かな修正・作業内容を一つにまとめてマージすることができる方法です。
支ブランチで作業を行い、当該ブランチにて都度コミットし、ある程度まとめて主ブランチにマージする、というもので、マージする際にそのブランチの全てのコミットを1つの単一のコミットに圧縮(squash)できます。
結果として主ブランチには当該支ブランチの作業内容が1つのクリーンなコミットとして統合されます。
具体的な処理例
-
git checkout -b ブランチ名 -
git push -u origin ブランチ名
※ここまでは事前準備フェーズ -
(
git status-> )git add ファイルパス(または.) -
git commit -m"fix: ..."
※ここで作業・修正を重ねる(squash用の各commitをためる) -
git push
最後にプッシュしてmainブランチにマージ(Squash Mergeの実施)-
Pull Request画面でSquash and mergeを選択すること - マージ後は通常通り、使用した作業ブランチを削除する
-
さいごに
ここで説明してはいませんが、ブランチモデルといってどのようにブランチを運用するかという手法があります。
筆者は比較的簡潔なGitHub Flowを採用していますが、チームや会社によってはgit-flowのところもあるかと思います。
これからGit, GitHubに触っていくという方は、チームや会社の制約が無い限り(ただでさえ覚えることが多いので)シンプルなGitHub Flowの方が良いかなと思います。
筆者が触れ始めたころ、情報を集めて理解するのに手間取ったので、
この記事が git, GitHubに触れ始める方々の役に少しでも立てれば幸いです。
ここまで読んでいただき、ありがとうございました。
参考