Git's main job is to make sure you never lose a committed change. But, it's also designed to give you total control over your development workflow. This includes letting you define exactly what your project history looks like; however, it also creates the potential to lose commits. Git provides its history-rewriting commands under the disclaimer that using them may result in lost content.


git commit --amend

The git commit --amend command is a convenient way to fix up the most recent commit. It lets you combine staged changes with the previous commit instead of committing it as an entirely new snapshot. It can also be used to simply edit the previous commit message without changing its snapshot.

Git チュートリアル: git commit --amend

But, amending doesn’t just alter the most recent commit—it replaces it entirely. To Git, it will look like a brand new commit, which is visualized with an asterisk (*) in the diagram above. It’s important to keep this in mind when working with public repositories.


git commit --amend



Premature commits happen all the time in the course of your everyday development. It’s easy to forget to stage a file or to format your commit message the wrong way. The --amend flag is a convenient way to fix these little mistakes.


On the git reset page, we talked about how you should never reset commits that have been shared with other developers. The same goes for amending: never amend commits that have been pushed to a public repository.


The following example demonstrates a common scenario in Git-based development. We edit a few files that we would like to commit in a single snapshot, but then we forget to add one of the files the first time around. Fixing the error is simply a matter of staging the other file and committing with the --amend flag:

# Edit hello.py and main.py git add hello.py git commit # Realize you forgot to add the changes from main.py git add main.py git commit --amend --no-edit

The editor will be populated with the message from the previous commit and including the --no-edit flag will allow you to make the amendment to your commit without changing its commit message. You can change it if necessary, otherwise just save and close the file as usual. The resulting commit will replace the incomplete one, and it will look like we committed the changes to hello.py and main.py in a single snapshot.

git rebase


Git チュートリアル: プロジェクト履歴の直線性を維持するリベース

見かけ上は、リベースはあるコミットから他のコミットにブランチを移動する手段に過ぎません。しかし Git の内部では、新たなコミットを生成してそれを移動先のベースコミットに適用することによってこれを行なっており、これは即ち文字通りにプロジェクト履歴の書き換えをしていることになります。ここでは、ブランチそのものは同じものに見えていても、それを構成するコミットは全く異なることを理解することが重要です。


git rebase <base>

Rebase the current branch onto <base>, which can be any kind of commit reference (an ID, a branch name, a tag, or a relative reference to HEAD).


リベースの主要な目的はプロジェクト履歴の直線性を維持することにあります。例えば、あるフィーチャーでの作業開始後に master ブランチに進行があった状況を考えます:

Git が master でブランチをリベースします

You have two options for integrating your feature into the master branch: merging directly or rebasing and then merging. The former option results in a 3-way merge and a merge commit, while the latter results in a fast-forward merge and a perfectly linear history. The following diagram demonstrates how rebasing onto master facilitates a fast-forward merge.

Git チュートリアル: 早送りマージ

Rebasing is a common way to integrate upstream changes into your local repository. Pulling in upstream changes with git merge results in a superfluous merge commit every time you want to see how the project has progressed. On the other hand, rebasing is like saying, “I want to base my changes on what everybody has already done.”


As we’ve discussed with git commit --amend and git reset, you should never rebase commits that have been pushed to a public repository. The rebase would replace the old commits with new ones, and it would look like that part of your project history abruptly vanished.

次の例は、プロジェクトの直線性を維持するために git rebase と git merge を併用したものです。これは、素早く確実に早送りマージを行う手軽な方法です。

# Start a new feature git checkout -b new-feature master # Edit files git commit -a -m "Start developing a feature"


# Create a hotfix branch based off of master git checkout -b hotfix master # Edit files git commit -a -m "Fix security hole" # Merge back into master git checkout master git merge hotfix git branch -d hotfix

hotfix を master にマージすると、プロジェクト履歴には分岐が発生します。そこで単にgit merge コマンドを使うのではなく、リベースによって履歴の直線性を維持しつつフィーチューの統合を行います:

git checkout new-feature git rebase master

これにより、new-feature は master の先端に移動したので、master との通常の早送りマージが可能となります:

git checkout master git merge new-feature

git rebase -i

