サイトロゴ

Gitと向き合うための、Gitでよく使うコマンドノート

著者画像
Toshihiko Arai

はじめに

Gitを使って開発、バージョン管理していますが、Sourcetreeだけでは解決できない場合があります。そんな時、実際にトラブルに合ったケースとともに解決方法を記録しておきました。また、よく使う、知っておくと便利なGitコマンドもご紹介いたします。

Githubでリポジトリ作ったら最初にやること

Githubで空のリポジトリを作っておく。ただし、Github側ではREADMEも.gitignoreも作らないこと!

プロジェクト配下で以下実行。

git init
touch .gitignore # 内容は適宜編集しておく
git add .
git commit -m "first commit"
git remote add origin https://github.com/ユーザー名/リモートリポジトリ名.git
git push -u origin main

これでローカルリポジトリがリモートリポジトリへ反映されます。あとはゴリゴリ開発していきましょう!

git branchでブランチ操作

現在のブランチを確認する

git branch --show-current

新しいブランチを作成する

git branch feature/⚪︎⚪︎機能の開発

ブランチを切り替える

git checkout feature/⚪︎⚪︎機能の開発

もしもブランチが切り替えられないケースに合ったら、とりあえずターミナルを再起動すればおkです。

ブランチを削除する

git branch -d feature/⚪︎⚪︎機能の開発

ただし、削除対象となるブランチ以外のブランチにチェックアウトする必要があります。

ブランチを強制削除する

たまに、上記コマンドでブランチの削除が行えないケースに合いました。そんな時は強制削除を試しましょう。強制削除はオプションの「D」を大文字にするだけです。

git branch -D feature/⚪︎⚪︎機能の開発

コンフリクトの解消

コンフリクトが起きたら、とにかく慌てないことが大事です。慌ててあれこれコマンド実行してしまうと、さらに面倒なことになりかねません。まずはお茶でも飲みながら落ち着いてから問題に取り組みましょう。

コンフリクトが発生していることを確認する

git status

コンフリクトの発生を確認したら、対象となるファイルを開きます。とくにVS Codeを使って開くのが、わかりやすくておすすめです。

コンフリクト部分を探す

コンフリクト部分には、以下のようなマーカーが書かれているはずです。

<<<<<<< HEAD
(あなたの変更内容)
=======
(他のブランチやマージされた内容)
>>>>>>> branch-name

<<<<<<< HEAD から=======が Current Change つまり自分が変更した部分です。=======から>>>>>>>の内容が Incoming Change、つまりマージしようとしたブランチ先での内容です。

どちらを保持するか判断したら、手作で内容を修正します。この時 <<<<<<< HEAD>>>>>>> のマークも削除してください。コンフリクトといっても、単にファイルにマーカーが記述されているだけなので、落ち着いて見れば大したことはありません。 VS Codeであれば、コンフリクト部分にボタンが表示されているはずなので、それを利用しましょう。

コンフリクトを修正したら、変更内容をステージングする

git add [修正したファイル名]

全てのコンフリクトを解決したら、新しいコミットを作成する

git commit

この時、エディタが開きます。マージメッセージを編集できるのですが、デフォルトのメッセージが提供されているので、そのままエディタを閉じてもらって大丈夫です。

リモートリポジトリの設定

設定されているリモートリポジトリを確認する

$ git remote -v    
origin  https://github.com/aragig/ChainableMark2Html.git (fetch)
origin  https://github.com/aragig/ChainableMark2Html.git (push)

リモートリポジトリのURLを削除する

git remote remove origin

新しいリモートリポジトリのURLを登録する

git remote add origin リモートリポジトリのURL

gitignoreが反映されない

git add . でステージングしても .gitignore の設定が無視される場合があります。そんな時は、一度キャッシュを削除すると効果的です。

git rm -r --cached .

zipmov などの大容量ファイルは、ステージに上げないのが無難です。.gitignoreでフィルタリングしておきましょう。

ローカルのみ追跡除外

次の設定を行うことで、セキュリティ情報や個人的な設定などの変更を追跡せずにすみます。

追跡から除外する

git update-index --skip-worktree path/to/file

追跡除外対象から解除する

git update-index --no-skip-worktree path/to/file

追跡除外対象のファイルを確認する

git ls-files -v | grep ^S

または、

git ls-files --others --ignored --exclude-standard

過去のコミットに戻りたい

$ git logを実行して、日付やコミットメッセージの内容を手がかりに、戻りたい地点を探します。

戻りたいコミットが見つかったら、commitのハッシュをコピーし、$ git checkout [ハッシュ]でチェックアウトします。

最後のコミットを取り消す

まだ、リモートリポジトリへプッシュしていない場合、比較的簡単に最後のコミットを取り消すことが可能です。

変更内容は保持して最後のコミットだけ取り消す

git reset --soft HEAD^

