Bitbucket Cloud での Git の使用方法についてのチュートリアルです。

Bitbucket Cloud を使用して Git での変更を元に戻す方法

目的

他のユーザーとコラボレーションしながら、ローカルマシンと Bitbucket Cloud リポジトリで変更を元に戻す方法を学習します。

ミッションの概要

このチュートリアルで説明するコマンドは、git revertgit resetgit loggit status です。

所要時間 対象者 前提条件

40 分

このチュートリアルは、次の git コマンドの知識を持ったユーザーを対象としています。

git clonegit commitgit pullgit push
Git をインストール済である
Bitbucket アカウントを持っている

誰でも間違えることはあります。すべてのプッシュ操作が完璧とは限りません。このチュートリアルは、最も一般的な git 機能を使用して変更を安全に元に戻すのに役立ちます。

このチュートリアルは、次の git コマンドの知識を持ったユーザーを対象としています。

これらのコマンドの知識がなくても、Bitbucket Cloud で git の使用方法を学ぶことができます。その後、こちらに戻り、変更を元に戻す方法を学習してください。これらの git コマンドは Windows または Unix 環境向けのものです。このチュートリアルでは、ファイルシステムナビゲーションを説明する際に Unix コマンドラインユーティリティを使用します。

ローカルマシンで変更を元に戻す

元に戻したい変更がローカルシステムにあり、その変更をリモートリポジトリにプッシュしていない場合、変更を元に戻す主な方法が 2 つあります。

コマンド 用語の定義

Git revert

通常の元に戻す操作とは異なる、「元に戻す」コマンド。そのコミットがなかったことにするのではなく、そのコミットによって加えられた変更を打ち消し、コンテンツを打ち消す新しいコミットを追加します。これは Git の履歴を保全するためであり、改訂履歴の完全性とコラボレーションの信頼性の確保のために重要です。

Git のリセット

変更を元に戻す、汎用性のある git コマンド。git reset コマンドには強力なオプションがありますが、このチュートリアルでは次のリセットモードのみを使用します。

  • --soft: 選択したコミットに対して HEAD のみをリセットします。基本的に git checkout と同じ動作ですが、Detached Head 状態を生成することはありません。
  • --mixed: 両方の履歴で選択したコミットに対して HEAD をリセットし、インデックスでの変更を元に戻します。
  • --hard: 両方の履歴で選択したコミットに対して HEAD をリセットし、インデックスでの変更を元に戻し、作業ディレクトリでの変更を元に戻します。このチュートリアルでは、ハードリセットのテストは行いません。

git reset の仕組みの詳細な説明については、git-scm.com の Git Tools - Reset Demystified (Git ツール - リセットコマンド詳説) をご覧ください。

チュートリアルを進めるにつれて、変更を元に戻す方法の学習の一環として他のいくつかの git コマンドを学びます。それでは、始めましょう。

リポジトリをフォークする

元のリポジトリのコードをすべて含む一意のリポジトリを作成することから始めましょう。このプロセスは、「リポジトリの フォーク」と呼ばれます。フォークとは、共有リポジトリが Bitbucket のようなサードパーティのホスティングサービスでホストされている場合に有効な拡張 git プロセスです。

  1. 次の URL をクリック、または入力します。https://bitbucket.org/atlassian/tutorial-documentation-tests/commits/all
  2. 左側のサイドバーで + 記号をクリックし、[Fork this repositor (このリポジトリをフォーク)] を選択し、ダイアログを確認して [フォークリポジトリ] をクリックします。
  3. 新規リポジトリの概要が表示されます。
  4. + 記号をクリックし、[このリポジトリをクローン] を選択します。
  5. コンピュータ上にリポジトリのクローンを作成します。
  6. クローンのリポジトリを含むディレクトリに移動します。

これで、完全なコードを持つリポジトリとローカルシステムの既存の履歴を取得し、変更を元に戻す作業を開始できます。

ローカルシステムでの変更を見つける

元に戻したい変更を見つけて参照できるようにする必要があります。これには、特定の変更の場所を見つけるためのコマンドラインユーティリティのある Bitbucket のコミット UI を参照します。