Running git rebase with the -i flag begins an interactive rebasing session. Instead of blindly moving all of the commits to the new base, interactive rebasing gives you the opportunity to alter individual commits in the process. This lets you clean up history by removing, splitting, and altering an existing series of commits. It’s like git commit --amend on steroids.


git rebase -i <base>

Rebase the current branch onto <base>, but use an interactive rebasing session. This opens an editor where you can enter commands (described below) for each commit to be rebased. These commands determine how individual commits will be transferred to the new base. You can also reorder the commit listing to change the order of the commits themselves.



ほとんどの開発者は、 master ブランチにマージする前にフィーチャーブランチの見栄えをよくするためにインタラクティブなリベースを使用する傾向があります。インタラクティブなリベースを使用すると、重要性の低いコミットを一纏めにし、不要なコミットを削除し、その他すべてを整理してから「公式」なリポジトリにコミットすることができます。事情を知らない者にとっては、このフィーチャー開発が全体的によく計画されたコミットの 1 本の系列として順調に進行したかのように見えます。

The example found below is an interactive adaptation of the one from the non-interactive git rebase page.

# Start a new feature git checkout -b new-feature master # Edit files git commit -a -m "Start developing a feature" # Edit more files git commit -a -m "Fix something from the previous commit" # Add a commit directly to master git checkout master # Edit files git commit -a -m "Fix security hole" # Begin an interactive rebasing session git checkout new-feature git rebase -i master

最後のコマンドによってエディターが開き、ブランチ new-feature で行われた 2 つのコミットを関連情報と共に表示します:

pick 32618c4 Start developing a feature pick 62eed47 Fix something from the previous commit

なお、各々のコミットの前にある pick コマンドは、リベースにおける動作を指定する任意のコマンドに変更することができます。ここでは、squash コマンドを使用して 2 つのコミットを結合するとします:

pick 32618c4 Start developing a feature squash 62eed47 Fix something from the previous commit

Save and close the editor to begin the rebase. This will open another editor asking for the commit message for the combined snapshot. After defining the commit message, the rebase is complete and you should be able to see the squashed commit in your git log output. This entire process can be visualized as follows:

Git Tutorial: git rebase -i example

ここで、結合されたコミットは元のコミットのいずれとも異なる ID を有すること、即ちこのコミットは実は新たなコミットであることに留意してください。


git checkout master git merge new-feature

The real power of interactive rebasing can be seen in the history of the resulting master branch—the extra 62eed47 commit is nowhere to be found. To everybody else, it looks like you’re a brilliant developer who implemented the new-feature with the perfect amount of commits the first time around. This is how interactive rebasing can keep a project’s history clean and meaningful.

git reflog

Git では、reflogと呼ばれる機能が働いて、ブランチの先端に対する更新の追跡が行われています。これにより、いかなるブランチからもいかなるタグからも参照されていない更新内容であってもその時点に戻ることができます。履歴を書き換えた後であっても reflog にはブランチの過去の状態が記録されており、必要な場合にはそこに戻ることができます。


git reflog

ローカルリポジトリの reflog を表示するコマンドです。

git reflog --relative-date

相対形式の日付 (例: 2 週間前) で reflog を表示するコマンドです。


現在の HEAD において更新 (ブランチの切り替え、新たに加えられた変更のプル、履歴の書き換え、あるいは単なる新規コミットの実行など) が加えられるたびに reflog に新たな項目が追加されます。

To understand git reflog, let's run through an example.

0a2e358 HEAD@{0}: reset: moving to HEAD~2 0254ea7 HEAD@{1}: checkout: moving from 2.2 to master c10f740 HEAD@{2}: checkout: moving from master to 2.2

The reflog above shows a checkout from master to the 2.2 branch and back. From there, there's a hard reset to an older commit. The latest activity is represented at the top labeled HEAD@{0}.

取り消しが意図しないものであった場合でも、2 つのコミットを取り消す前に (0254ea7) をポイントしていたコミットの元情報が reflog に残っています。

git reset --hard 0254ea7

Using git reset it is then possible to change master back to the commit it was before. This provides a safety net in case history was accidentially changed.

なお、変更がローカルリポジトリにコミット済みである場合は reflog が唯一のセーフティネットであること、また reflog は HEAD の移動を記録しているのみであることに留意してください。