変更内容を破棄して最後のコミットだけ取り消す

git reset --hard HEAD^

誤ってプッシュしたコミットを取り消す

誤ったコミットをリモートリポジトリへプッシュしてしまった場合の取り消し方法です。共同開発の場合は、他の開発者へ影響が出ますので、事前確認の上、慎重に行なってください。

強制プッシュで取り消す(履歴なし)

共同作業でなければ以下の方法が有効です。履歴も残りません。

  1. git resetなどのコマンドを使って、ローカルリポジトリのコミットを取り消しておく
  2. git push origin <branch-name> --force で、ローカルリポジトリをリモートリポジトリへ強制的に反映さセル

リバートを使って取り消す(履歴あり)

リバートを使えば、共同作業の場合でも安全に取り消すことができます。ただし履歴は残ります。

  1. git log で取り消したいコミットのハッシュを特定する
  2. git revert <commit-hash> で取り消したいコミットをリバートする
  3. コミットメッセージを残して、リモートリポジトリにプッシュする

HEADが”宙ぶらりん”、変更内容が見えなくなった

まずは落ち着いて、以下の手順を試してみてください。

1. 失われたコミットを見つける

失われたコミットを見つけるには、git reflogを使います。このコマンドは、ローカルリポジトリのHEADが過去に指していたコミットを表示します。コミットを行った後に何らかの理由でHEADが変更された場合でも、ここに記録が残ります。

git reflog

2. コミットの内容を確認する

git reflogで表示されたコミットの中から、失われたと思われるコミットを見つけ出し、そのコミットの内容を確認します。コミットID(例:a1b2c3d)を使用して、以下のコマンドを実行します。

git show a1b2c3d

このコマンドにより、コミットに含まれる変更内容を確認できます。

3. 失われたコミットを復元する

失われたコミットを正しいブランチに復元するには、次のコマンドを使用します。ここで、<branch>は復元したいブランチ名(例えばmaster)、<commit-id>は復元したいコミットIDです。

git checkout <branch>
git cherry-pick <commit-id>

または、コミットIDを直接ブランチにマージすることもできます。

git merge <commit-id>

git cherry-pickは、Gitで特定のコミットを現在のブランチに適用するコマンドです。これにより、別のブランチの変更を現在作業中のブランチに取り込むことができます。特に、複数のブランチ間で特定の変更だけを共有したい場合に便利です。


スタッシュで一時退避

開発中に、コミットはせずに別のブランチへ移動したい場合があります。そんな時に、変更内容を一時的に退避させるのがスタッシュです。

変更内容を一時退避させる

git stash

これでエラーや警告なく、ブランチやコミットを切り替えられるようになります。

スタッシュしたリストを確認する

git stash list

一時退避させた内容を戻す

元のブランチに戻ってきて、作業を再開したい場合は保存したスタッシュを戻す必要があります。

git stash pop

コミットメッセージを意味あるものにする

コミットメッセージを何も考えなしに自由に書いてしまうと、人はおろか、自分でさえ変更内容がわからなくなってコミットを遡れなくなってしまいます。そこでアイデアとして Conventional Commits でコミットメッセージの構造を標準化する方法があります。Conventional Commits とは、単なる仕様にすぎません。仕様に従うことで、コミットログから直接バージョン番号やリリースノートを生成することが容易になります。

基本的なフォーマット

```commit message [optional scope]:

[optional body]

[optional footer(s)]


**type:** コミットの種類を示す  
- feat: (新機能)
- fix: バグ修正
- docs: ドキュメントの変更
- style: コードのスタイルやフォーマットに関する変更
- refactor: リファクタリング
- test: テストの追加や修正
- chore: その他の変更

**scope (オプション) :** コミットが影響を与える範囲  
例えば、特定のコンポーネントやファイル名などがこれに該当する。

**description:** コミットの簡潔な説明  
何を変更したのか、なぜその変更が必要だったのかを明確にするべき。

**body (オプション) :** 詳細な説明  
変更の動機や、どのように変更したのかの詳細を記載。

**footer (オプション):** issueトラッカーのID関連付け

例: 
- Fixes #123
- Closes #456

#### 実際の例

```commit message
feat(authentication): OAuthの実装

APIアクセスへのOAuth認証を実装しました。
- API token 発行
- API token 無効

Closes #123

Conventional Commitsを使用することで、コミットログはより情報豊かで読みやすくなり、自動化ツールとの連携も容易になります。

とはいえ、Conventional Commitsに従って、すべての内容を書くのは面倒なので、私の場合は<description><description>オプションだけを仕様に従って記述するようにしています。これだけでもコミット履歴を見たときに、変更内容が分かりやすくなります。

commit message feat: OAuthの実装

特定のファイルにおいて現在のブランチと別ブランチの差分を表示する

git diff [別ブランチ名] --  [ファイルパス] 