git status

Git status は、作業ディレクトリの状態 (ローカルシステム上のリポジトリの場所) と、ステージングエリア (プロジェクト履歴に追加する変更を準備した場所) を返し、ファイルに変更が生じ、その変更がステージングエリアに追加された場合はそのファイルを表示します。git status を実行して、リポジトリの現状を調べましょう。

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean

ここに示す git status の出力は、リモート master ブランチですべてが最新に保たれていて、コミットすべき保留中の変更がないことを示しています。次の例では、変更を保留中の状態のままリポジトリを編集し、そのリポジトリを調べてみます。これは、プロジェクト履歴への追加準備 (またはステージング) がなされていない、ローカルシステム上のリポジトリのファイルに変更を加えたということです。

この次の例を説明するために、まず myquote2.html ファイルを開きます。myquote2.html の内容に変更を加え、ファイルを保存して終了します。もう一度 git status を実行し、この状態のリポジトリを調べましょう。

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
 
Changes not staged for commit:
 (use "git add <file>..." to update what will be committed)
 (use "git checkout -- <file>..." to discard changes in working directory)
 
 Modified: myquote2.html
 
no changes added to commit (use "git add" and/or "git commit -a")
--

ここに示す出力は、リポジトリには myquote2.html に対して保留中の変更があることを示しています。ここでよい点は、上記の例のように、元に戻したい変更がステージングエリアにまだ追加されていない場合、ファイルを編集するだけで続行できる点です。Git は、変更をステージングエリアに追加した時にのみ追跡を開始し、その後プロジェクト履歴に変更をコミットします。

では、myquote2.html に加えた変更を「元に戻す」操作を行いましょう。これは最小限の変更を行った簡単な例であるため、変更を元に戻すために利用可能な方法は 2 つあります。git checkout myquote2.html を実行すると、リポジトリは myquote2.html を前にコミットしたバージョンに復元します。または、git reset --hard を実行すると、リポジトリ全体を直前のコミットに戻すことができます。

git log

git log コマンドでは、プロジェクト履歴の一覧表示、フィルター、および特定の変更内容の検索を行うことができます。git status は作業ディレクトリとステージングエリアの状態を確認するためのものであるのに対し、git log はコミット済みの履歴 (コミット履歴) のみを表示します。

リポジトリの「コミット」ビューにアクセスすると、コミット履歴の同じログを Bitbucket UI 内で確認できます。当社のデモリポジトリのコミットビューは、https://bitbucket.org/dans9190/tutorial-documentation-tests/commits/all で確認できます。このビューの出力は、git log コマンドラインユーティリティと同様になり、元に戻す必要のあるコミットを見つけて特定することができます。

次の例では、履歴に複数の項目がありますが、それぞれ変更は根本的に 1 つずつのコミットです。つまり、コミットを見つけて元に戻す必要があります。

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

nothing to commit, working tree clean

$ git log

commit 1f08a70e28d84d5034a8076db9103f22ec2e982c
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Wed Feb 7 17:06:50 2018 +0000

    Initial Bitbucket Pipelines configuration

commit 52f823ca251a132225dd1cc18ad768de8d336e84
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Fri Sep 30 15:50:58 2016 -0700

    repeated quote to show how a change moves through the process

