はじめに
Git Advent Calendar 2023 15日目の投稿です。よろしくおねがいします。
ハンズオン形式で個人的によく使うコマンドをまとめておきます。完全に個人用のメモですが、ちょっと忘れたときなどに誰かの参考になればいいな~と思ってまとめます。
まとめるコマンド(随時更新してくつもり)
git diff
git reset
git checkout
git chery-pick
git revert
git rebase
git diff
git diff
は2つのツリー間の差分をとるコマンド。
-
git diff
- 作業ディレクトリとインデックスの差分をとる。
- 作業していて修正箇所がなんなのか確認するときによく使う。
-
git diff commit
- 作業ディレクトリと
commit
間の差分をとる。 - あんま使わない。
- 作業ディレクトリと
-
git diff --cached commit
- インデックスと指定されたコミットの差分をとる。
-
commit
にHEAD
を指定してコミットする内容が想定通りか確認をするときに使う。
-
git diff commit1 commit2
-
commit1
とcommit2
の差分をとる。 - コミット間でどういう修正があったか確認するときによく使う。
-
ファイル名のみ差分取る
git diff commit1 commit2 --name-only
例
準備
リポジトリに「hello1」、インデックスに「hello2」、作業ディレクトリに「hello3」と書いた「sample.txt」ファイルを用意しておきます。
~/Desktop/git/sample3 (master)
$ echo "hello1" > sample.txt
~/Desktop/git/sample3 (master)
$ git add .
~/Desktop/git/sample3 (master)
$ git commit -m"first commit"
~/Desktop/git/sample3 (master)
$ git log --oneline
4256de5 (HEAD -> master) first commit
~/Desktop/git/sample3 (master)
$ echo "hello2" > sample.txt
~/Desktop/git/sample3 (master)
$ git add .
~/Desktop/git/sample3 (master)
$ echo "hello3" > sample.txt
実行
※「hello1」がコミット、「hello2」がインデックス、「hello3」が作業ディレクトリです。
~/Desktop/git/sample3 (master)
$ git diff
diff --git a/sample.txt b/sample.txt
index 14be0d4..1b069b1 100644
--- a/sample.txt
+++ b/sample.txt
@@ -1 +1 @@
-hello2
+hello3
~/Desktop/git/sample3 (master)
$ git diff 4256de5
diff --git a/sample.txt b/sample.txt
index 15b8f2a..1b069b1 100644
--- a/sample.txt
+++ b/sample.txt
@@ -1 +1 @@
-hello1
+hello3
~/Desktop/git/sample3 (master)
$ git diff --cached 4256de5
diff --git a/sample.txt b/sample.txt
index 15b8f2a..14be0d4 100644
--- a/sample.txt
+++ b/sample.txt
@@ -1 +1 @@
-hello1
+hello2
git reset
git reset
はリポジトリとインデックスと作業内容を既知の状態に変更するコマンド。
-
git reset --soft commit
-
HEAD
の参照とブランチの参照を指定されたコミットに変更。 - インデックスと作業ディレクトリの内容は変更されない。
- インデックスと作業ディレクトリの作業内容のコミット先を変えたいときに使う。
-
-
git reset --mixed commit
-
HEAD
の参照とブランチの参照を指定されたコミットに変更。 - インデックスの内容もそのコミットが表すツリー構造にあうように変更。
- 作業ディレクトリの内容は変更されない。
- 個人的にはあんま使わない。
-
-
git reset --hard commit
-
HEAD
もインデックスも作業ディレクトリも変更。 - 作業を無に帰したいときに使う。マージした後に
ORIG_HEAD
したり。
-
例
準備
リポジトリに「hello1」、インデックスに「hello2」、作業ディレクトリに「hello3」と書いた「sample.txt」ファイルを用意しておきます。
~/Desktop/git/sample3 (master)
$ echo "hello1" > sample.txt
~/Desktop/git/sample3 (master)
$ git add .
~/Desktop/git/sample3 (master)
$ git commit -m"first commit"
~/Desktop/git/sample3 (master)
$ git log --oneline
4256de5 (HEAD -> master) first commit
~/Desktop/git/sample3 (master)
$ echo "hello2" > sample.txt
~/Desktop/git/sample3 (master)
$ git add .
~/Desktop/git/sample3 (master)
$ echo "hello3" > sample.txt
~/Desktop/git/sample3 (master)
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: sample.txt
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: sample.txt
実行
とりあえずgit reset --soft HEAD
して作業ディレクトリとインデックスが変わらないことを確認です。
~/Desktop/git/sample3 (master)
$ git reset --soft HEAD
~/Desktop/git/sample3 (master)
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: sample.txt
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: sample.txt
次にgit reset --mixed HEAD
してインデックスが変わることを確認です。
今回、HEAD
の内容にインデックスをリセットするので、git status
した時にChanges to be committed:~~
の内容が無くなることを期待します。
~/Desktop/git/sample3 (master)
$ git reset --mixed HEAD
Unstaged changes after reset:
M sample.txt
~/Desktop/git/sample3 (master)
$ git status
On branch 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: sample.txt
no changes added to commit (use "git add" and/or "git commit -a")
unstaged
されました。
次にgit reset --hard
します。
ステージされてるファイルがなくなったので、インデックスと作業ディレクトリにファイル修正中のファイルがあるようにしておきます。
~/Desktop/git/sample3 (master)
$ git add .
~/Desktop/git/sample3 (master)
$ echo "hello4" > sample.txt
~/Desktop/git/sample3 (master)
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: sample.txt
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: sample.txt
git reset --hard
します。
~/Desktop/git/sample3 (master)
$ git reset --hard HEAD
HEAD is now at 4256de5 first commit
~/Desktop/git/sample3 (master)
$ git status
On branch master
nothing to commit, working tree clean
いままでの作業が無に帰り、一番初めのコミットの内容にインデックスも作業ディレクトリの内容もリセットされました。
HEAD
にリセットすると分かりにくいかもしれないので、複数コミットを作って過去のコミットにリセットしてみます。
説明:もうひとつコミットをつくる
~/Desktop/git/sample3 (master)
$ echo "hello2" > sample.txt
~/Desktop/git/sample3 (master)
$ git add .
~/Desktop/git/sample3 (master)
$ git commit -m"second commit"
[master 6c08bf5] second commit
1 file changed, 1 insertion(+), 1 deletion(-)
~/Desktop/git/sample3 (master)
$ git log --oneline
6c08bf5 (HEAD -> master) second commit
4256de5 first commit
説明:インデックスと作業ディレクトリに修正中のファイルを作る
~/Desktop/git/sample3 (master)
$ echo "hello3" > sample.txt
~/Desktop/git/sample3 (master)
$ git add .
~/Desktop/git/sample3 (master)
$ echo "hello4" > sample.txt
~/Desktop/git/sample3 (master)
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: sample.txt
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: sample.txt
git reset
してみます。
~/Desktop/git/sample3 (master)
$ git reset --soft 4256de5
インデックスと作業ディレクトリに変化はありませんが、、、
~/Desktop/git/sample3 (master)
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: sample.txt
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: sample.txt
HEAD
の位置が移動してます。
~/Desktop/git/sample3 (master)
$ git log --oneline --all
4256de5 (HEAD -> master) first commit
元のHEAD
に戻します。
~/Desktop/git/sample3 (master)
$ git reset --soft 6c08bf5
~/Desktop/git/sample3 (master)
$ git log --oneline
6c08bf5 (HEAD -> master) second commit
4256de5 first commit
git reset --mixed
してみます。
~/Desktop/git/sample3 (master)
$ git reset --mixed 4256de5
Unstaged changes after reset:
M sample.txt
~/Desktop/git/sample3 (master)
$ git status
On branch 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: sample.txt
no changes added to commit (use "git add" and/or "git commit -a")
~/Desktop/git/sample3 (master)
$ git log --oneline
4256de5 (HEAD -> master) first commit
インデックスとリポジトリに登録された内容が同一のオブジェクトになるので、ステージされてる状態がなくなり、HEAD
が4256de5
を指すようになりました。
元に戻って、、
~/Desktop/git/sample3 (master)
$ git reset --mixed 6c08bf5
Unstaged changes after reset:
M sample.txt
~/Desktop/git/sample3 (master)
$ git status
On branch 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: sample.txt
no changes added to commit (use "git add" and/or "git commit -a")
~/Desktop/git/sample3 (master)
$ git log --oneline
6c08bf5 (HEAD -> master) second commit
4256de5 first commit
最後にgit reset --hard
します。
~/Desktop/git/sample3 (master)
$ git reset --hard 4256de5
HEAD is now at 4256de5 first commit
~/Desktop/git/sample3 (master)
$ git status
On branch master
nothing to commit, working tree clean
~/Desktop/git/sample3 (master)
$ git log --oneline
4256de5 (HEAD -> master) first commit
いままでのすべての作業が無に帰りました。
git reset --hard
をすると作業ディレクトリが指定したコミットID(何も指定しないとHEAD
)に更新されることから、修正中のファイルがすべて消えます。特にUntrackedなファイルがある状態でgit reset --hard
すると、ファイルがなかったことになるので注意してください。
git checkout
今までブランチを指定してきたgit checkout
ですが、過去のコミットにも戻れます。
下のようなログがあったときに、、
~/Desktop/git/sample3 (master)
$ git log --oneline
4256de5 (HEAD -> master) first commit
2つコミットを付け足します。
~/Desktop/git/sample3 (master)
$ echo "hello10" >sample.txt
~/Desktop/git/sample3 (master)
$ git commit sample.txt -m"second commit"
[master 2e8e7e3] second commit
1 file changed, 1 insertion(+), 1 deletion(-)
~/Desktop/git/sample3 (master)
$ cat sample.txt
hello10
~/Desktop/git/sample3 (master)
$ echo "hello20" > sample.txt
~/Desktop/git/sample3 (master)
$ git commit sample.txt -m"third commit"
[master 21e00a9] third commit
1 file changed, 1 insertion(+), 1 deletion(-)
ログはこうなります。
~/Desktop/git/sample3 (master)
$ git log --oneline
21e00a9 (HEAD -> master) third commit
2e8e7e3 second commit
4256de5 first commit
おのおののコミット時点の「sample.txt」は↓の中身です。
-
4256de5
:hello1 -
2e8e7e3
:hello10 -
21e00a9
:hello20 ←cat
するとわかるように現状このファイルが見れる状態
$ cat sample.txt
hello20
4256de5
に時をもどしましょう。git checkout commit
でHEAD
がコミットIDに移動します。
~/Desktop/git/sample3 (master)
$ git checkout 4256de5
Note: checking out '4256de5'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch-name>
HEAD is now at 4256de5 first commit
ファイルの中身を確認すると、過去のファイルの中身に戻ってます。
~/Desktop/git/sample3 ((4256de5...))
$ cat sample.txt
hello1
作業前のもとの状態に戻るにはgit checkout ブランチ名
です。
~/Desktop/git/sample3 ((4256de5...))
$ git checkout master
Previous HEAD position was 4256de5 first commit
Switched to branch 'master'
~/Desktop/git/sample3 (master)
$ git log --oneline
21e00a9 (HEAD -> master) third commit
2e8e7e3 second commit
4256de5 first commit
また、過去の状態を確認していて新しくブランチを作りたいときは、git checkout -b <branchname>
で続けて作業ができます。
git cherry-pick
git cherry-pick コミットID
は指定したコミットIDの内容をカレントブランチに適用して新しくコミットを作ります。
another
ブランチを作成してコミットを1つ作ります。
~/Desktop/git/sample3 (master)
$ git branch another
~/Desktop/git/sample3 (master)
$ git checkout another
Switched to branch 'another'
~/Desktop/git/sample3 (another)
$ echo "hello another" > sample.txt
~/Desktop/git/sample3 (another)
$ git commit sample.txt -m"another commit 1"
[another 0f6a11f] another commit 1
1 file changed, 1 insertion(+), 1 deletion(-)
~/Desktop/git/sample3 (another)
$ git log --oneline --graph --all
* 0f6a11f (HEAD -> another) another commit 1
* 21e00a9 (master) third commit
* 2e8e7e3 second commit
* 4256de5 first commit
git cherry-pick another
で、master
ブランチにanother
ブランチの内容を取り込みます。
~/Desktop/git/sample3 (another)
$ git checkout master
Switched to branch 'master'
~/Desktop/git/sample3 (master)
$ git cherry-pick another
[master 231e0fe] another commit 1
Date: Mon Nov 13 14:42:35 2023 +0900
1 file changed, 1 insertion(+), 1 deletion(-)
~/Desktop/git/sample3 (master)
$ git log --oneline --graph --all
* 231e0fe (HEAD -> master) another commit 1
| * 0f6a11f (another) another commit 1
|/
* 21e00a9 third commit
* 2e8e7e3 second commit
* 4256de5 first commit
~/Desktop/git/sample3 (master)
$ cat sample.txt
hello another
単純な例では競合が発生しませんでしたが、複数のコミットをgit cherry-pick
で入れ替えて取り込む場合など、競合が発生する可能性があります。
git revert
git revert
はコミットを打ち消すコミットを作成します。
打ち消す方法としてはgit reset
がありますが、git revert
は打ち消したことがコミットとして履歴に残ります。
master
ブランチの先頭のコミットの内容を取り消したいとします。
~/Desktop/git/sample3 (master)
$ git revert master
[master ae4838e] Revert "another commit 1"
1 file changed, 1 insertion(+), 1 deletion(-)
~/Desktop/git/sample3 (master)
$ git log --oneline --graph --all
* ae4838e (HEAD -> master) Revert "another commit 1"
* 231e0fe another commit 1
| * 0f6a11f (another) another commit 1
|/
* 21e00a9 third commit
* 2e8e7e3 second commit
* 4256de5 first commit
~/Desktop/git/sample3 (master)
$ cat sample.txt
hello20
打ち消すコミットが作られて、打ち消した結果、master
ブランチの直前のコミット21e00a9
の内容に修正されました。
git rebase
git rebase
は一連のコミットの基点を変更する際に使います。
今、こういうログを用意します。
~/Desktop/git/sample3 (master)
$ git log --oneline --graph --all
* ae4838e (HEAD -> master) Revert "another commit 1"
* 231e0fe another commit 1
| * 0f6a11f (another) another commit 1
|/
* 21e00a9 third commit
* 2e8e7e3 second commit
* 4256de5 first commit
another
ブランチが21e00a9
から分岐していますが、これを任意のコミットから分岐させるのがgit rebase
です。例えば、master
から分岐させてローカルで作業していた際にリモートのmaster
ブランチの開発が進んでしまった場合にgit rebase
して最新のmaster
の内容をローカルに反映させるときに使います。
早速つかってみます。another
ブランチの基点をae4838e
から分岐させます。
~/Desktop/git/sample3 (master)
$ git checkout another
Switched to branch 'another'
~/Desktop/git/sample3 (another)
$ git rebase master
First, rewinding head to replay your work on top of it...
~/Desktop/git/sample3 (another)
$ cat sample.txt
hello20
~/Desktop/git/sample3 (another)
$ git checkout master
Switched to branch 'master'
~/Desktop/git/sample3 (master)
$ git log --oneline --graph --all
* ae4838e (HEAD -> master, another) Revert "another commit 1"
* 231e0fe another commit 1
* 21e00a9 third commit
* 2e8e7e3 second commit
* 4256de5 first commit
master
ブランチにanother
ブランチの内容がすべてあったため、another
ブランチをae4838e
に移動させるだけでした。
さいごに
なにかで使ったコマンドはここにまとめて随時更新していこうと思います。