別ブランチ同士の比較も可能:

git diff ブランチA ブランチB -- path/to/file

現在のブランチ内の任意のコミット同士で、特定ファイルの差分を比較する

git diff <commit1> <commit2> -- path/to/file

HEAD(最後のコミット)と現在の作業状態の差分:

git diff HEAD -- path/to/file

コミットツリーを見やすく表示する

git log --graph --date=short でコミットツリーを表示できますが、お世辞にも見やすいとは言えません。そこで、オプションを追加してツリーを整形して見やすくする設定を紹介いたします。 こちらのstackoverflow で紹介されているものになります。

git config --global --edit で 以下エイリアスを追記します。

...
[alias]
lg1 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)' --all
lg2 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(auto)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
lg = lg1

git lggit lg2 を実行してみてください。下図のようにコミットツリーがとても見やすくなります。

コミットメッセージを変更したい

まだリモートリポジトリへプッシュしている前でしたら、コミットメッセージを修正・変更可能です。

git commit --amend

このコマンドを実行するとVimエディタが開かれるので、適宜内容を書き換えます。

特定のファイルについて直近で変更した人を調べたい

特定のファイルを直近で変更した人を調べるためには、以下のコマンドを使用します。

git log -1 --pretty=format:"%h %an %ad %s" -- <ファイルパス>

このコマンドは、指定されたファイルの直近のコミットを表示します。

例:

git log -1 --pretty=format:"%h %an %ad %s" -- path/to/file.txt

このコマンドは、以下の情報を表示します: - コミットハッシュ (%h) - 作者の名前 (%an) - コミット日時 (%ad) - コミットメッセージ (%s)

これにより、特定のファイルを誰が直近で変更したかを確認できます。

特定のファイルを直近で変更した数人分の情報を調べるには、以下のコマンドを使用します。

git log -n <表示したいコミット数> --pretty=format:"%h %an %ad %s" -- <ファイルパス>

例として、直近の5つのコミット情報を表示する場合は、以下のようにします。

git log -n 5 --pretty=format:"%h %an %ad %s" -- path/to/file.txt

これにより、指定したファイルに対して直近で行われた複数のコミットの情報を表示できます。

以下は、直近の5つのコミット情報の例です:

a1b2c3d John Doe 2024-08-01 10:00:00 修正内容1
b2c3d4e Jane Smith 2024-07-30 15:30:00 修正内容2
c3d4e5f Bob Brown 2024-07-25 12:45:00 修正内容3
d4e5f6g Alice White 2024-07-20 09:20:00 修正内容4
e5f6g7h Charlie Black 2024-07-15 17:10:00 修正内容5

このコマンドを使用することで、特定のファイルを直近で変更した数人分の情報を取得できます。

GitHub CLI の導入

GitHubで管理しているリポジトリ操作を、コマンドラインインターフェース(CLI)から操作できるツール「GitHub CLI」を導入してみました。ここではその使い方を学びながらまとめていきます。

インストール&事前準備

$ brew install gh

ghコマンド補完の設定

ghを実行する際に、コマンドをtabでtabで補完できるようにしておくと便利です。zshの設定に次の記述を書き込みます。

if type brew &>/dev/null
then
  FPATH="$(brew --prefix)/share/zsh/site-functions:${FPATH}"

  autoload -Uz compinit
  compinit
fi

issueの操作

以下、ローカルリポジトリのルートディレクトリ(.gitが存在する場所)で実行します。

issueを新規作成する

$ gh issue create 

コマンドを実行すると、対話形式でissueの内容を入力できます。

issueを一覧表示

$ gh issue list

issueをクローズ

$ gh issue close イシューナンバー

GitHubにリポジトリを作成

my-test-repo を非公開で作成します。

$ gh repo create my-test-repo --private -d 'This is test repository created by gh command.'

特定のファイルをコミット間で差分表示

git diff コマンドを使用して、特定のファイルに限定したコミット間の差分を比較することができます。

以下は手順です:

コマンド

git diff <commit1> <commit2> -- <file_path>
変数 内容
<commit1> 差分比較の基準となる最初のコミットハッシュ。
<commit2> 差分を比較する対象のコミットハッシュ。
<file_path> 差分を確認したい特定のファイルのパス。

たとえば、特定のファイル src/main.c の差分を abc1234def5678 という2つのコミット間で比較したい場合、以下のようにします:

git diff abc1234 def5678 -- src/main.c

現在のコミットと比較

commit1 または commit2 のどちらかを省略すると、HEAD(現在のコミット)との差分になります。

git diff abc1234 -- src/main.c  # abc1234 と HEAD の比較

指定したコミットの特定ファイルの内容を書き出す

git show <commit_hash>:<file_path> > filename

git show で指定するパスは、プロジェクトルートからの 相対パス を使います。絶対パスを指定していると、エラーになるので注意です。

関連記事