結論

Git のブランチとは、コミットを指す「名前の付いた目印」です。正体は .git/refs/heads/ にある、40文字のコミットID+改行だけの41バイトのファイルです。ファイルを丸ごと複製するわけではないので、何本作っても一瞬で、容量もほとんど増えません。

この記事でわかること

  • ブランチと HEAD の正体を、.git の中身を開いて確かめる方法
  • ブランチを切る→切り替える→コミット→マージする手順と実行結果
  • detached HEAD・削除できない・切り替えられない等のエラー原文と直し方

2026年10月29日更新|Git 2.43.0(Ubuntu 24.04)で実行確認

ブランチ(branch)は英語で「枝」です。Git では、コミットの並び(履歴)を枝分かれさせ、本流(main)を壊さずに別の作業を進めるために使います。ただし Git の中では「枝」という太いものがあるわけではなく、枝の先端のコミットを指す小さな目印があるだけです。下の図は、この記事で作るリポジトリの状態です。

flowchart TD
    H["HEAD"] --> M["main"]
    F["feature/login"] --> C3(("1226597"))
    M --> C2(("188ca2e"))
    C3 --> C2
    C2 --> C1(("95b0788"))

丸がコミット、四角が目印です。main と feature/login はそれぞれ1つのコミットを指し、HEAD は「今いるブランチ」を指しています。コミットの矢印は親(1つ前のコミット)に向かいます。

よく調べられることの答えを先にまとめます。

知りたいこと 答え 詳しい節
ブランチとは コミットを指す名前付きの目印。履歴を枝分かれさせて並行して作業する仕組み ブランチとは
ブランチの正体 .git/refs/heads/ブランチ名 という41バイトのファイル .git/refs/heads の中身
HEAD とは 今いるブランチを指す目印。中身は ref: refs/heads/main HEADとは
ブランチを切る(作る) git switch -c 名前(作って移る)、git branch 名前(作るだけ) ブランチを切る
git ブランチの切り替え git switch 名前。checkout でもできるが switch が分かりやすい switch と checkout
ブランチを統合する 統合先へ移って git merge 名前。fast-forward か 3-way になる マージ
origin/main とは 最後に通信したときのリモートの main の位置を写した目印 リモートブランチ
detached HEAD とは ブランチではなくコミットを直接指している状態。git switch -c で残す detached HEAD
main と master の違い 名前だけの違い。どちらも特別な機能は無い main と master