commit 4801b87c2147dce83f1bf31acfcffa6cb1d7e0a5
Merge: 1a6a403 3b29606
Author: Dan Stevens [Atlassian] <dstevens@atlassian.com>
Date:   Fri Jul 29 18:45:34 2016 +0000

    Merged in changes (pull request #6)

    Changes

一覧にあるコミットの 1 つをもう少し詳しく確認してみましょう。

commit 52f823ca251a132225dd1cc18ad768de8d336e84
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Fri Sep 30 15:50:58 2016 -0700
 
    repeated quote to show how a change moves through the process

各コミットメッセージには 4 つの要素があることがわかります。

要素 説明

コミットハッシュ

この特定の変更を識別する英数字文字列 (SHA-1 エンコード)

作成者

変更をコミットした人

日付

変更がプロジェクトにコミットされた日付

Commit Message

変更を説明するテキスト文字列。

ベストプラクティスのヒント: 短い説明のコミットメッセージを記載すれば、誰にとってもより調和のとれた作業リポジトリを作成できます。


特定のコミットを見つける

元に戻したい変更があっても、プロジェクト履歴をかなり遡らなければならず、またかなり広範囲になることがあります。そこで、git log を使用して特定の変更を見つける基本操作をいくつか学習しましょう。

  1. 端末ウィンドウで、cd (ディレクトリ変更) コマンドを使用してローカルリポジトリのトップレベルに移動します。
$ cd ~/repos/tutorial-documentation-tests/

git log --oneline コマンドを入力します。--oneline を追加すると、1 行ずつ各コミットが表示され、端末でより多くの履歴を確認できます。

q キーを押してコミットログを終了すると、いつでもコマンドプロンプトに戻ります。

次の例のような情報が表示されます。

$ git log --oneline
1f08a70 (HEAD -> master, origin/master, origin/HEAD) Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 (origin/changes) myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
...
  1. q キーを押してコマンドプロンプトに戻ります。
  2. git log コマンドによって生成された一覧から、ハッシュ c5826da がついていて変更が増えているコミットを見つけます。説明のコミットメッセージは記述されていないため、そのコミットに必要な変更が行われているかどうか確認する必要があります。
  3. 端末ウィンドウで git log 結果からコミットハッシュ c5826da をハイライトしてコピーします。
  4. git show と入力し、コピーしたコミットハッシュをペーストまたは転記し、Enter を押します。次のような情報が表示されます。
$git show c5826daeb6ee3fd89e63ce35fc9f3594fe243605
commit c5826daeb6ee3fd89e63ce35fc9f3594fe243605
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Tue Sep 8 13:50:23 2015 -0700

    more changes

diff --git a/README.md b/README.md
index bdaee88..6bb2629 100644
--- a/README.md
+++ b/README.md
@@ -11,12 +11,7 @@ This README would normally document whatever steps are necessary to get your app
 ### How do I get set up? ###

 * Summary of set up
-* Configuration
-* Dependencies
-* Database configuration
-* How to run tests
-* Deployment instructions
-* more stuff and things
:

下部のプロンプトは、すべての変更を表示するまで続行されます。q を押してコマンドプロンプトを終了します。

git log にフィルターをかけて特定のコミットを見つける

次の追加機能で git log の出力にフィルターをかけて調節できます。

フィルター 機能 コマンドの例 結果
-

表示されるコミットの数を制限する

git log -10

履歴での最新の 10 のコミット

--after

--before

関連する期間に対して表示されるコミットを制限する

--after "yyyy-mm-dd" --before "yyyy-mm-dd" も使用可能

git log --after 2017-07-04

2017 年 7 月 4 日以降のすべてのコミット

--author="name"

コミットの作成者と名前が一致するコミットをすべて一覧表示する

git log --author="Alana"

名前のフィールドに Alana とある名前の作成者によって作成されたすべてのコミット

--grep="message string"

入力した文字列と一致するコミットメッセージを含むすべてのコミットを返す

git log --grep="HOT-"

メッセージ内のテキストに HOT- が含まれるすべてのコミット

ここまでは git log コマンドについて非常に簡単に説明しました。このようなコマンドでの作業については、git log チュートリアル: 上級編をご覧ください。

git reset を使用して変更を元に戻す

まず、履歴にある直前のコミットを元に戻してみます。このとき、あなたは Bitbucket の CI/CD ソリューションパイプラインを有効化しましたが、スクリプトが正しくないことに気づいたとします。

  1. 端末ウィンドウに git log --oneline と入力します。
  2. log: 52f823c にある 2 番目のコミットのコミットハッシュをコピーし、q を押してコミットログを終了します。
  3. 端末ウィンドウに git reset --soft 52f823c と入力します。成功していればコマンドはバックグラウンドで実行されます。これで最初の変更が元に戻されました。では、このアクションの結果を確認しましょう。
  4. 端末ウィンドウに git status と入力すると、コミットが元に戻り、コミットされていない変更となっていることがわかります。次のように表示されます。
$ git status
On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)
 
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
 
    new file:   bitbucket-pipelines.yml
  1. 端末ウィンドウに git log --oneline と入力します。次のような情報が表示されます。
