Skip to content

Git チートシート

ソースコードの変更を追跡するための分散バージョン管理システム。

01

設定と初期化

グローバルとローカル設定

Git は3つのレベルで設定を保存します:システム(/etc/gitconfig)、グローバル(ユーザーの ~/.gitconfig)、ローカル(リポジトリごとの .git/config)。下位レベルが上位レベルを上書きします。コミット前に必ず user.name と user.email を設定してください。そうしないと役に立たないデフォルトIDが使用されます。init.defaultBranch を main に設定すると、非推奨の master デフォルトを避け、現代の慣行に合わせることができます。

git
# set user identity (required for commits)
git config --global user.name "Alice Lee"
git config --global user.email "[email protected]"

# set default editor and branch name
git config --global core.editor "code --wait"
git config --global init.defaultBranch main

# view all settings and their origin
git config --list --show-origin

# edit config files directly
git config --global --edit        # ~/.gitconfig
git config --edit                 # repo .git/config

リポジトリの作成とクローン

git init はバージョンデータをすべて格納する隠し .git ディレクトリを追加して空のリポジトリを作成します。git clone は完全な履歴を含むリモートリポジトリをコピーします。最新のスナップショットのみが必要な場合(CI ビルドなど)は --depth 1 でシャロークローンを使用します — ダウンロードサイズを劇的に削減します。--single-branch は無関係なブランチの取得を避けます。

git
# create a new repo from scratch in current dir
mkdir my-app && cd my-app
git init

# clone a remote repository
git clone https://github.com/user/repo.git

# clone into a specific folder name
git clone https://github.com/user/repo.git my-folder

# clone a single branch (saves bandwidth)
git clone -b dev --single-branch https://github.com/user/repo.git

# shallow clone: only the latest commit
git clone --depth 1 https://github.com/user/repo.git

エイリアスとショートカット

エイリアスは頻繁に使用するコマンドやコマンドシーケンスに短い名前を定義できます。gitconfig の [alias] セクションに保存されます。! で始まるエイリアスはシェルコマンドとして実行され、複雑なワークフローを可能にします。上記の lg エイリアスは、ブランチ構造を理解するのに非常に便利なコンパクトな視覚的履歴グラフを生成します。

git
# create shortcuts for common commands
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all"

# now use them
git co main
git lg

# alias that runs an external command (starts with !)
git config --global alias.unstage "reset HEAD --"
git unstage file.txt

ヘルプとドキュメント

Git には包括的な組み込みドキュメントが付属しています。git help <コマンド> はページャで man ページを開きます。-h フラグはオプションの1画面の要約を表示します。ガイド(git help -g)にはチュートリアル、用語集、日常のワークフローリファレンスが含まれており — 用語を学ぶ初心者に最適です。

git
# open the full manual for a command
git help commit
git commit --help

# show a concise synopsis
git commit -h

# list all git commands
git help -a

# list all guides (tutorial, glossary, etc.)
git help -g
git help glossary

.gitignore パターン

.gitignore は Git がバージョン管理から除外するファイルを指定します — ビルド成果物、依存関係、シークレットに不可欠です。パターンは glob 構文を使用し、末尾のスラッシュはディレクトリにマッチします。! を先頭に付けるとパターンを否定し、ファイルの追跡を強制します。.gitignore 自体はコミットしてチームで無視ルールを共有すべきです。既に追跡されているファイルは新しい無視パターンの影響を受けません — まず git rm --cached で削除してください。

git
# .gitignore file — patterns for files to skip
node_modules/
*.log
.env
.env.local
dist/
build/

# but track this specific file even if it matches
!important.log