確認環境:Ubuntu 24.04.5 LTS の上で、Git 2.43.0 と GNU bash 5.2.21 を使い、作業用のフォルダーにリポジトリを作って、ブランチの作成・切り替え・コミット・fast-forward と 3-way のマージ・detached HEAD・ブランチ名の検査・エラーの再現を実行しました。リモートは GitHub ではなく、同じマシンの中に作った bare リポジトリ(git init --bare)を origin にし、push・fetch・追跡ブランチ・ahead/behind を確かめています(外部への書き込みはしていません)。日時と作者は固定して実行したため、記事中のコミットIDは手元で同じ操作をしても一致しないことがあります。速さと容量は、5,000ファイル・約20MBのリポジトリを tmpfs(メモリ上のファイルシステム)に置いて測りました。git switch の仕様は git-scm.com の公式リファレンス、ブランチの考え方は Pro Git(日本語版)、GitHub の既定ブランチは GitHub Docs、マージ戦略の既定値の変更は Git のリリースノートで確かめました。図は mermaid-cli 11.16.0 で描画を確かめています(確認日 2026年10月29日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「ブランチとは?Gitの正体は41バイトのファイル|切る・切替・統合」

ブランチとは(Gitのブランチの意味)

この節では、ブランチが何のためにあり、Git ではどんな仕組みで実現されているのかが分かります。

ブランチとは、履歴を枝分かれさせて、本流に影響を与えずに別の作業を進めるための仕組みです。 新しい機能を作る、バグを直す、試しに書き換えてみる、といった作業を、それぞれ別のブランチで進め、できあがったら本流に合流(マージ)させます。

Pro Git(Git の公式サイトで公開されている本)は、ブランチを、開発の本流から分かれて本流を邪魔せずに作業を続けるための機能として説明し、Git のブランチは作成がほぼ一瞬で、切り替えも高速だと書いています。その理由が、次の節で見る「ブランチはただのファイル」という作りです。

よくある思い込み

ブランチを切るとファイル一式がコピーされる

ブランチごとに別のフォルダーがある

ブランチが多いと容量が増える

Git の実際

コミットを指す41バイトのファイルが1つ増えるだけ

作業フォルダーは1つ。切り替えると中身が入れ替わる

1,000本作ってもオブジェクトは1つも増えなかった

なぜブランチが要るのか

  • 本流を守る:main をいつでも動く状態に保ち、作りかけのコードを main に混ぜない。
  • 並行して作業する:Aさんはログイン機能、Bさんはクーポン機能、と別々のブランチで同時に進められる。
  • やり直しやすくする:試してうまくいかなかったブランチは、合流させずに捨てればよい。
  • レビューの単位にする:GitHub などのプルリクエストは「このブランチを main に合流させたい」という依頼で、ブランチがレビューの単位になる。

コミット・ブランチ・リポジトリの関係

用語 意味 .git の中で見える場所
リポジトリ 履歴をまるごと保存した入れ物 .git フォルダー全体
コミット ある時点のファイル一式の記録(スナップショット)と、親コミットへの参照 .git/objects/
ブランチ コミットを指す名前付きの目印。コミットすると前に進む .git/refs/heads/
HEAD 今いるブランチ(または今いるコミット)を指す目印 .git/HEAD
マージ 2つのブランチの変更を1つにまとめる操作 親を2つ持つコミットができる

Subversion のような集中型のバージョン管理では、ブランチを作るとサーバー上にディレクトリのコピー(実際には安い複製)ができる、という形でした。Git のような分散型では、ブランチは手元のリポジトリの中の目印で、作るのも消すのも自分のパソコンの中だけで完結します。

ブランチの正体:.git/refs/heads の中身(41バイトのファイル)

この節では、ブランチを作ったときに .git の中で何が増えるのかが、実際のファイルを開いて分かります。

ブランチは .git/refs/heads/ブランチ名 というファイルで、中身はコミットID(40文字の16進数)と改行だけです。 実際に確かめます。まず空のリポジトリを作りました。

$ git init -b main shop
Initialized empty Git repository in /srv/s4/r17/t56/w/shop/.git/
$ cd shop
$ cat .git/HEAD
ref: refs/heads/main
$ ls -a .git/refs/heads/
.  ..
$ git branch
$ git log
fatal: your current branch 'main' does not have any commits yet

コミットが1つも無いうちは、.git/refs/heads/ は空で、git branch も何も表示しません。HEAD は「main を指す」と書いてありますが、main のファイルはまだありません(このような状態を「生まれていないブランチ(unborn branch)」と呼びます)。2つコミットしてから、ブランチを1本切ります。

$ git add . && git commit -m "カートの合計を計算"
[main (root-commit) 95b0788] カートの合計を計算
 2 files changed, 3 insertions(+)
$ git add . && git commit -m "税率の設定を追加"
[main 188ca2e] 税率の設定を追加
 1 file changed, 1 insertion(+)

$ git branch feature/login
$ find .git/refs/heads -type f
.git/refs/heads/feature/login
.git/refs/heads/main
$ cat .git/refs/heads/main .git/refs/heads/feature/login
188ca2e72c39044ef365df726ab1f86dcea8e2f0
188ca2e72c39044ef365df726ab1f86dcea8e2f0
$ wc -c .git/refs/heads/main
41 .git/refs/heads/main
  • ブランチを切ると、ファイルが1つ増えるだけでした。 中身は今いるコミット(188ca2e)のIDで、main と同じです。
  • feature/login のようにスラッシュを入れると、refs/heads/feature/ というフォルダーの中にファイルができます。
  • 41バイトは、40文字のIDと改行1文字です。Pro Git も、ブランチの実体は、指しているコミットの40文字の SHA-1 チェックサムを書いただけの単純なファイル(41バイト)だと説明しています。

このIDが指す先は、コミットのオブジェクトです。中身を表示すると、ファイル一式(tree)と作者、メッセージ、親のコミットが書かれています。

$ git cat-file -t 188ca2e
commit
$ git cat-file -p 188ca2e
tree 445a2e5ee414068416fd59e1752bbcc0fa6629e8
parent 95b0788d12ff3d7a3bbddcdf2d78f5c4c2f9b6f4
author Hanako Yamada <hanako@example.com> 1793235720 +0900
committer Hanako Yamada <hanako@example.com> 1793235720 +0900

税率の設定を追加

コミットは親のIDを持っているので、ブランチが指す1つのコミットから親をたどれば、そのブランチの履歴がすべて分かります。「ブランチ=先端のコミットの場所」で、履歴そのものはコミットどうしのつながりが持っています。

手でファイルを置いてもブランチになる

仕組みを確かめるために、コミットIDを書いたファイルを手で置いてみました(ふだんの作業ではこの方法を使わず、git branch を使います)。

$ git rev-parse 95b0788 > .git/refs/heads/handmade
$ git branch -v
* feature/login 1226597 ログイン処理を追加
  handmade      95b0788 カートの合計を計算
  main          188ca2e 税率の設定を追加

ファイルを置いただけで、handmade がブランチとして一覧に出ました。Git にとってブランチは本当に「refs/heads の下にあるファイル」です。

ブランチが多いと packed-refs にまとまる

ブランチやタグが増えると、Git は1本1ファイルではなく、.git/packed-refs という1つのファイルにまとめて書くことがあります(git gc や git pack-refs のとき)。手元で git pack-refs --all を実行すると、refs/heads/ の下のファイルは無くなり、次の1つのファイルになりました(行は抜粋)。

$ git pack-refs --all
$ ls .git/refs/heads
$ cat .git/packed-refs
# pack-refs with: peeled fully-peeled sorted
15aa812c2ba296122710e67ab532d2effa3ea214 refs/heads/feature/coupon
1226597822a055346bfd8bad003426ec39322cd6 refs/heads/feature/login
cfb7285717bb5cc4d47ce85a852408f5bcee28b5 refs/heads/main
1d4ffe2b1a6551e8bfe15185e01b23bbfe977a42 refs/remotes/origin/main

このため、「refs/heads にファイルが無いのにブランチがある」こともあります。ブランチの有無は、ファイルを直接見るより git branch や git show-ref で確かめるのが確実です。

ブランチはどれくらい軽いのか(実測)

5,000ファイル・約20MBのリポジトリで、ブランチを作る時間と容量を測りました(tmpfs 上・2コア)。

0.002秒git branch 1回3回測って3回とも同じ
41バイトブランチ1本の大きさ1,005本で 41,205 バイト
0個増えたオブジェクト1,000本作る前後とも 5,188 個
操作 かかった時間 増えた容量
git branch 名前(1本) 0.002秒 41バイト(ファイル1つ)
git branch を1,000回 2.036秒(プロセス起動が大半) 41,000バイト
作業フォルダーを cp -r で複製 0.055〜0.086秒 20MB
同じコミットを指すブランチへ switch 0.022秒 なし
121ファイル違うブランチへ switch 0.022〜0.052秒 なし

tmpfs はメモリ上なのでコピーも速く、時間の差より容量の差(41バイトと20MB)が本質です。ディスクの上では、ファイル1つにつき最小の割り当て単位(手元では4KB)が使われるため、du -sh では 1,005本で4.0MBと表示されました。packed-refs にまとめた後は、1,006本で 57,292バイトの1ファイルでした。

HEADとは:今いるブランチを指す目印

この節では、HEAD の中身と、ブランチを切り替えたときに HEAD がどう変わるのかが分かります。

HEAD は「今いるブランチ」を指す目印で、.git/HEAD というファイルです。 ふだんはブランチ名を指していて、中身は ref: refs/heads/main のような1行です。ブランチがコミットを指し、HEAD がブランチを指す、という2段構えになっています。

$ cat .git/HEAD
ref: refs/heads/main
$ git log --oneline --decorate
188ca2e (HEAD -> main, feature/login) 税率の設定を追加
95b0788 カートの合計を計算

$ git switch feature/login
Switched to branch 'feature/login'
$ cat .git/HEAD
ref: refs/heads/feature/login
  • (HEAD -> main, feature/login) は「HEAD は main を指していて、main と feature/login は同じコミットを指している」という意味です。
  • git switch で切り替えると、HEAD のファイルの中身が書き換わり、作業フォルダーの中身がそのブランチの先端のコミットの状態になります。
  • git branch は目印を作るだけで、HEAD は動きません(作っただけでは切り替わらない)。

今いるブランチ名だけを取り出したいとき(スクリプトやプロンプトの表示など)は、次のどれでも同じ結果でした。

$ git branch --show-current
main
$ git rev-parse --abbrev-ref HEAD
main
$ git symbolic-ref HEAD
refs/heads/main

ブランチを切る(作る):git branch と git switch -c

この節では、「ブランチを切る」の意味と、ブランチを作るコマンドの違い、どこから切るかの指定方法が分かります。

「ブランチを切る」は、新しいブランチを作ることを指す言い回しです。 木の幹から枝を切り出すイメージで、チームの会話では「main から feature/login を切る」のように「どこから」と一緒に使います。新しいブランチは、指定しなければ今いるコミット(HEAD)から始まります。

やりたいこと コマンド HEAD は動くか
作るだけ git branch feature/login 動かない
作って移る git switch -c feature/login 新しいブランチへ移る
作って移る(以前からの書き方) git checkout -b feature/login 新しいブランチへ移る
main の先端から切る git switch -c fix/tax main 新しいブランチへ移る
リモートの最新の main から切る git fetch のあと git switch -c fix/tax origin/main 新しいブランチへ移る
過去のコミットから切る git switch -c try/old 95b0788 新しいブランチへ移る

git-scm.com のリファレンスは、git switch -c を「git branch に続けて git switch を実行するのと同じだが、切り替えが成功しなければブランチは作られない」と説明しています。作って移るなら -c を使うと、作ったのに移れていない、という状態を避けられます。

1

起点を最新にする

git switch main で main に移り、チームで使っているなら git pull で最新にする。前に取り込んだままの main から切ると、後でマージするときに差が大きくなる。

git switch main・git pull

2

目的が分かる名前で切る

git switch -c feature/login。種類/内容 の形にすると一覧で探しやすい。

git switch -c

3

そのブランチでコミットする

変更して git add・git commit。コミットすると、今いるブランチの目印だけが前に進む。

git add・git commit

4

共有する

git push -u origin feature/login でリモートに送り、プルリクエストを作る。

git push -u

5

合流させて片付ける

main にマージしたら、使い終わったブランチを git branch -d で消す。

git merge・git branch -d

コミットすると動くのは今いるブランチだけ

feature/login に移ってからコミットし、両方のファイルの中身を比べました。

$ git switch feature/login
Switched to branch 'feature/login'
$ git commit -m "ログイン処理を追加"
[feature/login 1226597] ログイン処理を追加
 1 file changed, 2 insertions(+)
 create mode 100644 login.py
$ cat .git/refs/heads/main .git/refs/heads/feature/login
188ca2e72c39044ef365df726ab1f86dcea8e2f0
1226597822a055346bfd8bad003426ec39322cd6
$ git log --oneline --decorate --graph --all
* 1226597 (HEAD -> feature/login) ログイン処理を追加
* 188ca2e (main) 税率の設定を追加
* 95b0788 カートの合計を計算

main のファイルは 188ca2e のまま、feature/login だけが新しいコミット 1226597 に書き換わりました。 コミットのたびに「HEAD が指しているブランチのファイル」が新しいIDで上書きされる、というのが Git のブランチの動きのすべてです。

git log --oneline --decorate --graph --all は、全部のブランチの位置と分かれ方を1画面で見せてくれるので、ブランチの操作に慣れるまでは、操作のたびに実行すると状態をつかみやすくなります。

git switch と git checkout の違い(ブランチの切り替え)

この節では、ブランチを切り替える2つのコマンドの違いと、どちらを使えばよいかが分かります。

ブランチの切り替えには git switch を使うのが分かりやすく、git checkout でも同じことができます。 Git 2.23 のリリースノートには、それまで git checkout 1つが受け持っていた「ブランチを切り替える」と「ファイルを戻す」を分けるために、git switch と git restore の2つを追加した、と書かれています。

切り替えのコマンド

checkoutブランチの切り替えもファイルの取り消しも1つのコマンド。git checkout 名前 が、ブランチ名かファイル名かで動きが変わる
→
switchブランチの切り替えだけを受け持つ。ファイルを戻すのは git restore

入門の段階では switch と restore で覚えると、取り違えが起きにくい

1

切り替える

git switch main。ローカルにあるブランチへ移る。

checkout main と同じ

2

作って切り替える

git switch -c 名前。checkout の -b にあたる。

起点も指定できる

3

直前のブランチへ戻る

git switch -。@{-1} と同じ意味で、2つのブランチを行き来する。

cd - と同じ考え方

4

コミットを見に行く

git switch --detach 188ca2e。ブランチではなくコミットへ移る。

detached HEAD になる

実際に切り替えると、作業フォルダーのファイルが入れ替わります。login.py は feature/login にしか無いので、main に戻ると消え、戻ってくると現れました。

$ git switch main
Switched to branch 'main'
$ ls
README.md  cart.py  config.py
$ git switch -
Switched to branch 'feature/login'
$ ls
README.md  cart.py  config.py  login.py

ファイルが消えたように見えても、コミットしてあれば .git の中に残っています。ブランチを切り替えるのは「作業フォルダーを、そのブランチの先端のコミットの状態に入れ替える」操作です。

switch の全オプションと、checkout との細かな違い(ファイルを戻す restore を含む)は、関連記事「git switchとは|使い方・オプション一覧とcheckoutとの違い」で扱っています。

コミットしていない変更はブランチを切り替えるとどうなるか

この節では、作業中の変更を残したままブランチを切り替えたときに、変更が持ち越されるのか止められるのかが、実行結果で分かります。

コミットしていない変更は、どのブランチにも属していません。 そのため、切り替えても安全なときは変更がそのまま付いてきて、切り替えると変更が失われるときは Git が止めます。

付いてくる場合

cart.py を書き換えたまま(コミットせずに)feature/login へ切り替えました。cart.py は main と feature/login で同じ中身なので、変更はそのまま持ち越されました。

$ git status -s
 M cart.py
$ git switch feature/login
Switched to branch 'feature/login'
M	cart.py
$ git status -s
 M cart.py

切り替えの直後に出た M cart.py は「変更中の cart.py を持ってきた」という知らせです。main で書いていたつもりの変更が、切り替えたあとのブランチでコミットされることがあるので、切り替える前に git status を見る習慣をつけると安全です。

止められる場合

README.md を書き換えたまま、README.md の中身が違うブランチへ切り替えようとすると、Git は切り替えを止めました。

$ git switch feature/coupon
error: Your local changes to the following files would be overwritten by checkout:
	README.md
Please commit your changes or stash them before you switch branches.
Aborting

「切り替えると、今の変更が上書きされて消える」ので止めた、という意味です。対処は3つあります。

対処 コマンド 向いている場面
コミットしてから切り替える git commit -am "作業途中" 今のブランチの変更として残したい
一時的に退避する git stash → 切り替え → 戻って git stash pop 急ぎで別のブランチを見たい
変更を捨てる git restore README.md その変更は要らない

git switch --discard-changes や -f でも切り替えられますが、変更は消えて戻せません。退避の方法は git stash の記事、ブランチを並べて同時に開く方法は git worktree の記事で扱っています。

ブランチを統合する:fast-forward と 3-way マージ

この節では、ブランチを main に合流させる手順と、Git が選ぶ2種類のマージの違いが、log --graph の実物で分かります。

統合するときは、取り込む側(main)に移ってから git merge 取り込みたいブランチ を実行します。 履歴の形によって、Git は fast-forward か 3-way マージのどちらかを行います。

flowchart TD
    Q{"分岐している?"}
    Q -->|いいえ| FF["fast-forward
目印を進めるだけ"] Q -->|はい| TW["3-way マージ
親2つのコミットを作る"]

fast-forward(目印を前に進めるだけ)

main に新しいコミットが無く、feature/login が main の先に一直線に伸びているときです。

$ git switch main
Switched to branch 'main'
$ git merge feature/login
Updating 188ca2e..1226597
Fast-forward
 login.py | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 login.py
$ git log --oneline --decorate --graph --all
* 1226597 (HEAD -> main, feature/login) ログイン処理を追加
* 188ca2e 税率の設定を追加
* 95b0788 カートの合計を計算

新しいコミットは作られず、main の目印が 188ca2e から 1226597 に動いただけです。 Updating 188ca2e..1226597 が、main のファイルの中身がどう書き換わったかをそのまま表しています。

3-way マージ(合流のコミットを作る)

feature/coupon を切ったあと、main にも別のコミットを積んで、履歴を分岐させてからマージしました。

$ git log --oneline --decorate --graph --all
* ab2f771 (HEAD -> main) READMEに使い方を追記
| * 15aa812 (feature/coupon) クーポン割引を追加
|/
* 1226597 (feature/login) ログイン処理を追加
...
$ git merge feature/coupon
Merge made by the 'ort' strategy.
 coupon.py | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 coupon.py
$ git log --oneline --decorate --graph --all
*   1d4ffe2 (HEAD -> main) Merge branch 'feature/coupon'
|\
| * 15aa812 (feature/coupon) クーポン割引を追加
* | ab2f771 READMEに使い方を追記
|/
* 1226597 (feature/login) ログイン処理を追加
* 188ca2e 税率の設定を追加
* 95b0788 カートの合計を計算
$ git cat-file -p HEAD
tree 82f31cb228a8e8007cc9bb34571f3eb3abdc9ed1
parent ab2f771c809dd2e512e1087794261b834bbb74a7
parent 15aa812c2ba296122710e67ab532d2effa3ea214
...
Merge branch 'feature/coupon'
  • Git は、2つのブランチの先端と、共通の祖先(分かれた地点、ここでは 1226597)の3つを比べて新しいスナップショットを作ります。これが「3-way」の意味です。
  • できたマージコミット 1d4ffe2 には parent が2行あります。親を2つ持つコミットが、log --graph の合流点です。
  • 表示の 'ort' はマージの方式の名前です。Git 2.34 のリリースノートで、既定の方式が recursive から ort に変わりました。以前の版の出力例では Merge made by the 'recursive' strategy. と表示されています。

1fast-forward

分岐していないとき。目印が進むだけで、マージコミットはできない。履歴は一直線。

23-way マージ

分岐しているとき。共通の祖先と両方の先端から、親2つのマージコミットを作る。

3コンフリクト

同じファイルの同じ場所を両方で変えていると、自動でまとめられず止まる。直してからコミットする。

マージした後は、git branch --merged で「main に取り込み済みのブランチ」を確かめてから消せます。

$ git branch --merged
  feature/coupon
  feature/login
* main

fast-forward でもマージコミットを残す --no-ff や、まとめて1つのコミットにする --squash、履歴を付け替える rebase との使い分けは、関連記事「git mergeとrebaseの違い|使い分けとコンフリクト解消」で扱っています。同じ場所を両方で変えたときに出るコンフリクトの直し方は、関連記事「Gitのコンフリクトの解消方法|マーカーの読み方から防ぎ方まで」で扱っています。

リモートブランチと追跡ブランチ(origin/main・push -u・ahead/behind)

この節では、origin/main が何を指しているのか、ローカルのブランチとリモートのブランチがどうつながるのかが分かります。

origin/main は「最後に通信したとき、リモート(origin)の main がどのコミットを指していたか」を写した、手元の目印です。 Pro Git はこれを「リモート追跡ブランチ」と呼び、利用者が直接動かすことはできず、git fetch などの通信のときに Git が更新する、と説明しています。

同じマシンに bare リポジトリを作って origin にし、push しました。

$ git remote add origin ../origin.git
$ git push -u origin main
To ../origin.git
 * [new branch]      main -> main
branch 'main' set up to track 'origin/main'.
$ git branch -vv
  feature/coupon 15aa812 [origin/feature/coupon] クーポン割引を追加
  feature/login  1226597 ログイン処理を追加
* main           1d4ffe2 [origin/main] Merge branch 'feature/coupon'
$ git branch -r
  origin/feature/coupon
  origin/main
$ find .git/refs/remotes -type f
.git/refs/remotes/origin/feature/coupon
.git/refs/remotes/origin/main
  • リモート追跡ブランチも、.git/refs/remotes/origin/ の下のファイルです。中身はやはり40文字のIDでした。
  • -u(--set-upstream)を付けて push すると、ローカルの main と origin/main がつながります(上流ブランチ、upstream)。git branch -vv の [origin/main] がそのつながりです。
  • feature/login は push していないので、追跡先が表示されていません。

ahead・behind の読み方

ローカルでコミットすると ahead(先行)になり、別の人が origin の main に push したものを fetch すると behind(遅れ)も付きます。

$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

$ git fetch
$ git branch -vv
* main            cfb7285 [origin/main: ahead 1, behind 1] README更新
$ git status
On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.
表示 意味 次にすること
[origin/main] 手元と origin/main が同じ なし
ahead 1 手元にだけコミットが1つある git push
behind 1 リモートにだけコミットが1つある git pull
ahead 1, behind 1 両方に別のコミットがある(分岐) pull でマージか rebase を選ぶ
[origin/x: gone] リモートのブランチが消された 手元のブランチも消すか判断する

ahead・behind は「最後に fetch した時点の」origin/main との比較です。fetch しないと behind は増えません。

他の人が作ったブランチで作業する

別の場所から origin に feature/search が push されたあと、手元で fetch して、同じ名前で switch しました。

$ git fetch
From ../origin
 * [new branch]      feature/search -> origin/feature/search
$ git switch feature/search
Switched to a new branch 'feature/search'
branch 'feature/search' set up to track 'origin/feature/search'.

$ git switch origin/main
fatal: a branch is expected, got remote branch 'origin/main'
hint: If you want to detach HEAD at the commit, try again with the --detach option.

origin/ を付けずに名前だけで switch すると、追跡つきのローカルブランチが作られて移れました。 git-scm.com のリファレンスでは、この動きは --guess と呼ばれ、既定で有効です。反対に origin/main そのものへは switch できません(リモート追跡ブランチは手元で動かせない目印のため)。fetch と pull の違いは関連記事「git fetchとpullの違い|図解とpull –rebaseの使い分け」で扱っています。

detached HEADとは(原文と戻り方)

この節では、detached HEAD の意味と、その状態で作ったコミットを失わずに戻る方法が分かります。

detached HEAD は、HEAD がブランチではなくコミットを直接指している状態です。 過去のコミットやタグ、origin/main を checkout したときに起きます。

$ git checkout 188ca2e
Note: switching to '188ca2e'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 188ca2e 税率の設定を追加
$ cat .git/HEAD
188ca2e72c39044ef365df726ab1f86dcea8e2f0
$ git branch
* (HEAD detached at 188ca2e)
  feature/coupon
  ...

.git/HEAD の中身が ref: refs/heads/… ではなく、コミットIDそのものになっています。 これが「頭(HEAD)がブランチから外れた(detached)」の意味です。見て回るだけなら問題はなく、git switch - か git switch main で戻れます。

この状態でコミットしてから main に戻ると、Git は次の警告を出しました。

$ git commit -m "軽減税率を試す"
[detached HEAD f8970a0] 軽減税率を試す
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git switch main
Warning: you are leaving 1 commit behind, not connected to
any of your branches:

  f8970a0 軽減税率を試す

If you want to keep it by creating a new branch, this may be a good time
to do so with:

 git branch <new-branch-name> f8970a0

Switched to branch 'main'

コミット f8970a0 を指すブランチが無いので、このままでは一覧にもログにも出てこなくなります。警告に出ているIDでブランチを作れば、コミットは残ります。 警告を見逃したときは、HEAD の移動の記録(reflog)からIDを探します。

$ git reflog -5
cfb7285 HEAD@{0}: checkout: moving from f8970a0de389b576b96b8d6af1d6f808615ec590 to main
f8970a0 HEAD@{1}: commit: 軽減税率を試す
188ca2e HEAD@{2}: checkout: moving from main to 188ca2e
...
$ git branch try/reduced-tax f8970a0
$ git log --oneline --graph try/reduced-tax -3
* f8970a0 軽減税率を試す
* 188ca2e 税率の設定を追加
* 95b0788 カートの合計を計算

reflog の記録には期限があり、どこからもたどれないコミットはいずれ git gc で消えます。戻し方の詳細と、時間がたってからの探し方は、関連記事「detached HEADの戻し方|gitのコミットが消えたとき」で扱っています。

mainとmasterの違い(デフォルトブランチ)

この節では、main と master のどちらが正しいのか、最初のブランチ名を決める設定が分かります。

main と master は名前が違うだけで、どちらにも特別な機能はありません。 Pro Git は、master は特別なブランチではなく、git init が最初に作るブランチの既定の名前というだけだ、と説明しています。GitHub Docs は、GitHub では新しいリポジトリの既定のブランチに main という名前を付ける、と書いています。

手元の Git 2.43.0 で、何も設定せずに git init すると master になり、次の案内が出ました。

$ git init demo
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: 	git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: 	git branch -m <name>
Initialized empty Git repository in /srv/s4/r17/t56/w/demo/.git/
$ cat demo/.git/HEAD
ref: refs/heads/master
やりたいこと コマンド 結果(手元)
今後の init をすべて main にする git config --global init.defaultBranch main 次の init から HEAD が refs/heads/main
このリポジトリだけ main で作る git init -b main 案内が出ずに main で始まる
作った後で master を main にする git branch -m master main ファイル名が変わるだけ。コミットはそのまま

GitHub に main で作ったリポジトリへ、手元の master を push すると、ブランチが2本並ぶことがあります。手元と GitHub で最初のブランチ名を揃えておくと迷いません。 最初の push までの手順は、関連記事「git initの使い方|既存フォルダを最初のpushまで進める手順」で扱っています。

ブランチ名の付け方と、一覧・削除・名前変更

この節では、ブランチ名に使えない文字とよく使われる名前の付け方、ブランチの一覧・削除・名前変更の基本が分かります。

使えない文字

ブランチ名はファイルのパスとして保存されるため、使えない文字があります。 規則は git-scm.com の git check-ref-format のページにまとまっていて、git check-ref-format --branch 名前 で手元で確かめられます。

名前 結果 理由
feature/login 使える スラッシュで区切るとフォルダーになる
機能/ログイン 使える 日本語も使える(ターミナルの文字コードに注意)
feature/a b 使えない 空白は使えない
fix..tax 使えない ドット2つの連続は使えない
fix~1・wip: 使えない ~ ^ : ? * [ は使えない
feature/ 使えない スラッシュで終われない
hotfix.lock 使えない .lock で終われない
-x 使えない ハイフンで始められない

使えない名前で作ろうとすると、fatal: 'feature/a b' is not a valid branch name になりました。もう1つ、フォルダーとファイルが同じ名前になる組み合わせも作れません。

$ git branch feature
fatal: cannot lock ref 'refs/heads/feature': 'refs/heads/feature/coupon' exists; cannot create 'refs/heads/feature'

refs/heads/feature/ がフォルダーとして使われているので、refs/heads/feature というファイルは作れない、という意味です。ブランチがファイルだと知っていると、このエラーの理由がすぐ分かります。

よく使われる名前の形

  • 1種類/内容 の形にするfeature/login・fix/tax-rounding・hotfix/payment-timeout・docs/readme など
  • 2課題の番号を入れるfeature/123-login のようにすると、Issue やチケットとつなげやすい
  • 3英小文字とハイフンにそろえる大文字小文字を区別しないファイルシステム(Windows・Mac の既定)では Feature/Login と feature/login がぶつかりやすい
  • 4短く、目的が分かる名前にするtest・tmp・new だけの名前は、1週間後に何のブランチか分からなくなる

チームでどの種類のブランチをいつ切るか(Git Flow・GitHub Flow・GitLab Flow)は、関連記事「Gitのブランチ戦略|Git Flow・GitHub Flowの違いと選び方」で扱っています。

一覧・削除・名前変更(git branch のオプション)

ブランチの一覧の見方と、削除・名前変更・リモートのブランチの扱いの基本です。

やりたいこと コマンド メモ
ローカルの一覧 git branch * が今いるブランチ
先端のコミットも表示 git branch -v/-vv -vv は追跡先と ahead/behind も
リモート追跡ブランチの一覧 git branch -r/-a -a はローカルとリモートの両方
取り込み済み・未取り込み git branch --merged/--no-merged 消してよいかの判断に使う
あるコミットを含むブランチ git branch --contains 188ca2e 修正がどこまで入ったかを調べる
削除(取り込み済みだけ) git branch -d 名前 未マージなら止まる
強制削除 git branch -D 名前 未マージのコミットも目印を失う
名前変更 git branch -m 前 新 今のブランチなら -m 新
リモートのブランチを削除 git push origin --delete 名前 共有中のブランチは周知してから

main に取り込んでいないブランチを -d で消そうとすると、Git は止めました。

$ git branch -d spike
error: the branch 'spike' is not fully merged.
If you are sure you want to delete it, run 'git branch -D spike'
$ git branch -d main
error: cannot delete branch 'main' used by worktree at '/srv/s4/r17/t56/w/shop'

2つ目は「今いるブランチは消せない」というエラーで、別のブランチに移ってから消します。ブランチを消しても消えるのは目印のファイルだけで、コミットはしばらく .git の中に残ります(reflog でIDが分かれば git branch 名前 ID で戻せます)。削除と名前変更の詳しい手順と、リモートのブランチの扱いは、関連記事「gitブランチの削除と名前変更|-d・-D・-mとリモートブランチ削除」で扱っています。

git ブランチのよくあるエラー/つまずき(原文つき)

この節では、ブランチの操作でよく出るエラーの原文と、意味・直し方が一覧で分かります。

すべて手元の Git 2.43.0 で出した原文です。

エラーの原文 意味 直し方
fatal: invalid reference: feature/logn その名前のブランチが無い(綴りの誤り) git branch -a で名前を確かめる。リモートだけにあるなら先に git fetch
fatal: a branch named 'feature/login' already exists 同じ名前がもうある 作らずに git switch feature/login で移る
fatal: 'feature/a b' is not a valid branch name 使えない文字が入っている 空白や ~ ^ : を取り除く
fatal: cannot lock ref 'refs/heads/feature' feature/… がフォルダーとしてある 別の名前にする(feature-x など)
error: Your local changes to the following files would be overwritten by checkout 切り替えると作業中の変更が消える commit か stash してから切り替える
error: the branch 'spike' is not fully merged. 取り込んでいないコミットがある 要らないと確かめてから -D
error: cannot delete branch 'main' used by worktree 今いるブランチを消そうとした 別のブランチへ移ってから消す
fatal: a branch is expected, got remote branch 'origin/main' リモート追跡ブランチへは switch できない git switch main(名前だけ)か --detach
fatal: your current branch 'main' does not have any commits yet まだ1つもコミットが無い 最初のコミットをすると main ができる
fatal: not a valid object name: '0a0a0a0' 起点に指定したIDが存在しない git log --oneline か reflog でIDを確かめる
  • 「ブランチを作ったのに変更が main に入っている」:git branch 名前 は作るだけで移らないため、main のままコミットしていることがあります。git branch --show-current で今いるブランチを確かめます。
  • 「git branch に何も出ない」:まだ1つもコミットしていないと、ブランチは表示されません。
  • 「同僚のブランチが見えない」:git fetch するまで、手元の origin/… は更新されません。

判断表:いつブランチを切るか・どのコマンドを使うか

この節では、作業の場面ごとに、ブランチを切るかどうかと使うコマンドが判断表で分かります。

場面 ブランチを切るか 使うコマンド
新しい機能を作り始める 切る(main から) git switch -c feature/名前 main
本番で見つかった不具合を急いで直す 切る(リリース中のブランチから) git switch -c hotfix/名前 origin/main
うまくいくか分からない書き換えを試す 切る(捨ててよい前提で) git switch -c try/名前
過去の版の動きを見るだけ 切らない git switch --detach ID
過去の版から直したい 切る(そのIDから) git switch -c fix/名前 ID
同僚のブランチをレビューで動かす 切らない(同じ名前で追跡) git fetch → git switch 名前
1人で使う練習用のリポジトリ 切らなくてもよいが、練習には切る git switch -c practice
2つのブランチを同時に開いておきたい ブランチとは別の仕組み git worktree add

ブランチをどれくらいの大きさにするかの目安です。

  1. 11つのブランチは1つの目的にするログインとクーポンを同じブランチに混ぜない。レビューも取り消しも楽になる
  2. 2短い期間で合流させる長く分かれているほど main との差が開き、コンフリクトが増える
  3. 3長くなるなら main をこまめに取り込むgit merge main か rebase で差を小さく保つ
  4. 4合流させたら消す--merged で確かめて -d。一覧が短いと間違えにくい

よくある質問

Q. ブランチとは簡単に言うと何ですか? A. 履歴を枝分かれさせて、本流(main)を壊さずに別の作業を進める仕組みです。Git の中では、枝の先端のコミットを指す名前付きの目印(.git/refs/heads の下の41バイトのファイル)です。

Q. 「ブランチを切る」とはどういう意味ですか? A. 新しいブランチを作ることです。git switch -c 名前 で作って移るか、git branch 名前 で作るだけにします。指定しなければ、今いるコミットから切られます。

Q. ブランチとマージの違いは何ですか? A. ブランチは履歴を分ける操作(と、その目印)、マージは分かれた履歴を1つにまとめる操作です。ブランチで作業し、終わったらマージで本流に戻す、という組で使います。

Q. ブランチはいくつまで作れますか? A. 手元で1,000本作っても、増えたのは目印のファイルだけで、オブジェクトは1つも増えませんでした。数の上限より、一覧が長くなって目的が分からなくなるほうが困るので、合流したブランチは消します。

Q. ブランチとフォークの違いは何ですか? A. ブランチは同じリポジトリの中の枝、フォークは GitHub などでリポジトリそのものを自分のアカウントに複製したものです。書き込み権限のないリポジトリに変更を提案するときにフォークを使い、フォークの中でもブランチを切って作業します。

Q. コミットしないでブランチを切り替えるとどうなりますか? A. 切り替え先でも同じファイルが同じ中身なら、変更はそのまま付いてきます。上書きされて消えてしまう場合は、Git が Your local changes ... would be overwritten と表示して切り替えを止めます。

Q. ブランチを削除するとコミットも消えますか? A. 消えるのは目印だけで、コミットはしばらく .git の中に残ります。reflog でIDを探して git branch 名前 ID を実行すれば戻せます。どこからもたどれないコミットは、時間がたつと git gc で消えます。

Q. main で直接作業してはいけないのですか? A. 1人の練習なら main だけでも動きます。チームで使うときは、main を常に動く状態に保ち、レビューの単位を作るために、作業ごとにブランチを切るのが一般的です。リポジトリによっては main への直接の push が設定で禁止されています。

Q. git checkout と git switch はどちらを使えばよいですか? A. ブランチの切り替えは git switch、ファイルを戻すのは git restore と分けて覚えると、取り違えが起きにくくなります。git checkout も引き続き使え、以前からの手順書や記事では checkout で書かれていることが多いです。

Q. origin/main と main は何が違いますか? A. main は手元で作業するブランチ、origin/main は最後に通信したときのリモートの main の位置を写した目印です。origin/main は fetch や pull のときだけ動き、手元でコミットしても動きません。

Q. Git のブランチが Subversion より軽いのはなぜですか? A. Git のブランチはコミットを指すファイル1つで、作ってもファイル一式を複製しないからです。Git はファイルの差分ではなく、コミットごとのスナップショットを持っていて、ブランチはその先端の場所を覚えているだけです。

まとめ

  • ブランチは、履歴を枝分かれさせて本流を守りながら作業する仕組み。Git の中では、コミットを指す41バイトのファイル(.git/refs/heads/名前)。
  • HEAD は今いるブランチを指す目印で、中身は ref: refs/heads/main。コミットすると、HEAD が指すブランチの目印だけが前へ進む。
  • ブランチを切るのは git switch -c 名前、切り替えは git switch 名前。git branch 名前 は作るだけで移らない。
  • 統合は、取り込む側に移って git merge。分岐していなければ fast-forward、分岐していれば親2つのマージコミットができる(手元の 2.43 では 'ort' 方式)。
  • origin/main は最後の通信時点のリモートの位置。detached HEAD で作ったコミットは、git switch -c か reflog から git branch で残す。

次に読むとよい記事です。チームでのブランチの運用は関連記事「Gitのブランチ戦略|Git Flow・GitHub Flowの違いと選び方」、統合の方法の選び方は関連記事「git mergeとrebaseの違い|使い分けとコンフリクト解消」で扱っています。

参考・出典

確認日はいずれも 2026年10月29日です。

  • Pro Git(日本語版)「3.1 Git のブランチ機能 - ブランチとは」:https://git-scm.com/book/ja/v2/Git-のブランチ機能-ブランチとは
  • Pro Git(日本語版)「3.2 Git のブランチ機能 - ブランチとマージの基本」:https://git-scm.com/book/ja/v2/Git-のブランチ機能-ブランチとマージの基本
  • Pro Git(日本語版)「3.5 Git のブランチ機能 - リモートブランチ」:https://git-scm.com/book/ja/v2/Git-のブランチ機能-リモートブランチ
  • Git「git-switch Documentation」:https://git-scm.com/docs/git-switch
  • Git「git-check-ref-format Documentation」:https://git-scm.com/docs/git-check-ref-format
  • Git のリリースノート 2.23.0(git switch・git restore の追加):https://github.com/git/git/blob/master/Documentation/RelNotes/2.23.0.adoc
  • Git のリリースノート 2.34.0(既定のマージ方式が ort に):https://github.com/git/git/blob/master/Documentation/RelNotes/2.34.0.adoc
  • GitHub Docs「ブランチについて」:https://docs.github.com/ja/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches
  • GitHub Docs「既定のブランチを変更する」:https://docs.github.com/ja/repositories/configuring-branches-and-merges-in-your-repository/managing-branches-in-your-repository/changing-the-default-branch

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「ブランチとは?Gitの正体は41バイトのファイル|切る・切替・統合」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ
参加受付中

AI駆動開発、 無料セミナー