$ git log --oneline
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 (origin/changes) myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
...
  1. ブランチの新しい HEAD が想定どおりコミット 52f823c になっていることがわかります。
  2. q を押してログを終了します。ここまでで簡単なリセットの方法を学習したので、端末を起動させたままにしておき、もう少し複雑な操作を試してみましょう。

git reset を使用して複数の変更を元に戻す

たとえば、プルリクエスト #6 (4801b87) に再作業が必要なことに気づいたとします。クリーンな履歴を保持したいと思っているため、HEAD をリセットして、1a6a403 をコミットします。今回は git reset コマンドを使用します。

  1. git log --online を入力します。
  2. コミットハッシュ 1a6a403 (myquote edited online with Bitbucket) をコピーします。このコミットはプルリクエスト #6 の直後にあり、元に戻す必要のある変更が含まれています。
  3. 端末ウィンドウに git reset 1a6a403 と入力します。出力は次のようになります。
$ git reset 1a6a403
Unstaged changes after reset:
M README.md
M myquote2.html

変更がコミットされていない状態になったことがわかります。つまり、プロジェクトの履歴とステージングエリアの両方から複数の変更を削除したことになります。

  1. 端末ウィンドウに git status と入力します。出力は次のようになります。

$ git status
On branch master
Your branch is behind 'origin/master' by 6 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)
 
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
 
    modified:   README.md
    modified:   myquote2.html
 
Untracked files:
  (use "git add <file>..." to include in what will be committed)
 
    bitbucket-pipelines.yml
 
no changes added to commit (use "git add" and/or "git commit -a")

元に戻した最初の変更 (bitbucket-pipelines.yml ファイル) が、完全に git では追跡できなくなりました。これは、git reset を呼び出すことにより、ブランチの HEAD と git の追跡エリアまたはインデックスエリアの両方から変更を削除したためです。根本的なプロセスは、ここで説明しているよりも少し複雑です。詳細については、git reset を参照してください。

  1. 端末ウィンドウに git log --oneline と入力します。