# ignore all .txt files in build/ but not subdirs
build/*.txt

# ignore everything in a folder except one file
secrets/*
!secrets/template.env
02

ステージングとコミット

ステータスとステージング

Git は2段階モデルを使用します:変更はコミットされる前にステージングエリア(インデックス)に入ります。git status は変更、ステージ済み、未追跡を表示します。git add -p はパッチの個別ハンクをステージでき — 乱雑な作業ツリーを焦点を絞った論理的なコミットに分割するのに不可欠です。git restore --staged(モダンなコマンド)で編集を失わずにステージ解除できます。

git
# see current state of working tree
git status
git status -s              # short format
git status -sb             # short + branch info

# stage changes
git add file.txt           # one file
git add src/               # a directory
git add .                  # all changes in repo
git add -p                 # stage interactively by hunk

# unstage a file (keep changes in working dir)
git restore --staged file.txt
git reset HEAD file.txt    # older syntax

変更のコミット

コミットはステージされた変更のスナップショットを記録します。メッセージは命令法で書きます('added feature' ではなく 'add feature')。-a フラグは既に追跡されているファイルのみをステージします — 新しいファイルには git add が必要です。--amend は最後のコミットを書き換えます。タイプミスの修正や忘れたファイルの追加に使用しますが、共有ブランチに既にプッシュしたコミットは決して修正しないでください。

git
# commit staged changes with a message
git commit -m "feat: add login form"

# multi-line commit message
git commit -m "feat: add login form" -m "Closes #42"

# stage tracked files AND commit in one step
git commit -am "fix: correct typo"

# amend the previous commit (keep message)
git commit --amend --no-edit

# amend and edit the message
git commit --amend -m "feat: add login form (v2)"

コミットメッセージの規約

Conventional Commits は構造化されたコミットメッセージのために広く採用されている仕様です。タイププレフィックス(feat、fix、docs など)により、自動化された変更履歴生成とセマンティックバージョニングが可能になります。! マーカーは破壊的変更を示します。空行で件名(50文字以内)と本文を区切り、さらに空行で 'Closes #123' のようなフッターを区切ります。これは GitHub で自動的に issue をクローズします。

git
# Conventional Commits format
feat: add user registration endpoint
fix: resolve crash on empty cart
docs: update API reference
style: format login component
refactor: extract validation logic
test: add unit tests for parser
chore: upgrade dependencies

# with scope and breaking change marker
feat(api): add pagination to list endpoint
fix!: change default port (BREAKING CHANGE)

# with body and footer
feat: add dark mode

Implement theme toggle using CSS variables.
Closes #128

log で履歴を表示

git log は履歴を探索する主要なツールです。--oneline --graph --all はブランチ構造を一目で理解するのに最も便利な組み合わせです。--author、日付範囲、--grep でメッセージ内容でフィルタできます。--stat はどのファイルが変更されたかと行数を表示し、--patch は各コミットの完全な diff を表示します。

git
# full history with details
git log
git log --oneline                 # one line per commit
git log --oneline --graph --all   # visual branch graph
git log -n 5                      # last 5 commits

# filter by author, date, or message
git log --author="Alice"
git log --since="2 weeks ago"
git log --grep="fix"

# show files changed in each commit
git log --stat
git log --patch                   # full diffs

diff と show

git diff はスナップショットを比較します — 引数なしだとインデックスに対する未ステージの変更を表示します。--staged はインデックスと HEAD を比較します。git show は単一コミットのメタデータとパッチを表示します。HEAD:path 構文でチェックアウトせずに任意のコミットの任意のファイルの内容を表示でき、古いバージョンの復元や履歴の調査に便利です。

git
# compare working tree, index, and commits
git diff                  # unstaged changes
git diff --staged         # staged but uncommitted
git diff HEAD             # all changes vs last commit
git diff main feature     # compare two branches
git diff abc1234 def5678  # compare two commits

# inspect a single commit
git show HEAD             # latest commit diff + metadata
git show abc1234
git show HEAD:file.txt    # view a file at a given commit
03

ブランチとマージ

ブランチの作成と切り替え

Git のブランチはコミットへの軽量なポインタです — 作成はほぼ瞬時です。git switch(Git 2.23+)はブランチ変更のためのモダンで安全な checkout の代替で、checkout はファイルの復元に予約されています。-d は未マージのブランチの削除を拒否し(作業を保護)、-D は強制削除します。ブランチリストをクリーンに保つため、マージ後に必ずブランチを削除してください。

git
# list branches
git branch                 # local branches
git branch -a              # local + remote
git branch -vv             # with tracking info

# create and switch
git branch feature         # create only
git checkout feature       # switch to it
git checkout -b feature    # create + switch (classic)
git switch -c feature      # create + switch (modern)

# delete branches
git branch -d feature      # safe delete (merged only)
git branch -D feature      # force delete

ブランチのマージ

ファストフォワードマージは、ターゲットに新しいコミットがない場合、ブランチポインタを単に前に移動します — 線形な履歴を生成します。--no-ff はマージコミットを強制し、ブランチが存在した事実を保存します(機能追跡に便利)。--squash はすべてのブランチコミットを1つのステージされた変更にまとめ、その後1回コミットします — main に統合する前にノイズの多い機能履歴を整理するのに最適です。

git
# merge feature into main
git checkout main
git merge feature

# fast-forward merge (default when possible)
#   main just moves forward to feature's commit

# create a merge commit (preserves branch history)
git merge --no-ff feature -m "Merge feature branch"

# squash all feature commits into one
git merge --squash feature
git commit -m "feat: add feature (squashed)"

# abort a merge with conflicts
git merge --abort

マージコンフリクトの解決

コンフリクトは同じ行が2つのブランチで異なる変更を受けた時に発生します。Git は両側を示すコンフリクトマーカー(<<<<<<<、=======、>>>>>>>)を挿入します。ファイルを望ましい最終状態に編集し、git add で解決済みとしてマークして解決します。マージを完了するにはコミットします。git mergetool は視覚的 diff ツールを起動します。圧倒された場合は、git merge --abort でマージ前の状態に戻れます。

git
# a conflict produces markers in the file
# <<<<<<< HEAD
# my changes (current branch)
# =======
# their changes (incoming branch)
# >>>>>>> feature

# edit the file to resolve, then:
git add resolved-file.txt
git commit                # finalize the merge

# use a merge tool
git mergetool

# see which files conflict
git status

# abandon the merge
git merge --abort

リベース

リベースはブランチのコミットを別のブランチの上にリプレイし、マージコミットのない線形な履歴を生成します。インタラクティブリベース(-i)はパワーツールです:squash はコミットをマージ、reword はメッセージを編集、drop はコミットを削除、edit はコミットを変更するために一時停止します。プッシュして共有したコミットは決してリベースしないでください — 履歴を書き換え、チームメイトのリポジトリを壊します。リベースは自分のローカルブランチでのみ使用してください。

git
# rebase feature onto main (replay feature commits)
git checkout feature
git rebase main

# interactive rebase — rewrite last 5 commits
git rebase -i HEAD~5
# options: pick, reword, squash, fixup, drop, edit

# continue, skip, or abort during a rebase
git rebase --continue
git rebase --skip
git rebase --abort

# rebase while pulling
git pull --rebase origin main

チェリーピックと reflog

チェリーピックは別のブランチの個別コミットを現在のブランチに適用します — ブランチ全体をマージせずにバグ修正をバックポートするのに便利です。reflog はすべての HEAD の移動(コミット、チェックアウト、リセット)を記録するローカルログで、約90日間保持されます。これはセーフティネットです:破壊的なリセットの後でも、reflog で古いコミットハッシュを見つけて復元できます。reflog データはローカルのみで、プッシュされません。

git
# apply a specific commit onto current branch
git cherry-pick abc1234
git cherry-pick abc1234 def5678   # multiple commits
git cherry-pick abc1234..def5678  # range (exclusive start)

# reflog: record of where HEAD has been
git reflog
git reflog show feature

# recover a 'lost' commit
git reset --hard HEAD@{2}

# view a branch's history of moves
git reflog show main
04

リモートリポジトリ

リモートの管理

リモートは別のリポジトリへの名前付き参照で、通常はフォークに origin、元のプロジェクトに upstream を使用します。git remote -v は fetch と push の URL を表示します。GitHub のフォークは upstream リモートを使用して元のリポジトリと同期します:upstream から fetch、merge または rebase、その後 origin に push します。set-url は HTTPS と SSH 認証の切り替えに便利です。

git
# list configured remotes
git remote -v
git remote show origin

# add a remote
git remote add origin https://github.com/user/repo.git

# add an upstream remote (for forks)
git remote add upstream https://github.com/original/repo.git

# rename or remove
git remote rename origin upstream
git remote remove origin

# change a remote URL (e.g. HTTPS to SSH)
git remote set-url origin [email protected]:user/repo.git

fetch、pull と push

fetch はリモートデータをダウンロードしますが、作業ツリーは変更しません — マージ前に安全に検査できます。pull = fetch + merge(--rebase で rebase)。新しいブランチの最初の push には -u が必要で、トラッキングを設定して以降の git push/pull が引数なしで動作するようにします。--force-with-lease は --force の安全な代替です:その間に他の人がプッシュしていない場合のみリモートを上書きし、チームメイトの作業の誤った上書きを防ぎます。

git
# download remote changes without merging
git fetch origin
git fetch --all --prune      # all remotes, drop deleted branches

# fetch + merge in one step
git pull
git pull --rebase            # rebase instead of merge

# push local commits to remote
git push origin main
git push -u origin feature   # push + set upstream tracking
git push                     # subsequent pushes (uses tracking)

# force push (rewrites remote history — DANGER)
git push --force-with-lease  # safer than --force

トラッキングとブランチの同期

トラッキングブランチはローカルブランチをリモートブランチにリンクし、git pull と git push が fetch/push 先を指定なしで把握できるようにします。-u(--set-upstream-to の短縮形)が最初の push でこれを設定します。チームメイトがリモートブランチを削除すると、ローカルのリモートトラッキング参照が古くなります — git remote prune origin でクリーンアップします。git fetch --prune は fetch 中にこれを自動的に行います。

git
# set upstream for current branch
git branch -u origin/main
git branch --set-upstream-to=origin/main

# create a local branch tracking a remote one
git checkout -b feature origin/feature
git switch feature           # auto-detects tracking branch

# delete a remote branch
git push origin --delete feature

# list all remote-tracking branches
git branch -r
git remote prune origin      # remove stale remote refs

プルリクエストのワークフロー

標準的な GitHub フロー:機能ブランチを作成、プッシュ、レビュー用のプルリクエストを開き、マージ後にブランチを削除します。フォークの場合、upstream リモートで元のリポジトリから変更をプルできます。フォークの main を定期的に upstream と同期しておくと、後の大規模で苦痛なマージを防げます。多くのチームはブランチリストを整理するために「マージ時に自動削除」を有効にしています。

git
# typical feature workflow
git checkout -b feature/login
# ... make changes, commit ...
git push -u origin feature/login

# create PR on GitHub, then after merge:
git checkout main
git pull origin main
git branch -d feature/login

# sync a fork with its upstream
git fetch upstream
git checkout main
git merge upstream/main
git push origin main

ベアリポジトリとミラー

ベアリポジトリには作業ツリーがありません — .git データのみを保存します。ベアリポジトリはサーバー(セルフホスト Git など)で複数人が push/pull する中央リモートとして使用されます。--mirror はリモートトラッキング参照を含むすべてをクローンし、バックアップやリポジトリのホスト間移行に使用されます。--all はすべてのブランチを、--tags はすべてのタグをプッシュします。

git
# create a bare repo (no working tree) — for servers
git init --bare project.git

# mirror clone (full copy including all refs)
git clone --mirror https://github.com/user/repo.git

# push all branches and tags
git push --all
git push --tags

# push a specific branch to a specific remote
git push origin local-name:remote-name
05

タグとリリース

軽量タグと注釈付きタグ

タグは特定のコミットをマークし、通常はリリースに使用します。軽量タグは単なる名前付きポインタで、注釈付きタグはタガー、日付、メッセージを保存する完全な Git オブジェクトです — 署名され不変なためリリースに推奨されます。慣例として v1.0.0 はセマンティックバージョニング(major.minor.patch)に従います。git show <タグ> でタグ付けされたコミットとタグ注釈を表示します。

git
# lightweight tag (just a pointer to a commit)
git tag v1.0.0

# annotated tag (stores metadata + message)
git tag -a v1.0.0 -m "Release 1.0.0"

# tag a specific commit
git tag -a v0.9.0 abc1234 -m "Old release"

# list and inspect tags
git tag
git tag -l "v1.*"
git show v1.0.0

タグのプッシュと共有

タグは明示的にプッシュされるまでローカルです — よくある落とし穴です。--follow-tags はプッシュされたコミットから到達可能な注釈付きタグのみをプッシュし、リリースワークフローで最も安全なデフォルトです。タグをチェックアウトすると「デタッチド HEAD」状態(ブランチ上にない)になります — 検査には問題ありませんが、変更を加えたい場合は最初にブランチを作成してください:git checkout -b fix/v1.0.1 v1.0.0。

git
# tags are NOT pushed by default
git push origin v1.0.0       # push one tag
git push origin --tags       # push all tags

# push tags + branches together
git push origin main --follow-tags

# delete a tag locally and remotely
git tag -d v1.0.0
git push origin --delete v1.0.0

# checkout code at a tag (detached HEAD)
git checkout v1.0.0

署名付きタグ(GPG)

署名付きタグとコミットは GPG(または新しい Git では SSH キー)を使用して、作成者の身元を暗号論的に証明します。これはなりすましを防ぎます — オープンソースリリースに不可欠です。配布者とユーザーは git tag -v でタグを検証できます。GitHub は署名付きコミットとタグに「Verified」バッジを表示します。tag.gpgsign=true を設定してタグを常に自動署名します。

git
# sign a tag with your GPG key
git tag -s v1.0.0 -m "Signed release 1.0.0"

# verify a signed tag
git tag -v v1.0.0

# configure signing key
git config --global user.signingkey ABCD1234
git config --global tag.gpgsign true   # sign all tags

# also sign commits
git commit -S -m "signed commit"
git config --global commit.gpgsign true

セマンティックバージョニング

セマンティックバージョニング(SemVer)はバージョン番号に意味を与えます:MAJOR は互換性のない API 変更、MINOR は後方互換性のある新機能、PATCH はバグ修正。プレリリースサフィックス(-alpha、-beta、-rc)は安定性を示します。SemVer に従うと、ライブラリのユーザーはアップグレードが安全かを知ることができます — 自動化ツールは SemVer 文字列を解析・比較して破壊的変更を検出できます。

git
# semantic versioning: MAJOR.MINOR.PATCH
v1.0.0   # initial stable release
v1.1.0   # new backward-compatible feature  -> MINOR
v1.1.1   # backward-compatible bug fix       -> PATCH
v2.0.0   # breaking change                   -> MAJOR

# pre-release tags
v2.0.0-alpha.1
v2.0.0-beta.1
v2.0.0-rc.1

# git tag with the version
git tag -a v1.2.0 -m "Add export feature"
git push origin v1.2.0

describe と changelog

git describe はコミットから到達可能な最新のタグを見つけ、何コミット先にあるかを報告します — v1.2.0-3-gabc1234 のようなビルドバージョン文字列の生成に最適です。ログ範囲構文 v1.1.0..v1.2.0 は v1.2.0 にあって v1.1.0 にないコミットを表示し、2つのリリース間のリリースノートや changelog を作成するのに必要なものです。

git
# describe the closest tag (great for versioning)
git describe --tags
# output: v1.2.0-3-gabc1234
# meaning: 3 commits after v1.2.0, commit hash abc1234

# use it for build versioning
VERSION=$(git describe --tags --always)
echo "Building $VERSION"

# generate a changelog between two tags
git log v1.1.0..v1.2.0 --oneline
git log v1.1.0..v1.2.0 --pretty=format:"- %s" > CHANGELOG.md
06

変更の取り消し

reset:soft、mixed、hard

reset は現在のブランチポインタを移動します。--soft は変更をステージしたまま保持(コミットのみ取り消し)— 再コミットに理想的です。--mixed(デフォルト)はステージ解除しますが作業ツリーの変更は保持します。--hard はすべてを完全に破棄します — 唯一の復元手段は reflog です。共有履歴を書き換え、分岐を引き起こすため、プッシュしたコミットには決して --hard を使用しないでください。

git
# reset moves HEAD and optionally the index/worktree
git reset --soft HEAD~1     # undo commit, keep staged
git reset --mixed HEAD~1    # undo commit + unstage (DEFAULT)
git reset --hard HEAD~1     # undo commit + discard changes

# reset to a specific commit
git reset --hard abc1234

# reset a single file to HEAD
git reset HEAD file.txt     # unstage
git checkout -- file.txt    # discard working changes

revert(安全な取り消し)

reset(履歴を書き換える)とは異なり、revert は対象コミットを逆転する新しいコミットを追加します — 履歴が保存されるため共有ブランチに安全です。これは既にプッシュされた変更を取り消す正しい方法です。マージコミットの revert には -m 1 でどの親ラインを保持するかを指定する必要があります(1 = マージ先のブランチ)。

git
# revert creates a NEW commit that undoes another
git revert abc1234
git revert HEAD             # undo last commit

# revert a range
git revert HEAD~3..HEAD

# revert without committing (stage the inverse)
git revert --no-commit abc1234

# revert a merge commit
git revert -m 1 abc1234     # -m 1 = keep main branch parent

restore と clean

git restore(Git 2.23+)は作業ツリー操作のためのモダンで焦点を絞ったコマンドで、checkout から懸念を分離します。--staged は作業変更に触れずにステージ解除します。git clean は未追跡ファイルを削除します — 常に最初に -n(ドライラン)で何が削除されるかをプレビューしてください。-x は積極的で、gitignore されたファイルも削除し、クリーンなビルドに便利ですが、シークレットやビルド成果物を消去する可能性があります。

git
# discard unstaged changes in a file
git restore file.txt
git checkout -- file.txt    # older syntax

# unstage a file (keep working changes)
git restore --staged file.txt

# restore a file from a specific commit
git restore --source=abc1234 file.txt

# remove untracked files
git clean -n                # dry run (preview)
git clean -fd               # remove untracked files + dirs
git clean -fdx              # also remove ignored files

amend と fixup

--amend は最後のコミットを書き換えます — タイプミスの修正や忘れたファイルの追加に便利ですが、プッシュしたコミットは決して修正しないでください。fixup ワークフローはエレガントです:小さな問題に気づいたら fixup コミットを作成し、git rebase -i --autosquash が自動的に並べ替えて対象コミットにスカッシュします。これにより履歴をクリーンに保ちながら、小さな修正を段階的にコミットできます。

git
# amend the last commit (message + content)
git add forgotten-file.txt
git commit --amend --no-edit

# change only the commit message
git commit --amend -m "better message"

# create a fixup commit (for later autosquash)
git commit --fixup=abc1234

# squash fixups during interactive rebase
git rebase -i --autosquash abc1234~1

reflog による復元

reflog はセーフティネットです。コミット、チェックアウト、reset、rebase のすべてを記録します — コミットを「破壊」する操作も含みます。エントリは約90日間保持されます。誤って reset --hard したりブランチを削除した場合、reflog で孤立したコミットハッシュを見つけて reset するか、そのハッシュを指す新しいブランチを作成できます。reflog はローカルのみなので、オフラインでも機能します。

git
# reflog records every HEAD movement
git reflog
# abc1234 HEAD@{0}: reset: moving to abc1234
# def5678 HEAD@{1}: commit: feat: add x
# ghi9012 HEAD@{2}: checkout: moving to feature

# recover a 'lost' commit
git reset --hard def5678

# recover a deleted branch
git branch recovered-feature def5678

# reflog for a specific branch
git reflog show feature
07

スタッシュとワークフロー

変更のスタッシュ

stash は未コミットの変更を退避し、クリーンなツリーでブランチを切り替えたり更新をプルできるようにします。apply はスタッシュをリストに保持(複数のブランチに適用したい場合に便利)し、pop は適用して削除します。スタッシュは stash@{N} で参照される LIFO スタックです。clear は慎重に使用してください — すべてのスタッシュを完全に破棄します。

git
# save uncommitted changes (reverts working tree to HEAD)
git stash
git stash push -m "wip: login form"   # with a message

# list, show, apply
git stash list
git stash show -p stash@{0}   # show diff
git stash apply               # apply latest, keep stash
git stash pop                 # apply latest, drop stash

# apply a specific stash
git stash apply stash@{2}

# drop a stash
git stash drop stash@{0}
git stash clear               # drop ALL stashes

部分スタッシュと選択的スタッシュ

これらのフラグは何をスタッシュするかを細かく制御します。--keep-index は論理的なコミットをステージしたが、その変更のみをテストしたい場合に便利です — 残りをスタッシュし、テストを実行して pop します。-u は未追跡ファイルを含め(そうでなければ作業ツリーに残ります)。-p は git add -p と同様に特定のハンクを選択できます。

git
# stash only staged changes
git stash --staged

# stash only unstaged changes (keep staged)
git stash --keep-index

# stash interactively by hunk
git stash -p

# stash including untracked files
git stash -u
git stash --include-untracked

# stash everything (even ignored)
git stash -a

スタッシュブランチと作成

git stash branch はスタッシュの元の親コミットで新しいブランチを作成し、そこにスタッシュを適用します — コンフリクトでスタッシュが現在のブランチにクリーンに適用できなくなった時に最適です。show -p でスタッシュをパッチファイルとしてエクスポートしてアーカイブや共有もできます。スタッシュはローカルでプッシュされないため、長期保存には使用しないでください。

git
# create a branch from a stash (great for conflicts)
git stash branch feature/wip stash@{0}

# create a commit from a stash without applying
git stash store -m "saved wip" stash@{0}

# apply a stash to a different branch
git checkout other-branch
git stash apply stash@{0}

# inspect stash contents
git stash show stash@{0} --stat
git stash show -p stash@{0} > patch.diff

Git ワークフローモデル

GitHub Flow が最もシンプルです:1つの main ブランチ、PR 付きの機能ブランチ、マージ時にデプロイ — 継続的デプロイに理想的です。Git Flow(Vincent Driessen のモデル)は構造化されたリリース管理のために develop、release、hotfix ブランチを追加します — バージョン管理された製品に適しています。Trunk-Based Development は非常に短命なブランチを使用し、最大限の統合速度を求める高性能な DevOps チームに好まれます。

git
# GitHub Flow (simple, popular)
# main is always deployable; feature branches + PRs
git checkout -b feature/x
git push -u origin feature/x
# open PR, review, merge to main, deploy

# Git Flow (structured, with release branches)
# main: production releases
# develop: integration branch
# feature/*: features off develop
# release/*: release prep
# hotfix/*: urgent fixes off main

# Trunk-Based Development
# short-lived branches (1-2 days), frequent rebase on main

サブモジュール

サブモジュールは1つの Git リポジトリを別のリポジトリに埋め込みます — ライブラリを独立してバージョン管理しながらプロジェクト間で共有するのに便利です。親リポジトリはサブモジュールの特定コミットへのポインタを保存します。クローンはデフォルトでサブモジュールの内容を取得しません。--recurse-submodules で1ステップで取得します。サブモジュールは扱いにくい場合があります。よりシンプルな依存関係管理には、Git subtrees やパッケージマネージャーを検討してください。

git
# add another repo as a submodule
git submodule add https://github.com/user/lib.git libs/lib

# clone a repo with its submodules
git clone --recurse-submodules https://github.com/user/repo.git

# initialize submodules in an existing clone
git submodule update --init --recursive

# update submodules to their latest remote commit
git submodule update --remote

# record a submodule pointer change
git add libs/lib
git commit -m "chore: bump lib submodule"
08

検査とデバッグ

blame と annotate

git blame(annotate とも呼ばれる)はファイルの各行のコミットと作成者を表示します — コードがなぜそのようになっているかを理解するために不可欠です。-L は行範囲に制限し、大きなファイルに便利です。-w は純粋な空白変更を無視し、-C は別のファイルから移動またはコピーされたコードを検出し、行が実際にどこから来たかのより正確な履歴を提供します。

git
# show who last changed each line
git blame file.txt
git blame -L 10,20 file.txt        # only lines 10-20
git blame -e file.txt              # show author email
git blame -w file.txt              # ignore whitespace changes
git blame -C file.txt              # detect moved lines across files

# GUI annotation in some editors
git gui blame file.txt

bisect(二分探索バグ発見)

bisect は履歴を二分探索してバグを導入した正確なコミットを特定します。既知の good と bad コミットをマークし、Git が中間点をチェックアウトし、テストして good/bad をマークし、毎回範囲を半分にします。スクリプトがあれば、プロセス全体を完全に自動化できます — 大規模な履歴の回帰バグに大きな時間を節約します。

git
# find the commit that introduced a bug
git bisect start
git bisect bad                 # current commit is broken
git bisect good v1.0.0         # v1.0.0 was working

# Git checks out a midpoint; test it, then:
git bisect good                # or git bisect bad

# automate with a script that exits non-zero on bug
git bisect start HEAD v1.0.0 -- npm test

# finish and return to original branch
git bisect reset

# view the bisect log
git bisect log

コードと履歴の検索

git grep は作業ツリーの追跡ファイルを検索します — インデックスを使用するため grep -r より高速です。-S 'pickaxe' オプションは特定の文字列を追加または削除したコミットを見つけ、関数やバグがいつ導入されたかを追跡するのに非常に便利です。-G は似ていますが diff 内の任意の場所の正規表現にマッチします。--author や --since フィルタと組み合わせて、履歴内の任意の変更を特定できます。

git
# search working tree for a string
git grep "TODO"
git grep -n "TODO" -- "*.js"
git grep -i "error" src/

# search across all commits (history)
git log -S "functionName" --oneline    # pickaxe: when added/removed
git log -G "functionName.*\(" --oneline  # regex match in diffs

# search commit messages
git log --grep="fix.*login" --oneline
git log --author="Alice" --since="1 week ago"

fsck とダングリングオブジェクト

git fsck(ファイルシステムチェック)はオブジェクトデータベースの整合性を検証し、ダングリングコミットを見つけられます — reflog が不十分な場合の復元に便利です。git gc はオブジェクトを再編成して圧縮しディスク容量を節約します。--prune=now は到達不能なオブジェクトを即座に削除します。Git は定期的に自動 gc を実行しますが、手動で実行すると大きなリポジトリを縮小できます。--aggressive は最大圧縮のためにデルタを再計算します。

git
# check repository integrity
git fsck --full
git fsck --unreachable

# find dangling (unreachable) commits & blobs
git fsck --lost-found

# garbage collect and prune old objects
git gc
git gc --prune=now
git gc --aggressive

# count objects and disk usage
git count-objects -v

archive と bundle

git archive は .git ディレクトリなしでコミットのクリーンなスナップショットをエクスポートします — リリースの配布や、履歴を必要としない人にソースを送るのに理想的です。git bundle はリポジトリ(またはコミット範囲)を1つのファイルにパッケージ化し、そこからクローンや fetch が可能です — リモートサーバーを使用できないエアギャップネットワーク間やメールでのリポジトリ転送に最適です。

git
# export a snapshot as a tar/zip (no .git history)
git archive --format=zip --output=app.zip HEAD
git archive --format=tar HEAD | gzip > app.tar.gz
git archive -o release.zip v1.0.0

# bundle a repo (with history) into a single file
git bundle create repo.bundle --all
git bundle create patch.bundle main..feature

# clone from a bundle (offline transfer)
git clone repo.bundle new-repo
git fetch patch.bundle feature
09

高度なテクニック

フック

フックは特定の時点で自動的に実行されるスクリプトです。クライアント側フック(pre-commit、commit-msg、pre-push)はリンティングやテストなどのローカルポリシーを強制します。サーバー側フック(pre-receive、post-receive)はリモートで実行され、ブランチ保護や CI/CD のトリガーを強制できます。.git/hooks ディレクトリには .sample で終わるサンプルスクリプトが含まれています — 有効化するにはリネームします。Husky や pre-commit フレームワークのようなツールはチームの一貫性のためにリポジトリ自体でフックを管理します。

git
# client-side hooks live in .git/hooks/
#   pre-commit    runs before a commit is created
#   commit-msg    validates the commit message
#   pre-push      runs before pushing to remote

# sample pre-commit hook (.git/hooks/pre-commit)
#!/bin/sh
npm run lint || exit 1
npm test || exit 1

# server-side hooks (on the remote)
#   pre-receive, update, post-receive

# make a hook executable
chmod +x .git/hooks/pre-commit

ワークツリー

ワークツリーを使用すると、1つのリポジトリに対して複数の作業ディレクトリを持ち、それぞれ異なるブランチにできます — クローンなしで。機能ブランチの作業ツリーを保持したままホットフィックスに取り組む必要がある場合や、別のブランチを編集しながら1つのブランチで長時間のビルドを実行する場合に不可欠です。すべてのワークツリーは同じ .git オブジェクトデータベースを共有するため、ディスク使用量は最小限です。

git
# create a second working tree of the same repo
git worktree add ../app-feature feature/x

# list worktrees
git worktree list

# create a worktree with a new branch
git worktree add -b hotfix/y ../app-hotfix main

# remove a worktree
git worktree remove ../app-feature

# prune stale worktree metadata
git worktree prune

履歴のフィルタと書き換え

シークレットや大きなファイルがコミットされた場合、履歴の書き換えが必要です。git filter-repo は git filter-branch のモダンで高速な代替です。BFG Repo-Cleaner は大きなファイルやパスワードパターンを削除するためのユーザーフレンドリーな代替です。書き換え後、force-push し、すべてのコラボレーターに再クローンを通知する必要があります — 古いコミットは期限切れになるまで reflog に残ります。漏洩したシークレットは常に即座にローテートしてください。

git
# remove a file from ALL of history (sensitive data)
git filter-repo --path secrets.env --invert-paths
# (install git-filter-repo; the old filter-branch is deprecated)

# rewrite author info across all commits
git filter-repo --mailmap mailmap.txt

# split a subdirectory into its own repo
git filter-repo --subdirectory-filter libs/lib

# the simpler BFG Repo-Cleaner (Java tool)
bfg --delete-files *.env
bfg --replace-text passwords.txt

スパースチェックアウトと部分クローン

部分クローン(--filter)はコミットとツリーをフェッチしますが、blob(ファイル内容)はアクセス時に遅延ダウンロードします — 巨大なリポジトリのクローンを劇的に高速化します。スパースチェックアウトは作業ツリーを特定のディレクトリに制限し、作業する部分のみを表示します。これらを組み合わせることで巨大なモノレポが管理可能になります:クローンが高速で、作業ツリーが小さく保たれます。

git
# partial clone: download history on demand
git clone --filter=blob:none https://github.com/user/huge-repo.git

# sparse checkout: only certain directories
git clone --no-checkout https://github.com/user/repo.git
cd repo
git sparse-checkout init --cone
git sparse-checkout set src docs
git checkout main

# add a directory to the sparse set later
git sparse-checkout add tests

# disable sparse checkout (fetch everything)
git sparse-checkout disable

reflog、refspec と notes

refspec は fetch/push 中に ref がどのようにマッピングされるかを明示的に制御します — ローカル機能ブランチをリモート main にプッシュするような珍しいワークフローに便利です。git notes はコミットにメタデータを書き換えずに付加でき、レビューコメントや CI リンクに便利です。notes は別の ref(refs/notes/commits)に保存され、明示的にプッシュ・フェッチする必要があります。

git
# refspec: explicit fetch/push mapping
git fetch origin "refs/heads/*:refs/remotes/origin/*"
git push origin "refs/heads/feature:refs/heads/main"

# add a note to a commit (without changing it)
git notes add -m "Reviewed by Alice" abc1234
git notes show abc1234
git log --show-notes

# configure where notes are stored
git config --global notes.displayRef "refs/notes/*"

# push notes to a remote
git push origin refs/notes/commits
10

ベストプラクティスとヒント

コミットの衛生

良いコミットは小さく、原子的で、自己完結しています:1コミットにつき1つの論理的変更。これによりコードレビューが容易になり、bisect が高速になり、revert が外科的になります。git add -p を使用して単一の懸念に関連するハンクのみをステージします。命令法のメッセージ('added' ではなく 'add')はコードベースへの指示として読めます。マージ前に機能ブランチを最新の main にリベースすると、履歴が線形で理解しやすくなります。

git
# commit small, focused, logical units
git add -p               # stage only relevant hunks
git commit -m "fix: handle null user in login"

# write clear, imperative messages
# GOOD: "feat: add password reset endpoint"
# BAD:  "stuff", "fix", "WIP", "asdf"

# one concern per commit
git add login.ts && git commit -m "feat: add login"
git add styles.css && git commit -m "style: format login"

# rebase before merging to keep history clean
git fetch && git rebase origin/main

ブランチ保護とコードレビュー

ブランチ保護ルールは force-push を防ぎ、PR レビューを要求し、CI 通過でマージをゲートします — チームの安全性に不可欠です。線形履歴の要求は rebase または squash マージを強制し、履歴を読みやすくします。署名付きコミット(GPG または SSH)は作成者を証明し、なりすましを防ぎます。これらの設定は Git ではなくホスティングプラットフォーム(GitHub/GitLab)で構成されますが、組織全体の良い Git 衛生を強制します。

git
# on GitHub/GitLab: protect the main branch
# - require pull request reviews
# - require status checks (CI) to pass
# - require linear history (no merge commits)
# - dismiss stale reviews on push
# - require signed commits

# enforce via config (GitHub CLI)
gh api repos/:owner/:repo/branches/main/protection \
  -X PUT -f required_status_checks[strict]=true

# sign commits and verify on receive
git config --global commit.gpgsign true
git config --global gpg.format ssh

無視とシークレット管理

コミットされたシークレットは最も一般的な Git セキュリティインシデントです。一度プッシュされたら、シークレットは侵害されたと想定してください — 履歴から削除した後でも、クローンやフォークに保持されるため即座にローテートします。予防が最善です:.gitignore でシークレットを無視し、環境変数やシークレットマネージャー(Vault、AWS Secrets Manager)を使用し、各コミット前に API キーやパスワードをスキャンする git-secrets や pre-commit フックをインストールします。

git
# never commit secrets — use .gitignore
echo ".env" >> .gitignore
echo "*.pem" >> .gitignore
echo "secrets/" >> .gitignore

# if you accidentally committed a secret:
# 1. rotate/revoke the secret immediately
# 2. remove from history
git filter-repo --path .env --invert-paths
git push --force-with-lease

# use environment files or secret managers
echo "API_KEY=$API_KEY" > .env.local   # gitignored
# load via dotenv in your app

# use git-secrets to scan pre-commit
git secrets --install
git secrets --register-aws

パフォーマンスのヒント

大きなリポジトリは遅くなる可能性があります。fsmonitor と untrackedcache はファイルシステム状態をキャッシュして git status をはるかに高速化します。シャロークローンと部分クローンは初期ダウンロードを削減します。定期的に git gc を実行してオブジェクトをコンパクト化します。--no-verify は pre-commit と commit-msg フックをスキップします — 緊急時に便利ですが、チームの品質チェックをバイパスするため習慣にしないでください。

git
# speed up status on large repos
git config --global core.fsmonitor true
git config --global core.untrackedcache true

# shallow clone for CI
git clone --depth 1 https://github.com/user/repo.git

# partial clone for huge monorepos
git clone --filter=blob:none https://github.com/user/monorepo.git

# periodic garbage collection
git gc --prune=now

# disable slow hooks temporarily
git commit --no-verify

よくある落とし穴

これらの古典的な間違いを避けてください:共有ブランチには決して force-push しない(--force-with-lease が安全なオプション);他の人が作業の基にした可能性のあるコミットは決してリベースしない;デタッチド HEAD で最初にブランチを作成せずにコミットしない。大きなバイナリには Git LFS を使用してください — そうしないと履歴が永久に膨張します。クロスプラットフォームチームで空白のみの diff ノイズを避けるため、OS ごとに改行設定(autocrlf)をしてください。

git
# PITFALL: force-pushing to shared branches
git push --force origin main   # DON'T — use --force-with-lease

# PITFALL: rebasing pushed commits
# rebase only your local, unpushed branches

# PITFALL: committing on detached HEAD
git checkout v1.0.0
# changes here are not on a branch — create one:
git checkout -b fix/v1.0.1

# PITFALL: large binary files bloating history
# use Git LFS for binaries
git lfs install
git lfs track "*.psd"
git add .gitattributes

# PITFALL: CRLF/LF line endings across OS
git config --global core.autocrlf input   # on Linux/Mac
git config --global core.autocrlf true    # on Windows
11

Git Flow ワークフロー

Git Flow ブランチモデル

Git Flow はリリースベースのプロジェクトのための厳格なブランチモデルです。main は常に本番コードを保持し、develop は統合作業を保持します。機能は develop から分岐し、develop にマージし戻します。リリースは develop から分岐し、安定化した後、main(タグ付き)と develop の両方にマージします。ホットフィックスは main から分岐し、main と develop の両方にマージします。このモデルは予定されたリリース(デスクトップアプリ、オンプレミスソフトウェア)のプロジェクトに適しています。継続的デプロイには、GitHub Flow(main + 機能ブランチ)がシンプルです。git-flow CLI ツールがブランチのダンスを自動化します。

git
# Git Flow uses long-lived branches:
# main      → production-ready code
# develop   → latest delivered development changes
# feature/* → new features (branched from develop)
# release/* → release preparation (branched from develop)
# hotfix/*  → urgent production fixes (branched from main)

# Initialize git-flow (interactive setup)
git flow init

# Start a new feature
git flow feature start my-feature
# Creates feature/my-feature from develop

# Finish a feature (merges to develop, deletes branch)
git flow feature finish my-feature

# Publish a feature to remote
git flow feature publish my-feature

# Start a release
git flow release start 1.2.0
# Creates release/1.2.0 from develop

# Finish a release (merges to main AND develop, tags)
git flow release finish 1.2.0

GitHub Flow(よりシンプル)

GitHub Flow は最もシンプルなワークフローです:main は常にデプロイ可能で、機能ブランチは短命で、すべてプルリクエスト経由でマージされます。develop ブランチやリリースブランチはありません — main は継続的にデプロイされます。これは継続的デプロイのある Web アプリに適しています。重要なルール:main に直接コミットしないでください。常にレビュー用の PR を使用します。機能ブランチを小さく短命に(週ではなく日で)保ちます。リポジトリをクリーンに保つため、マージ後にブランチを削除します。このモデルは Git Flow の構造化されたリリース管理よりも速度とシンプルさを優先します。

git
# GitHub Flow: only main + feature branches
# 1. Create branch from main
git checkout main
git pull origin main
git checkout -b feature/add-login

# 2. Commit changes
git add .
git commit -m "feat: add login page"

# 3. Push to remote
git push -u origin feature/add-login

# 4. Open Pull Request on GitHub
# 5. Review, discuss, get approval
# 6. Merge to main (via GitHub UI or CLI)
git checkout main
git pull origin main
git branch -d feature/add-login  # delete local branch

# 7. Deploy from main (continuous deployment)

Trunk-Based Development

Trunk-Based Development は最も極端です:開発者は main に直接コミットします(または24時間以内にマージされる非常に短命なブランチ)。これにより真の継続的統合が可能になります — 全員が常に統合します。未完了の機能は長命なブランチではなく機能フラグ(デプロイされるが非表示)を使用します。これには強力な CI/CD、包括的なテスト、機能フラグインフラが必要です。Google、Facebook、Netflix が使用しています。利点:マージ地獄なし、高速なフィードバック、小さな変更。課題:規律、テストカバレッジ、機能フラグ管理が必要。堅牢な CI/CD を持つ経験豊富なチームに最適です。

git
# Trunk-Based: everyone commits to main (trunk)
# Short-lived feature branches optional

# Direct commit to main (small teams)
git checkout main
git pull
# make changes
git add . && git commit -m "fix: typo in header"
git push

# With short-lived branches (larger teams)
git checkout -b quick-fix
git commit -m "fix: validation bug"
git push
# PR merged within 24 hours

# Feature flags enable incomplete code on main
# Code is deployed but hidden behind a flag
if (featureFlag.isEnabled("new-checkout")) {
  showNewCheckout();
} else {
  showOldCheckout();
}

Fork & Pull ワークフロー

Fork & Pull ワークフローはオープンソースの標準です。貢献者はリポジトリをフォーク(自分のコピーを作成)し、フォークにブランチをプッシュし、元の(upstream)リポジトリに PR を開きます。upstream リモートでフォークを元のリポジトリと同期できます。常に更新された main から機能ブランチを作成してください。このワークフローは書き込みアクセスなしで誰もが貢献できるようにします。メンテナーが PR をレビューしてマージします。フォークを同期するには、upstream を fetch して定期的に merge/rebase します。一部のプロジェクトは、直接プッシュアクセスを持つ内部貢献者のために「クローン、ブランチ、PR」モデルを使用します。

git
# For open-source projects (contributors don't have push access)

# 1. Fork the repo on GitHub (UI button)
# 2. Clone YOUR fork
git clone https://github.com/YOUR-USERNAME/project.git
cd project

# 3. Add upstream (original repo)
git remote add upstream https://github.com/ORIGINAL/project.git

# 4. Keep your fork updated
git fetch upstream
git checkout main
git merge upstream/main  # or: git rebase upstream/main
git push origin main

# 5. Create feature branch
git checkout -b feature/my-contribution

# 6. Push to YOUR fork
git push origin feature/my-contribution

# 7. Open Pull Request from your fork to upstream

ブランチ命名規約

一貫したブランチ命名は明確さを向上し、自動化を可能にします。一般的なプレフィックス:feature、bugfix、hotfix、release、chore、docs、refactor、experiment。チケット番号(PROJ-123)を含めるとブランチが issue にリンクされ、自動リンクが有効になります。スラッシュは Git GUI で視覚的階層を作成します。一部のチームは Git フックや CI チェックで命名を強制します。規約は CONTRIBUTING.md に文書化すべきです。名前は説明的だが簡潔に保ちます。個人の名前(johns-branch)は避けてください — 作業を説明し、作成者ではありません。一貫した命名によりブランチのクリーンアップと履歴ナビゲーションがはるかに容易になります。

git
# Common naming patterns:
feature/add-user-authentication
feature/PROJ-123-user-profile
bugfix/fix-login-redirect
bugfix/PROJ-456-crash-on-startup
hotfix/security-patch-xss
release/v2.0.0
chore/update-dependencies
docs/api-documentation
refactor/extract-auth-module
experiment/new-algorithm

# Using ticket numbers (Jira, Linear, etc.)
git checkout -b feature/PROJ-123-oauth-login

# Auto-linking in commit messages
git commit -m "PROJ-123: implement OAuth login"
# GitHub auto-links PROJ-123 to the Jira ticket

# Branch naming with slashes creates hierarchy
# in Git GUI tools (GitHub, GitKraken, SourceTree)
12

リベースの深掘り

インタラクティブリベース

インタラクティブリベース(-i)は最も強力な履歴編集ツールです。プッシュ前にコミットの書き換え、並べ替え、結合、分割、削除ができます。squash はコミットを親に結合し(メッセージをマージ)、fixup は同じですがコミットメッセージを破棄します('WIP' コミットのクリーンアップ)。edit はコミットを修正(ファイル追加、内容変更)するためリベースを一時停止します。reword はメッセージのみ変更できます。drop はコミットを削除します。履歴をクリーンに保つため、常にプッシュ前にリベースしてください。他の人が既にプルしたコミットは決してリベースしないでください — 共有履歴を書き換えます。

git
# Rebase last 5 commits interactively
git rebase -i HEAD~5

# Opens editor with:
# pick a1b2c3d First commit
# pick e4f5g6h Second commit
# pick i7j8k9l Third commit
# pick m0n1o2p Fourth commit
# pick q3r4s5t Fifth commit

# Commands:
# pick   = use commit as-is
# reword = use commit, edit message
# edit   = pause to amend the commit
# squash = combine with previous commit
# fixup  = like squash, discard this message
# drop   = remove commit entirely
# exec   = run a shell command
# reorder = move lines to reorder commits

コミットのスカッシュ

スカッシュは複数のコミットを1つに結合し、クリーンな履歴を作成します。これは機能ブランチのマージに理想的です:20の 'WIP' コミットを1つの意味のある 'feat: add login' コミットにスカッシュします。--fixup フラグは --autosquash が自動的に配置して対象にスカッシュする特別なコミットを作成します — 履歴を散らかさずにレビューフィードバックを修正するのに最適です。git reset --soft main の後に単一コミットですべてを一度にスカッシュします(完全スカッシュにはインタラクティブリベースよりシンプル)。多くのチームが PR マージを自動スカッシュに設定しています(GitHub の 'Squash and merge' オプション)。

git
# Squash the last 3 commits into one
git rebase -i HEAD~3

# In editor, change:
# pick a1b2c3d First
# squash e4f5g6h Second  (or 'fixup' to discard message)
# squash i7j8k9l Third

# Git prompts for combined commit message

# Squash everything since branching from main
git rebase -i main

# Auto-squash fixup commits
git commit --fixup a1b2c3d  # creates fixup! commit
git rebase -i --autosquash main
# Git automatically reorders and squashes fixup commits

# Squash all commits into one on a branch
git reset --soft main
git commit -m "feat: complete feature X"

リベース vs マージ

マージは完全なブランチ履歴を保存します(機能が分岐・マージされた場所を示すマージコミット付き)。リベースはコミットをターゲットの上にリプレイし、マージコミットのない線形な履歴を作成します。マージはより安全(履歴の書き換えなし)で機能のコンテキストを示します。リベースはクリーンですがコミット履歴を書き換えます。一般的な戦略:マージ前に機能ブランチを最新の main にリベースし、その後マージ(ファストフォワードまたは --no-ff でマージコミット)。これによりクリーンなコミットと機能を示すマージコミットの両方が得られます。公開/共有ブランチでは履歴コンフリクトを避けるためマージを優先してください。

git
# MERGE: preserves complete history with merge commits
git checkout main
git merge feature
# Creates a merge commit, history looks like a graph:
# *   merge commit
# |\
# | * feature commit 2
# | * feature commit 1
# * main commit

# REBASE: linear history, no merge commits
git checkout feature
git rebase main
git checkout main
git merge feature  # fast-forward, no merge commit
# History is linear:
# * feature commit 2
# * feature commit 1
# * main commit

# When to use each:
# Merge: preserve context of feature branch, public repos
# Rebase: clean linear history, before pushing feature branch

リベースコンフリクトの解決

リベースコンフリクトはコミットを変更されたベースにリプレイする時に発生します。各コンフリクトを解決し、解決したファイルを git add し、git rebase --continue します。リベースは一度に1コミット処理するため、複数のコンフリクトに遭遇する可能性があります。--skip はコミットを破棄します(リベース後に空になった場合に使用)。--abort はすべてをキャンセルしリベース前の状態に戻ります — 常に安全な脱出です。複雑なコンフリクトには、git mergetool が視覚的マージツール(VS Code、Beyond Compare など)を起動します。マージコンフリクトとの主な違い:リベースは同じコンフリクトを複数回(リプレイされたコミットごとに1回)解決する必要がある場合があります。

git
# During rebase, conflicts pause the process
git rebase main
# CONFLICT in file.txt

# 1. Resolve conflicts manually in the file
#    (look for <<<<<<< ======= >>>>>>> markers)

# 2. Stage resolved files
git add file.txt

# 3. Continue the rebase
git rebase --continue

# Skip a commit (if it's empty after rebase)
git rebase --skip

# Abort the entire rebase (return to original state)
git rebase --abort

# Use a merge tool for conflicts
git mergetool

# After resolving, the rebase continues
# with the next commit automatically

リベース --onto(高度)

git rebase --onto は正確なコミット移植のための高度な形式です。構文:rebase --onto NEW-BASE OLD-BASE BRANCH — OLD-BASE と BRANCH の間のコミットを取り、NEW-BASE の上にリプレイします。これはブランチのベースポイントを変更するのに便利です(例:機能が別のマージされた機能に基づいていた場合、main にリベースしてクリーンアップ)。また履歴から特定のコミットを削除するのにも使用されます(それらの周りにリプレイ)。これはパワーユーザー機能です — まず通常のリベースを理解してください。高度な履歴書き換えの前には常にバックアップ(reflog)を用意してください。

git
# Scenario: feature branch was based on old-branch,
# but you want to rebase onto main instead

# git rebase --onto new-base old-base branch
git rebase --onto main old-branch feature

# This takes commits from old-branch..feature
# and replays them onto main

# Use case: remove commits from the middle
# Remove commit C from branch (replay A,B,D onto base)
#   base -> A -> B -> C -> D
# git rebase --onto base C D
# Result: base -> A -> B -> D'

# Use case: move a branch to a different parent
git rebase --onto main feature/sub-feature feature/main-feature
# Moves main-feature's unique commits from sub-feature to main
13

チェリーピックと bisect

git cherry-pick

cherry-pick はあるブランチから別のブランチに特定のコミットを適用します。ユースケース:リリースブランチにバグ修正を適用、マージし忘れたコミットをコピー、選択的に機能を移植。コミットは新しいハッシュを取得します(親が異なるため)。ターゲットブランチが分岐している場合、cherry-pick はコンフリクトを起こす可能性があります。--no-commit はコミットせずに変更をステージします(複数の cherry-pick を結合するのに便利)。過度の cherry-pick は避けてください — ブランチが最終的にマージされる時に重複コミットを作成する可能性があります。体系的なバックポートには、マージ付きのリリースブランチを使用してください。

git
# Apply a specific commit to current branch
git cherry-pick a1b2c3d

# Cherry-pick multiple commits
git cherry-pick a1b2c3d e4f5g6h i7j8k9l

# Cherry-pick a range (exclusive start, inclusive end)
git cherry-pick A..E  # commits B, C, D, E

# Cherry-pick without committing (stage only)
git cherry-pick --no-commit a1b2c3d
# or: -n

# Cherry-pick and edit commit message
git cherry-pick --edit a1b2c3d

# Cherry-pick from another branch
git cherry-pick feature-branch~2

# If conflicts occur:
git add . && git cherry-pick --continue
git cherry-pick --abort  # cancel

git bisect(二分探索)

git bisect はコミット履歴を二分探索してバグを導入した正確なコミットを見つけます。現在の状態を 'bad'、既知の動作するコミットを 'good' としてマークします。Git が中間点をチェックアウトし、テストして good/bad をマークします。各ステップで検索空間を半分にします — 1000コミット中のバグを約10ステップで見つけられます。bisect reset で元のブランチに戻ります。これは回帰の追跡に不可欠です。git bisect log で bisect セッションを保存/復元できます。原因コミットは多くの場合、根本原因を即座に明らかにします。

git
# Find which commit introduced a bug
git bisect start

# Mark current (bad) commit
git bisect bad

# Mark a known-good commit (last working version)
git bisect good v1.0.0
# or: git bisect good a1b2c3d

# Git checks out a middle commit
# Test it, then mark:
git bisect good  # if this commit works
git bisect bad   # if this commit is broken

# Repeat until Git identifies the culprit:
# "a1b2c3d is the first bad commit"

# When done:
git bisect reset  # return to original branch

# Skip a commit (can't test, e.g., doesn't build)
git bisect skip

自動 bisect

自動 bisect は各コミットのテストスクリプトを実行し、手動テストを排除します。スクリプトは0(good)、非ゼロ(bad)、または125(スキップ — 例:ビルド失敗)で終了します。Git が各コミットを自動的にマークし原因を見つけます。これはテストスイートで非常に強力です:git bisect run npm test で破壊的コミットを数分で見つけられます。検索を特定のファイルに制限(git bisect start -- path/to/file)して高速化もできます。スクリプトは何でも構いません:テスト、ビルドチェック、API をチェックする curl コマンド。後で再現・再開するため bisect ログを保存してください。

git
# Auto-bisect with a test script
git bisect start
git bisect bad HEAD
git bisect good v1.0.0

# Git runs this script for each commit
# Exit 0 = good, exit 1 = bad, 125 = skip
git bisect run npm test

# Or a custom script
git bisect run ./scripts/check-bug.sh

# Example check script:
#!/bin/bash
npm run build || exit 125  # skip if build fails
npm test -- --grep "login bug"
# exit 0 if test passes (good), 1 if fails (bad)

# Git automatically finds the bad commit
# without manual testing

# Bisect with a file range (faster)
git bisect start -- src/auth/login.js

git blame と annotate

git blame はファイルの各行の作成者とコミットを表示します — コードがなぜ存在するかを理解するために不可欠です。-L は行範囲に制限し(より高速で焦点を絞る)。-w は空白のみの変更を無視(真の内容の作成者を表示)。-M は同じファイル内で移動されたコードを検出し、-C は他のファイルからコピーされたコードを検出(コピーアーではなく元の作成者を表示)。blame は非難ではなく理解のため — コードのコンテキストを見つけて git show で完全なコミットを読むために使用します。GitHub の 'Blame' ボタンが視覚的インターフェースを提供します。git log -S と組み合わせて特定のテキストがいつ追加されたかを見つけます。

git
# Show who last modified each line
git blame file.txt

# Blame specific line range
git blame -L 10,20 file.txt

# Show full commit hash (not abbreviated)
git blame -l file.txt

# Show email instead of name
git blame -e file.txt

# Ignore whitespace changes
git blame -w file.txt

# Detect moved lines within file
git blame -M file.txt

# Detect moved lines from other files
git blame -C file.txt

# Blame with commit message
git blame --show-name --show-email file.txt | head

git revert(安全な取り消し)

git revert は以前のコミットを取り消す新しいコミットを作成します — 履歴を書き換える reset とは異なり、共有ブランチで変更を取り消す安全な方法です。revert は履歴を書き換えられない本番ブランチに理想的です。マージコミットの revert には -m 1(メインライン親)が必要 — これはブランチ履歴を保持しながらマージを取り消します。revert の revert は元の変更を再適用します(revert が間違いだった場合によく使用)。複数コミットの場合、コンフリクトを最小限にするため新しい順(最新から)で revert してください。共有/公開ブランチでは常に revert を使用し、reset はローカルブランチのみに使用してください。

git
# Revert a commit (creates a NEW commit that undoes it)
git revert a1b2c3d

# Revert multiple commits
git revert a1b2c3d e4f5g6h

# Revert a range
git revert A..E

# Revert without committing (stage the reversal)
git revert --no-commit a1b2c3d

# Revert a merge commit
git revert -m 1 a1b2c3d
# -m 1 specifies the mainline parent (parent 1 = the branch
# you merged INTO, parent 2 = the branch you merged FROM)

# If revert conflicts:
git add . && git revert --continue
git revert --abort
14

reflog と復元

git reflog の基礎

reflog は HEAD とブランチポインタのすべての変更を記録します — コミットを「破壊」する操作(reset --hard、rebase、ブランチ削除)も含みます。これはセーフティネットです:「失われた」コミットは約90日間(デフォルト)reflog 経由で復元可能です。reflog はローカル(プッシュされない)で、ポインタ移動の時系列履歴を表示します。復元するには、reflog でコミットハッシュを見つけて checkout/reset します。@{N} 構文でエントリを参照します:HEAD@{0} が現在、HEAD@{1} が前。作業を「失った」と思ったら、まず reflog を確認してください — ほぼ確実にまだそこにあります。

git
# View the reflog (reference log)
git reflog
# Shows ALL reference changes, including:
# - commits, checkouts, resets, rebases, merges
# Example output:
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: add feature
# i7j8k9l HEAD@{2}: checkout: moving from main to feature

# Reflog for a specific branch
git reflog show feature-branch

# Reflog with dates
git reflog --date=iso

# Recover a "lost" commit
git reflog
# Find the commit hash, then:
git checkout a1b2c3d  # or: git reset --hard a1b2c3d

削除されたブランチの復元

削除されたブランチと reset されたコミットは reflog 経由で復元できます。コミットオブジェクトはガベージコレクション(デフォルト:到達不能オブジェクトは90日)まで Git のオブジェクトストアに存在し続けます。削除されたブランチを復元するには、reflog で先端コミットを見つけてそれを指す新しいブランチを作成します。reset --hard の失敗には、reflog が以前の HEAD 位置を表示します — そこに reset し戻します。悪い rebase には、rebase 開始前の reflog エントリを見つけてそこに reset します。重要な教訓:Git では、ほとんど何も即座に完全に失われることはありません。パニックする前に必ず reflog を確認してください。

git
# Accidentally deleted a branch?
git branch -D feature  # force deleted

# Find it in reflog
git reflog
# e4f5g6h HEAD@{2}: commit: work on feature

# Recreate the branch at that commit
git branch feature e4f5g6h

# Or checkout and create
git checkout -b feature e4f5g6h

# Recover after reset --hard
git reset --hard HEAD~3  # oops, went too far
git reflog
# Find the commit before the reset
git reset --hard HEAD@{1}  # undo the reset

# Recover after a bad rebase
git reflog
git reset --hard HEAD@{5}  # before the rebase started

git fsck(ダングリングオブジェクト)

git fsck はリポジトリの整合性をチェックし、ダングリングオブジェクト — 任意のブランチやタグから参照されていないコミット、blob、ツリーを見つけます。--lost-found はこれらを .git/lost-found/ に書き込みます。これは reflog に必要なものがない場合(reflog エントリの期限切れ、または git gc の実行)の最後の手段です。ダングリングコミットは中断された操作や期限切れの reflog エントリの結果であることがよくあります。git show で検査し、ブランチを作成して復元します。fsck --full はすべてのオブジェクトの整合性を検証します(破損の検出に便利)。重要なリポジトリで定期的に fsck を実行して早期に問題をキャッチしてください。

git
# Find dangling (unreachable) commits
git fsck --lost-found

# Output:
# dangling commit a1b2c3d...
# dangling blob e4f5g6h...

# Inspect a dangling commit
git show a1b2c3d

# Recover it
git branch recovered a1b2c3d

# Full fsck (check repository integrity)
git fsck --full

# Check for dangling objects only
git fsck --no-reflogs --dangling

# When reflog doesn't have what you need
# (e.g., expired, or gc ran), fsck finds
# ALL dangling objects in the object store

git stash の深掘り

git stash は未コミットの変更を一時的に退避します。push -m で説明的なメッセージを追加(複数のスタッシュの管理に不可欠)。-u は未追跡ファイルを含め、-a は無視されたファイルも含めます。apply は削除せずに再適用、pop は適用して削除。stash branch はスタッシュから新しいブランチを作成(スタッシュが現在のブランチとコンフリクトする場合に便利)。スタッシュはスタック(LIFO)に保存 — stash@{N} で参照。show -p で diff を表示。スタッシュは再起動後も保持されますがローカル(プッシュされません)。古いスタッシュは定期的にクリーンアップしてください。蓄積します。長期の作業には、スタッシュではなくブランチを作成してください。

git
# Stash with message
git stash push -m "work in progress on login"

# Stash specific files
git stash push -m "wip" file1.txt file2.txt

# Stash including untracked files
git stash push -u  # or --include-untracked

# Stash including ignored files
git stash push -a  # or --all

# List stashes
git stash list
# stash@{0}: On feature: wip on login
# stash@{1}: On main: quick fix

# Apply a specific stash
git stash apply stash@{1}

# Apply and drop (pop)
git stash pop  # applies stash@{0} and removes it

# Show stash contents
git stash show -p stash@{0}

# Create branch from stash
git stash branch new-branch stash@{0}

# Drop a stash
git stash drop stash@{1}
git stash clear  # drop ALL stashes

git tag の管理

タグは特定のコミットを重要(リリース、マイルストーン)としてマークします。注釈付きタグ(-a)はメタデータ(タガー、日付、メッセージ)を保存し、リリースに推奨されます。軽量タグは単なる名前付きポインタ(メタデータなし)です。署名付きタグ(-s)は検証に GPG を使用(セキュリティリリースに重要)。タグはデフォルトではプッシュされません — --tags でプッシュします。セマンティックバージョニング(v1.2.3)が標準の命名規約です。タグをチェックアウトするとデタッチド HEAD 状態になります(検査やリリースのビルド用)。GitHub リリースはタグに基づいて構築 — タグを作成し、ノート付きでリリースを公開します。

git
# Create annotated tag (recommended)
git tag -a v1.0.0 -m "Release 1.0.0"

# Create lightweight tag
git tag v1.0.0

# Tag a specific commit
git tag -a v0.9.0 -m "beta" a1b2c3d

# List all tags
git tag
git tag -l "v1.*"  # filter by pattern

# Push tags to remote
git push origin v1.0.0      # single tag
git push origin --tags       # all tags

# Delete a tag
git tag -d v1.0.0            # local
git push origin --delete v1.0.0  # remote

# Show tag details
git show v1.0.0

# Checkout a tag (detached HEAD)
git checkout v1.0.0

# Signed tags (GPG)
git tag -s v1.0.0 -m "signed release"
15

ワークツリーとサブモジュール

git worktree

git worktree は同じリポジトリから追加の作業ディレクトリを作成します — クローン不要。各ワークツリーが異なるブランチを同時にチェックアウトします。これは以下に最適です:機能ブランチを開いたままホットフィックスに取り組む、別のブランチでテストを実行しながらコーディング、1つのワークツリーで長時間実行されるビルドを持つ。すべてのワークツリーは同じ .git ディレクトリ(オブジェクト、ref)を共有するため、同期しディスク容量を節約します。同じブランチを2つのワークツリーでチェックアウトできません(コンフリクトを避けるため Git が防止)。マルチブランチワークフローにはクローンよりワークツリーが高速です。

git
# Create a new working directory linked to the repo
git worktree add ../project-hotfix hotfix-branch

# Work in the new directory
cd ../project-hotfix
# This is a full working tree on hotfix-branch
# Shares the same .git, so no cloning needed

# List worktrees
git worktree list
# /path/to/project          main
# /path/to/project-hotfix   hotfix-branch

# Remove a worktree
git worktree remove ../project-hotfix

# Prune stale worktree entries
git worktree prune

# Create worktree at new branch
git worktree add -b feature-x ../project-feature main

git submodule の基礎

サブモジュールは1つの Git リポジトリを別のリポジトリに埋め込みます — 共有ライブラリや依存関係を含めるのに便利です。親リポジトリはサブモジュールの内容ではなくポインタ(コミットハッシュ)を保存します。クローン時に --recurse-submodules が不可欠(そうでなければサブモジュールは空)。サブモジュールの更新(--remote)は最新のコミットをフェッチし、その後親リポジトリで新しいハッシュをコミットする必要があります。サブモジュールは複雑です:ブランチ、コンフリクト、更新には慎重な扱いが必要です。よりシンプルな依存関係管理には、Git subtrees、パッケージマネージャー(npm、pip)、またはモノレポ戦略を検討してください。特定の外部コミットを追跡する必要がある場合にサブモジュールを使用してください。

git
# Add a submodule to your repo
git submodule add https://github.com/user/lib.git libs/lib

# Clone a repo with submodules
git clone --recurse-submodules https://github.com/user/project.git

# If you forgot --recurse-submodules:
git submodule update --init --recursive

# Pull latest changes in all submodules
git submodule update --remote

# Pull specific submodule
git submodule update --remote libs/lib

# After updating submodules, commit the new hash
git add libs/lib
git commit -m "update lib submodule"

# Execute command in all submodules
git submodule foreach 'git status'

サブモジュールのワークフロー

サブモジュール内での作業は通常のリポジトリでの作業と同様 — サブモジュールディレクトリ内からコミットしてプッシュします。親リポジトリはコミットハッシュを追跡するため、サブモジュールを変更した後は親でもコミットする必要があります。ブランチを切り替えると、サブモジュールの内容が一致しない場合があります — git submodule update --init --recursive を実行して同期してください。サブモジュールの削除には3つのステップが必要です:deinit(登録解除)、git rm(追跡から削除)、.git/modules の手動削除。サブモジュールのワークフローはエラーを起こしやすいです。ハッシュの不一致を避けるため、サブモジュールを更新する際は常にチームとコミュニケーションを取ってください。

git
# Change code inside a submodule
cd libs/lib
# Make changes, commit, and push
git add .
git commit -m "fix: bug in lib"
git push origin HEAD:main

# Back in parent repo, update the pointer
cd ../..
git add libs/lib
git commit -m "chore: update lib submodule"

# Switch branches with submodules
git checkout main
git submodule update --init --recursive

# Delete a submodule
git submodule deinit -f libs/lib
git rm libs/lib
rm -rf .git/modules/libs/lib
git commit -m "remove lib submodule"

# Move a submodule
git mv libs/lib libs/new-lib

Git フック

Git フックは Git ライフサイクルの特定の時点でスクリプトを実行します。クライアント側フック(pre-commit、pre-push、commit-msg)はローカル標準を強制します。pre-commit はリンティング/フォーマットに理想的、pre-push はテスト実行、commit-msg は Conventional Commits の強制に使用します。フックは Git で追跡されません(.git/hooks/ に存在)ため、クローン間で同期されません。チーム全体でフックを共有するには、Husky(npm)、pre-commit(Python)のようなツールを使用するか、フックをチェックインされたディレクトリにコミットしてシンボリックリンクを張ります。サーバー側フック(pre-receive、post-receive)はリモートで実行され、すべての貢献者のポリシーを強制できます。

git
# Hooks live in .git/hooks/ (not tracked by Git)
# Sample hooks are provided with .sample extension

# pre-commit: runs before commit is created
# .git/hooks/pre-commit
#!/bin/bash
npm run lint || exit 1  # block commit if lint fails

# pre-push: runs before pushing
#!/bin/bash
npm test || exit 1  # block push if tests fail

# commit-msg: validate commit message format
#!/bin/bash
# $1 is the path to the commit message file
if ! grep -qE "^(feat|fix|docs|chore):" "$1"; then
  echo "Use conventional commit format: type: message"
  exit 1
fi

# prepare-commit-msg: auto-populate message
#!/bin/bash
echo "# Branch: $(git branch --show-current)" >> "$1"

# Make hooks executable
chmod +x .git/hooks/pre-commit

Git LFS(Large File Storage)

Git LFS は大きなファイル(バイナリ、動画、データセット)を Git 内のテキストポインタで置き換え、実際の内容を別の LFS サーバーに保存します。これによりリポジトリが軽量に保たれます — LFS なしでは、バイナリファイルがリポジトリを永久に膨張させます(すべてのバージョンが保存されるため)。git lfs track でファイルパターンを追跡し、.gitattributes をコミットします。その後、大きなファイルは透過的に動作します。git lfs migrate import は既存のファイルを遅延的に LFS に変換します(履歴を書き換え — まずチームと調整)。LFS にはサーバーサポートが必要です(GitHub、GitLab、Bitbucket すべてがサポート)。注意:LFS にはホスティングプラットフォームで帯域幅/ストレージのクォータがあります。本当に巨大なファイルには、URL 付きの外部ストレージを検討してください。

git
# Initialize Git LFS
git lfs install

# Track large file types
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "assets/**"

# This creates/updates .gitattributes
# Commit the .gitattributes file
git add .gitattributes
git commit -m "chore: configure LFS tracking"

# Add large files normally
git add design.psd
git commit -m "add design file"
git push

# View LFS tracked files
git lfs ls-files

# Pull LFS content (if not auto-downloaded)
git lfs pull

# Migrate existing files to LFS (rewrites history)
git lfs migrate import --include="*.psd" --everything

# Check LFS status
git lfs status
16

スタッシュ

保存と取り出し

git stash は未コミットの変更を退避し、クリーンな作業ツリーでブランチを切り替えたり更新をプルできるようにします。pop は最上位のスタッシュを適用して削除し、apply は保持します。スタッシュは LIFO スタックです。

git
# Save uncommitted changes (tracked files only)
git stash

# Save including untracked files
git stash -u

# Pop the most recent stash (removes it)
git stash pop

# Apply without removing (keeps stash in list)
git stash apply

名前付きスタッシュ

常に -m を渡してスタッシュにラベルを付けてください — デフォルトメッセージはブランチとコミットで、説明的であることは稀です。stash@{N} でインデックスで特定のスタッシュを参照します。

git
# Save with a descriptive message
git stash push -m "WIP: refactor auth flow"

# List all stashes with messages
git stash list

# Apply a specific stash by index
git stash apply stash@{1}

スタッシュブランチ

git stash branch はスタッシュが元々作成されたコミットから新しいブランチを作成し、そこにスタッシュを適用します。これはスタッシュがクリーンに適用できなくなった時の最もクリーンな復元方法です。

git
# Create a new branch from a stash
git stash branch feature-branch stash@{0}

# Useful when stash conflicts with current branch
# - Creates branch from the commit where stash was made
# - Applies stash on top
# - Drops stash if apply succeeds

部分スタッシュ

-p(インタラクティブハンク選択)または特定のファイルをリストすることで必要なもののみをスタッシュします。--keep-index は未ステージの変更をスタッシュし、ステージされた変更をそのまま残します。

git
# Interactively choose hunks to stash
git stash push -p

# Stash specific files only
git stash push -m "config tweaks" config.yml .env.local

# Stash with keep-index (staged changes stay)
git stash --keep-index

スタッシュの管理

git stash show -p はスタッシュの完全な diff を表示します。drop は単一のスタッシュを削除し、clear はすべてを消去します(元に戻せません)。スタッシュはローカルのみで、リモートにプッシュされることはありません。

git
# Show what's in a stash
git stash show -p stash@{0}

# Drop a specific stash
git stash drop stash@{0}

# Clear all stashes (irreversible)
git stash clear

# Show stash list with dates
git stash list --date=relative
17

リベース

基本的なリベース

リベースはブランチのコミットを別のブランチの上に移動し、線形な履歴を生成します。マージとは異なり、コミットハッシュを書き換えます。プッシュして共有したコミットは決してリベースしないでください。

git
# Rebase current branch onto main
git checkout feature
git rebase main

# Abort if conflicts are too messy
git rebase --abort

# Continue after resolving conflicts
git rebase --continue

インタラクティブリベース

インタラクティブリベース(-i)は共有前に履歴を書き換えることができます:コミットの並べ替え、関連するものを1つのクリーンなコミットにスカッシュ、メッセージの変更、間違いの削除。常に未プッシュのコミットで行ってください。

git
# Rebase last 5 commits interactively
git rebase -i HEAD~5

# Commands: pick, reword, edit, squash, fixup, drop
# squash  = combine with previous, keep message
# fixup   = combine with previous, discard message
# reword  = change commit message only

スカッシュと fixup

--fixup は別のコミットの修正としてマークされたコミットを作成します。リベース中の --autosquash が fixup! と squash! コミットを対象の隣に自動的に配置します。これにより「早めにコミット、後でクリーンアップ」のワークフローが合理化されます。

git
# Create a fixup commit targeting an earlier commit
git commit --fixup a1b2c3

# Autosquash during rebase (auto-reorders fixups)
git rebase -i --autosquash HEAD~5

リベース --onto

--onto は外科的なリベースです:コミットの範囲をあるベースから別のベースに移動します。ブランチの親を変更したり、ブランチの最初の数コミットを削除するのに使用します。

git
# Move commits from one base to another
# git rebase --onto <new-base> <old-base> <branch>
git rebase --onto main feature-old feature-new

# Drop the first N commits of a branch
git rebase --onto main HEAD~3

リベースのコンフリクト

リベース中、コンフリクトは各コミットで停止します。解決し、git add し、--continue で進めます。--skip はコンフリクトするコミットを完全に破棄します。--abort はリベース前の状態に戻ります。

git
# During rebase, conflicts pause the process
git rebase main
# CONFLICT (content): Merge conflict in file.js

# Resolve in editor, then:
git add file.js
git rebase --continue

# Skip a commit that conflicts (drop it)
git rebase --skip

# Give up entirely
git rebase --abort
18

チェリーピック

コミットのチェリーピック

cherry-pick は別のブランチから現在のブランチに特定のコミットを適用し、同じ変更で新しいコミットを作成します。親が異なるため、新しいコミットは異なるハッシュを持ちます。

git
# Apply a specific commit to current branch
git cherry-pick a1b2c3d

# Cherry-pick multiple commits
git cherry-pick a1b2c3d e4f5g6h

# Cherry-pick a range (exclusive of start, inclusive of end)
git cherry-pick A..E

コミットなしのチェリーピック

--no-commit(-n)はコミットを作成せずにチェリーピックした変更をステージします。これにより複数の cherry-pick を1つのコミットに結合したり、コミット前に変更を修正できます。

git
# Apply changes to working tree without committing
git cherry-pick --no-commit a1b2c3d

# Stage the changes yourself
git add -p
git commit -m "Custom message"

チェリーピックのコンフリクト

チェリーピック中のコンフリクトは操作を一時停止します。解決し、git add し、--continue します。--skip は現在のコミットを放棄します。--abort はチェリーピックをキャンセルしブランチを復元します。

git
git cherry-pick a1b2c3d
# error: could not apply a1b2c3d...

# Resolve conflicts, then:
git add resolved-file.js
git cherry-pick --continue

# Skip this commit
git cherry-pick --skip

# Abort the entire cherry-pick
git cherry-pick --abort

別のブランチからのチェリーピック

古典的なホットフィックスワークフロー:メンテナンスブランチでバグを修正し、同じコミットを main(および他のアクティブなブランチ)にチェリーピックします。これにより無関係な機能作業のマージを避けます。

git
# Find the commit hash on another branch
git log --oneline feature-branch

# Switch to target branch
git checkout main

# Cherry-pick the commit
git cherry-pick <hash>

# Useful for hotfixes: fix on a feature branch,
# then cherry-pick the fix to main

チェリーピックの戦略

-X theirs/ours はコンフリクト解決を偏らせます。-x は元のコミットハッシュを記録する行を追加 — ブランチ間でホットフィックスをチェリーピックする際の監査証跡に不可欠です。

git
# Use a different merge strategy
git cherry-pick -X theirs a1b2c3d   # prefer their changes on conflict
git cherry-pick -X ours a1b2c3d     # prefer our changes on conflict

# Preserve original commit author
git cherry-pick -x a1b2c3d          # adds "(cherry picked from ...)" to message

# Edit commit message before committing
git cherry-pick -e a1b2c3d
19

bisect

基本的な bisect

git bisect はコミット履歴を二分探索してどのコミットがバグを導入したかを見つけます。現在のコミットを bad、既知の good コミットを good としてマークします。約 log2(N) ステップ後、Git が原因コミットを特定します。

git
# Start bisecting
git bisect start

# Mark current commit as bad (has the bug)
git bisect bad

# Mark a known-good commit (older)
git bisect good v1.0.0

# Git checks out the midpoint. Test, then mark:
git bisect good   # or
git bisect bad

# Exit bisect mode
git bisect reset

bisect ログとリプレイ

git bisect log はすべての good/bad の決定を記録します。コミットを誤ってマークした場合(よくある間違い)、リセットしてログをリプレイし、間違ったステップを修正できます。

git
# Record what happens during bisect
git bisect log > bisect.log

# If you make a mistake, replay from the log
git bisect reset
git bisect replay bisect.log

# Visualize the bisect state
git bisect visualize

自動 bisect

git bisect run は検索を自動化します:Git が各候補をチェックアウトし、スクリプトを実行し、終了コードに基づいてコミットをマークします。これは手動テストより劇的に高速です。

git
# Auto-bisect: git runs a test script and marks good/bad itself
git bisect start HEAD v1.0.0 --     # bad=HEAD, good=v1.0.0
git bisect run npm test             # exit 0=good, 1-124=bad, 125=skip

# Or with a custom script
git bisect run ./scripts/check-bug.sh

ファイルによる bisect

git bisect start にパスを渡すと、そのファイルを変更したコミットに検索を制限します。これにより数百の無関係なコミットをスキップし、バグが存在する可能性の高いファイルに焦点を当てます。

git
# Limit bisect to changes in a specific file
git bisect start -- path/to/file.js

# Combine with bad/good markers
git bisect bad HEAD
git bisect good v1.0.0

# Git only considers commits that touched that file

bisect のリセット

完了したら必ず git bisect reset を実行してください — 元のブランチに戻り、bisect 状態をクリーンアップします。リセットしないと、作業ツリーは最後にテストしたコミットのままになります。

git
# Exit bisect mode and return to original branch
git bisect reset

# Reset to a specific branch/commit instead
git bisect reset <branch>

# View current bisect state
git bisect status
20

サブモジュール

サブモジュールの追加

サブモジュールは1つの Git リポジトリを別のリポジトリに埋め込みます — 共有ライブラリをベンダリングするのに便利です。git submodule add は .gitmodules にサブモジュールを登録します。新しいクローンには --recurse-submodules が必要です。

git
# Add a submodule at a specific path
git submodule add https://github.com/user/lib.git libs/lib

# This creates:
# - libs/lib/ (the submodule checkout)
# - .gitmodules (tracks submodule URLs and paths)

# Commit the new submodule
git commit -m "Add lib submodule"

# Clone a repo with submodules included
git clone --recurse-submodules https://github.com/user/repo.git

サブモジュールの更新

サブモジュールは特定のコミットに固定されます。git submodule update --remote は追跡ブランチの最新コミットをフェッチし、ポインタを更新します。このポインタ変更を親リポジトリでコミットする必要があります。

git
# Pull latest changes in all submodules
git submodule update --remote

# Update a specific submodule
git submodule update --remote libs/lib

# Then commit the updated pointer
git add libs/lib
git commit -m "Bump lib submodule"

# Initialize submodules after cloning
git submodule update --init --recursive

サブモジュールの foreach

foreach は各サブモジュールディレクトリでシェルコマンドを実行します — ステータス確認、更新のプル、ビルドなどの一括操作に便利です。--recursive はネストされたサブモジュールに下降します。

git
# Run a command in every submodule
git submodule foreach 'git status'

# With recursion into nested submodules
git submodule foreach --recursive 'git checkout main'

# Use --quiet to suppress the "Entering..." messages
git submodule foreach --quiet 'git pull'

登録解除と削除

サブモジュールの削除は複数ステップのプロセスです:deinit で登録解除、rm -rf .git/modules/... でサブモジュールの Git データを削除、git rm で作業ツリーを削除。.git/modules のクリーンアップを忘れると孤立データが残ります。

git
# Deinit a submodule (unregisters, keeps files)
git submodule deinit libs/lib

# Fully remove a submodule
git submodule deinit -f libs/lib
rm -rf .git/modules/libs/lib
git rm -f libs/lib
git commit -m "Remove lib submodule"

サブモジュールのブランチ

デフォルトでは、サブモジュールはデタッチド HEAD です。submodule.<name>.branch を設定すると --remote がそのブランチを追跡します。サブモジュール内で変更を加えるには、cd で入り、ブランチをチェックアウトし、コミットしてプッシュします。

git
# Configure a submodule to track a branch
git config -f .gitmodules submodule.libs/lib.branch main

# Now --remote updates from that branch
git submodule update --remote

# Work inside a submodule like a normal repo
cd libs/lib
git checkout feature-branch
git push
cd ../..
git add libs/lib
git commit -m "Update lib to feature-branch"
21

フック

一般的なフック

Git フックは .git/hooks/ のスクリプトで、特定の時点で自動的に実行されます。クライアント側フックはマシンで実行され、アクションをブロックできます。サーバー側フックはリモートで実行され、ポリシーを強制します。フックはデフォルトでバージョン管理されません — 共有には Husky を使用してください。

git
# Client-side (run on your machine):
#   pre-commit        - runs before commit is created
#   prepare-commit-msg - can edit commit message
#   commit-msg        - validates commit message
#   pre-push          - runs before pushing
#   post-merge        - runs after git merge

# Server-side (run on the remote):
#   pre-receive       - runs before refs are updated
#   update            - runs once per ref
#   post-receive      - runs after refs are updated

pre-commit フック

pre-commit はコミット作成前に実行され、非ゼロ終了でコミットを中止します。一般的な用途:ステージされたファイルのリント、フォーカスを絞ったテストの実行、コードのフォーマット。高速に保つ(5秒以内)か、開発者が --no-verify でバイパスします。

git
#!/bin/sh
# .git/hooks/pre-commit

# Run linter on staged files
npm run lint-staged
if [ $? -ne 0 ]; then
  echo "Linting failed. Fix errors and try again."
  exit 1
fi

# Run tests
npm test -- --findRelatedTests
if [ $? -ne 0 ]; then
  echo "Tests failed."
  exit 1
fi

exit 0

commit-msg フック

commit-msg は $1 として一時コミットメッセージファイルへのパスを受け取ります。メッセージを検証または書き換えできます。非ゼロ終了でコミットを拒否します。これは Conventional Commits を強制する標準的な方法です。

git
#!/bin/sh
# .git/hooks/commit-msg

# Enforce Conventional Commits format
pattern='^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\(.*\))?: .{1,72}$'

if ! grep -qE "$pattern" "$1"; then
  echo "Invalid commit message format."
  echo "Use: <type>(<scope>): <description>"
  exit 1
fi

Husky のセットアップ

Husky はバージョン管理された .husky/ ディレクトリから Git フックをインストールするため、npm install 後にすべてのチームメンバーが同じフックを得ます。lint-staged はステージされたファイルのみでコマンドを実行し、pre-commit を高速に保ちます。

git
# Install Husky
npm install --save-dev husky
npx husky init

# Add a pre-commit hook
echo 'npm run lint-staged' > .husky/pre-commit

# Add a commit-msg hook
echo 'npx --no-install commitlint --edit $1' > .husky/commit-msg

# package.json
{
  "scripts": { "prepare": "husky" },
  "lint-staged": {
    "*.{js,ts}": ["eslint --fix", "prettier --write"]
  }
}

pre-push フック

pre-push は ref がプッシュされる前に実行され、非ゼロ終了で中止します。stdin から提案されたプッシュを読み取ります。一般的な用途:保護されたブランチへのプッシュのブロック、完全なテストスイートの実行。

git
#!/bin/sh
# .husky/pre-push

# Reads stdin: <local ref> <local sha> <remote ref> <remote sha>
while read local_ref local_sha remote_ref remote_sha; do
  if [ "$remote_ref" = "refs/heads/main" ]; then
    echo "Direct push to main is not allowed."
    exit 1
  fi
done

npm test
if [ $? -ne 0 ]; then
  echo "Tests failed. Push aborted."
  exit 1
fi
22

ワークツリー

ワークツリーの追加

ワークツリーは同じリポジトリにリンクされた別の作業ディレクトリです。コンテキストを切り替えるためにスタッシュすることなく、異なるディレクトリで複数のブランチを同時にチェックアウトできます。

git
# Create a worktree at a path, on a new branch
git worktree add ../project-feature feature-branch

# Worktree on an existing branch
git worktree add ../project-hotfix hotfix-branch

# Worktree at a specific commit (detached HEAD)
git worktree add --detach ../project-inspect v1.0.0

# List all worktrees
git worktree list

ワークツリーのワークフロー

ワークツリーはコンテキスト切り替えに威力を発揮します:機能に深く没頭している時に緊急のバグが発生。スタッシュして IDE の状態を失う代わりに、main でワークツリーを作成し、そこでバグを修正して戻ります。

git
# Scenario: working on feature, urgent bug comes in
git worktree add ../project-hotfix main

cd ../project-hotfix
git checkout -b fix-urgent
# ... fix the bug, commit, push ...

cd ../project-feature
# Your feature work is untouched

# Clean up when done
git worktree remove ../project-hotfix

削除とプルーン

remove はワークツリーディレクトリとその管理メタデータを削除します。あったブランチは残ります。ワークツリーに未コミットの変更がある場合、--force を渡さないと remove は拒否します。

git
# Remove a worktree (must be clean or use --force)
git worktree remove ../project-feature

# Force remove even with uncommitted changes
git worktree remove --force ../project-feature

# Prune worktree admin files for deleted directories
git worktree prune

# Show what would be pruned
git worktree prune --dry-run -v

ワークツリーの利点

ワークツリーはいくつかのペインポイントを解決します:コンテキスト切り替えのスタッシュ不要、並列ビルド/テスト、ブランチごとの隔離された node_modules、サイドバイサイドのブランチ比較。共有オブジェクトデータベースによりディスクオーバーヘッドが最小限です。

git
# 1. No stashing needed for context switches
# 2. Run long builds/tests in one worktree while
#    continuing work in another
# 3. Each worktree has its own node_modules
# 4. Compare two branches side-by-side in two
#    editor windows
# 5. Shared object database = minimal disk overhead

# Typical layout:
# ~/projects/
#   main-repo/          (main branch)
#   main-repo-feature/  (feature worktree)
#   main-repo-hotfix/   (hotfix worktree)

ロックされたワークツリー

ワークツリーに邪魔してはいけない作業(長時間実行のビルド、アタッチされたデバッガ)が含まれる場合にロックします。ロックされたワークツリーは prune を生き残ります。move はワークツリーを再配置し、repair は管理ファイルを修正します。

git
# Lock a worktree (prevents it from being pruned)
git worktree lock ../project-feature --reason "Running long build"

# Unlock when done
git worktree unlock ../project-feature

# Move a worktree to a new path
git worktree move ../project-feature ../new-location/project-feature

# Repair after moving manually
git worktree repair ../new-location/project-feature
23

reflog

reflog の表示

reflog は HEAD とブランチ先端のすべての変更を記録します — コミット、チェックアウト、reset、rebase。これはローカルのセーフティネットです:破壊的な操作の後でも、コミットは reflog に残っています。

git
# Show reflog for HEAD
git reflog
# a1b2c3d HEAD@{0}: commit: Fix bug
# e4f5g6h HEAD@{1}: checkout: moving to feature
# 789abc0 HEAD@{2}: reset: moving to HEAD~1

# Show reflog for a specific branch
git reflog show feature

# Show reflog with dates
git reflog --date=iso

失われたコミットの復元

ハード reset や rebase の後、「失われた」コミットは reflog 経由でまだ到達可能です。git reflog でハッシュを見つけ、reset --hard または cherry-pick で復元します。これが Git が安全である理由 — ほぼ何も完全に失われることはありません。

git
# Find the commit you lost (e.g., after a hard reset)
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: Important work  <-- this one

# Reset back to the lost commit
git reset --hard e4f5g6h

# Or cherry-pick it onto your current branch
git cherry-pick e4f5g6h

reflog と reset

ORIG_HEAD は破壊的操作(reset、merge、rebase)後に前の HEAD を指す便利な ref です。git reset --hard ORIG_HEAD で1コマンドで最後のそのような操作を取り消せます。

git
# Undo a git reset --hard
git reflog
git reset --hard HEAD@{1}

# Undo a rebase
git reflog
git reset --hard HEAD@{5}

# Undo a merge
git reset --hard ORIG_HEAD
# ORIG_HEAD is set by merge, rebase, reset, and cherry-pick

期限切れとクリーンアップ

reflog エントリは蓄積しディスク容量を消費します。expire は古いエントリを削除し、--expire-unreachable は任意の ref から到達可能でないエントリのみを対象とします。期限切れ後、git gc --prune=now を実行して到達不能オブジェクトを削除します。

git
# Expire reflog entries older than 30 days
git reflog expire --expire=30.days

# Expire entries unreachable from current branches
git reflog expire --expire-unreachable=30.days

# Delete a specific reflog entry
git reflog delete HEAD@{2}

# Dry run (see what would be expired)
git reflog expire --dry-run --expire=now --all

ブランチの reflog

各ブランチは独自の reflog を維持します。git branch -D でブランチを削除しても、コミットは reflog に残ります — ハッシュを見つけて git branch <名前> <ハッシュ> でブランチを再作成できます。

git
# Each branch has its own reflog
git reflog show main
# a1b2c3d main@{0}: commit: Update docs
# e4f5g6h main@{1}: pull origin main: Fast-forward

# Recover a deleted branch
git reflog  # find the hash the branch pointed to
git branch recovered-branch e4f5g6h

# Compare current state with a past reflog entry
git diff HEAD@{1} HEAD
24

LFS

インストールと追跡

Git LFS は大きなファイル(画像、動画、バイナリ)を Git リポジトリの外に保存し、コミットにはポインタファイルで置き換えます。git lfs track は .gitattributes にパターンを登録します。大きなファイルを追加する前に必ず .gitattributes をコミットしてください。

git
# Install Git LFS (once per user)
git lfs install

# Track large file types
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "assets/*"

# View tracking rules
cat .gitattributes

# Commit the .gitattributes file
git add .gitattributes
git commit -m "Configure LFS tracking"

LFS ファイルの追加とコミット

ファイルパターンが追跡されると、git add は自動的に LFS 経由でファイルをステージします。コミットはバイナリの代わりに小さなポインタファイル(約130バイト)を保存します。実際の内容は push 時に LFS サーバーにアップロードされます。

git
# After configuring tracking, add files normally
git add design.psd
git commit -m "Add design file"

# Verify LFS is handling the file
git lfs ls-files
# a1b2c3d4 * design.psd

# The commit contains a pointer, not the actual file
git show HEAD -- design.psd
# version https://git-lfs.github.com/spec/v1
# oid sha256:...
# size 12345678

クローンとプル

LFS 付きのリポジトリのクローンは最初にポインタファイルをダウンロードし、その後実際の内容をダウンロードします。LFS ダウンロードが失敗した場合、git lfs pull で再試行します。git lfs fetch は作業ツリーに書き込まずにオブジェクトをダウンロードします。

git
# Clone a repo with LFS files (downloads them automatically)
git clone https://github.com/user/repo.git

# If LFS files are missing, fetch them
git lfs pull

# Fetch LFS objects without checking them out
git lfs fetch

# Checkout LFS files for specific paths
git lfs checkout assets/

LFS への移行

git lfs migrate import は履歴内の大きなファイルを遅延的に LFS ポインタに変換します。これはすべてのコミットハッシュを書き換えます — すべてのコラボレーターが再クローンする必要があります。影響を確認するため最初に --dry-run を実行してください。

git
# Convert existing large files to LFS (rewrites history!)
git lfs migrate import --include="*.psd" --include-ref=refs/heads/main

# Migrate all branches
git lfs migrate import --include="*.psd" --everything

# Check what would be migrated (dry run)
git lfs migrate import --include="*.psd" --include-ref=refs/heads/main --dry-run

LFS の管理

git lfs status は保留中の LFS 変更を表示します。git lfs env は設定を表示します。git lfs fsck はポインタファイルから参照されるすべての LFS オブジェクトが存在し破損していないことを検証します。

git
# View LFS status
git lfs status

# List all LFS files in the repo
git lfs ls-files

# Check LFS configuration
git lfs env

# Untrack a file type (does not remove existing LFS objects)
git lfs untrack "*.zip"

# Verify LFS objects are present and valid
git lfs fsck
25

CI/CD 統合

GitHub Actions の基礎

GitHub Actions は push/PR でワークフローを実行します。actions/checkout がリポジトリをフェッチし、fetch-depth: 0 で完全な履歴を取得します。npm ci はロックファイルからインストールします(install より高速で厳格)。キャッシュキーで依存関係をキャッシュします。

git
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm test
      - run: npm run build

条件付きワークフロー

on: push: branches でブランチやイベントでワークフローをフィルタします。ジョブレベルの if: 条件でコンテキストに基づいてジョブをスキップします。needs: でジョブ間に依存関係を作成 — test が通過した場合のみ deploy が実行されます。

git
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh

CI での Git フック

CI パイプラインは多くの場合ローカルフックを模倣します:最初にリント(高速フェイル)、次にテスト。needs: lint でリンティングが通過した場合のみテストが実行され、CI 分を節約します。ジョブを分割すると並列ランナーで高速化できます。

git
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm ci
      - run: npm run lint
      - run: npm run typecheck

  test:
    needs: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test -- --coverage

シークレットと環境

シークレット(API キー、トークン)はリポジトリ設定に保存し、${{ secrets.NAME }} で参照します。これらはログに出力されません。環境はデプロイ前に手動承認を要求でき、ゲートを追加します。

git
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production  # requires manual approval
    steps:
      - uses: actions/checkout@v4
      - name: Deploy
        env:
          API_KEY: ${{ secrets.API_KEY }}
          DB_URL: ${{ secrets.DATABASE_URL }}
        run: ./scripts/deploy.sh "$API_KEY" "$DB_URL"

マトリックスビルド

マトリックスビルドは同じジョブを複数の OS/言語の組み合わせで並列実行します。これによりプラットフォーム固有のバグを早期にキャッチできます。fail-fast: false で1つが失敗してもすべての組み合わせを実行します。CI 分を制御するためマトリックスを合理的に保ってください。

git
jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        node-version: ['18', '20', '22']
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm test

Was this helpful?

Learning path

Learn from scratch

Learn this language from the ground up with structured lessons.