1a6a403 myquote edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
e52470d README.md edited online with Bitbucket
e2fad94 README.md edited online with Bitbucket
592f84f Merge branch 'master' into new-feature2 Merge branch  especially if it merges an updated upstream into a topic branch.
7d0bab8 added a line
879f965 adding to the quote file
8994332 Merged in HOT-235 (pull request #2)
b4a0b43 removed sarcastic remarks because they violate policy.
b5f5199 myquote2.html created online with Bitbucket
b851618 adding my first file
5b43509 writing and using tests

ログの出力では、コミット履歴も変更され、コミット 1a6a403 で開始していることを示しています。さらに例を示して説明してみましょう。たとえば、たった今実行したリセットを元に戻したいとします。検討した結果、プルリクエスト #6 の内容を保持することにします。

resets を Bitbucket にプッシュする

Git resets は、git が提供するいくつかの「元に戻す」方法の 1 つです。リセットは通常、変更を元に戻すための「安全ではない」オプションと見なされています。ローカルに独立したコードで作業する場合はリセットでも問題ありませんが、チームメンバーと共有する場合にはリスクを伴います。

リモートチームがリセットしたブランチを共有するには、「強制プッシュ」を実行する必要があります。「強制プッシュ」は git push -f を実行することによって起動します。強制プッシュを使用すると、プッシュの実行後に構築されたブランチの履歴がすべて削除されます。

この「安全ではない」シナリオの例としては、次のものがあります。

  • 開発者 A は、ブランチで新機能の開発作業に取り組んでいます。
  • 開発者 B は、同じブランチで別の機能の開発作業に取り組んでいます。
  • 開発者 B が、開発者 A と開発者 B の両者が作業を開始する前の状態にブランチをリセットすることにします。
  • その後、開発者 B はそのブランチをリモートリポジトリに強制的にプッシュし、リセットします。
  • 開発者 A が更新を受け取るためにブランチをプルします。このプルの間、開発者 A は強制された更新を受け取ります。これによって、開発者 A のローカルブランチは両者が今までに完了したすべての作業よりも前の時点にリセットされ、両者のコミットが失われます。

git reset を元に戻す

ここまでは、git commit の SHA ハッシュを git reset に渡していました。今、git log の出力からリセットしたコミットが失われています。このようなコミットを取り戻すにはどうしたらよいでしょうか?Git がコミットへのポインターを分離しない限り、コミットが完全に削除されることはありません。さらに、git は「reflog」と呼ばれるすべての ref 動作ログを別に保存しています。git reflog を実行すれば、reflog を調べることができます。

1a6a403 HEAD@{0}: reset: moving to 1a6a403
1f08a70 HEAD@{1}: reset: moving to origin/master
1f08a70 HEAD@{2}: clone: from git@bitbucket.org:dans9190/tutorial-documentation-tests.git

git reflog の出力は、上記のようになります。リポジトリでのアクションの履歴を確認できます。最初の行は、プルリクエスト #6 を復元するために実行したリセットの参照です。それでは、プルリクエスト #6 を復元するためのリセットをリセットしましょう。この reflog の出力の 2 列目は、リポジトリで実行した変更アクションへの ref ポインターを示しています。ここで、HEAD@{0} は以前に実行したリセットコマンドの参照です。そのリセットコマンドには応答する必要はないため、リポジトリを HEAD@{1} に復元します。

$ git reset --hard HEAD@{1}
HEAD is now at 1f08a70 Initial Bitbucket Pipelines configuration

git log --oneline を使用して、リポジトリのコミット履歴を調べてみましょう。

$git log --online
1f08a70 Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
e52470d README.md edited online with Bitbucket
e2fad94 README.md edited online with Bitbucket
592f84f Merge branch 'master' into new-feature2 Merge branch  especially if it merges an updated upstream into a topic branch.
7d0bab8 added a line
:

ここでは、リポジトリのコミット履歴が、これまで実行していた前のバージョンに復元されていることを確認できます。コミット 4801b87 は最初のリセット操作では失われているように見えましたが、復元されています。git reflog は、リポジトリの変更を元に戻す強力なツールです。詳しい使用方法については、git reflog のページをご覧ください。

Git revert

前の例では、git resetgit reflog を使用して時間を遡る、重要な取り消し操作を実行しました。Git には、もう 1 つの取り消し操作ユーティリティがあり、ほとんどの場合、リセットよりも安全と見なされます。打消し操作では、指定したコミットの変更を打ち消す操作を含む新しいコミットが作成されます。このような打消しコミットはその後、リモートリポジトリに安全にプッシュされ、他の開発者と共有されます。

次のセクションでは、git revert の使用について説明します。前のセクションの例を続けて使用しましょう。まず、ログを調べて、打ち消すコミットを見つけます。

$ git log --online
1f08a70 Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
1f08a70 Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
e52470d README.md edited online with Bitbucket
e2fad94 README.md edited online with Bitbucket
592f84f Merge branch 'master' into new-feature2 Merge branch  especially if it merges an updated upstream into a topic branch.
7d0bab8 added a line
:

この例では、作業するコミットとして最新のコミット 1f08a70 を取り上げましょう。このシナリオでは、そのコミットで行った編集を元に戻すことにします。次を実行します。

$ git revert 1f08a70

これによって git merge ワークフローが開始されます。Git により新しいコミットが作成されます。その内容は、打消し操作に指定されたコミットを打ち消すことです。その後 Git によって構成済みのテキストエディターが起動し、新しいコミットメッセージが求められます。このコミットワークフローのため、打消しはより安全な取り消し操作のオプションと見なされています。打消しコミットの作成では、取り消し操作を実行した時のコミット履歴に明確な痕跡が残ります。

これで、変更を元に戻す方法の学習が終了しました。

お疲れさまでした。必要な時にこのチュートリアルを参照するか、「変更を元に戻す」セクションに進み、詳細を学習してください。Bitbucket で効率よく作業しましょう!