0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Git】git mvの挙動パターン一覧

Posted at

はじめに

git mvは「ファイルを移動(リネーム)するコマンド」ですが、
実際には特別な「rename」情報を記録しているわけではありません。

Gitの設計では「rename」は存在せず、
「削除 + 追加」 として履歴に残り、「これはrenameだな」と検出される仕組みです。

この記事では、ファイルの状態ごとにgit mvがどう挙動するかをパターン化して整理します。

基本挙動

git mv は、内部的に以下の処理をまとめて行っています。

mv a.txt b.txt         # ファイル名変更
git rm --cached a.txt  # インデックスから a.txt を削除
git add b.txt          # インデックスに b.txt を追加

つまり 「単なるショートカット」 に過ぎません。
このためファイルの状態によって結果が変わります。

パターン一覧

① コミット済みファイルをリネーム

git mv a.txt b.txt
  • a.txt は削除
  • b.txt が新規ファイルとして追加

git status:

renamed: a.txt -> b.txt

※ただし内部的には削除+追加。
コミットすると履歴上は「削除と追加」になるが、git statusで確認するとリネームして判定される。


「1.」のより詳細な説明

コミット済みファイルをリネームする場合の挙動をより詳しくみていきます

1. コミット済みのファイルを確認

$ ls gitmv/
test01

gitmv/配下にtest01というファイルがあります。
こちらのファイルは既にコミット済みです。

2. ファイル名を変更

$ git mv gitmv/test01 gitmv/test02

3. ファイル名変更後の状態を確認

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

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    gitmv/test01 -> gitmv/test02

renamed: gitmv/test01 -> gitmv/test02と記載ある通りリネームされたと判定されています。

4. git mvを利用せずに同じ状態にする

  • 通常のmvコマンドでファイル名を変更する
$ mv gitmv/test01 gitmv/test02
  • 現在のファイルの状態を確認する
$ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    gitmv/test01

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        gitmv/test02

no changes added to commit (use "git add" and/or "git commit -a")

gitmv/test01が削除され、まだステージングに追加されていないことが分かります。
またgitmv/test02が新規ファイルとして追加され、まだ追跡されていない状態です。

  • ファイル削除情報インデックスに追加する
$ git rm --cached gitmv/test01
rm 'gitmv/test01'

これで削除情報がインデックスに追加され、次回コミットでtest01は完全に削除されます。
※ インデックスの追加は'git add'でも可能だが、'git rm --cached'がやりたいことの文脈に一致するため利用しています。

  • 現在のファイルの状態を確認する
$ git status -uall
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    gitmv/test01

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        gitmv/test02

gitmv/test01の削除がステージングに追加されました。

  • gitmv/test02の新規追加をステージングに追加する
$ git add gitmv/test02
  • 現在のファイルの状態を確認する
$ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    gitmv/test01 -> gitmv/test02

gitmv/test01が削除、gitmv/test02が新規追加されたことにより
gitmv/test01gitmv/test02にリネームされたと判定されています。

つまり以下の二つは同じことを実行していると言えます。

$ git mv gitmv/test01 gitmv/test02
$ mv gitmv/test01 gitmv/test02
$ git rm --cached gitmv/test01
$ git add gitmv/test02

② 新規ファイル(git add 済み)をリネーム

echo "foo" > a.txt
git add a.txt
git mv a.txt b.txt
  • インデックス上で「a.txt の新規追加」が消える
  • 「b.txt の新規追加」として置き換わる

git status:

new file: b.txt

👉 rename としては記録されず、単純に「b.txt の追加」となる。


「2.」のより詳細な説明

ステージング済み新規ファイルをリネームする場合の挙動をより詳しくみていきます

1. ステージング済み新規ファイルを確認

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

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   gitmv/test01

2. ファイル名を変更

$ git mv gitmv/test01 gitmv/test03

3. ファイル名変更後の状態を確認

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

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   gitmv/test03

リネームではなく、gitmv/test03の新規追加と認識される。

4. git mvを利用せずに同じ状態にする

  • 通常のmvコマンドでファイル名を変更する
$ mv gitmv/test01 gitmv/test03
  • 現在のファイルの状態を確認する
$ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   gitmv/test01

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    gitmv/test01

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        gitmv/test03

3つの情報が分かります
gitmv/test01が新規ファイルとしてステージングエリアに追加されている
gitmv/test01が削除ファイルとして未ステージングとなっている
gitmv/test03が新規ファイルとして未追跡ファイルとなっている

  • 変更を全てステージングに追加する
$ git add -A
  • 現在のファイルの状態を確認する
$ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   gitmv/test03

git mvした結果と同じになりました。
つまり以下の2つは同じ挙動と言えます

$ git mv gitmv/test01 gitmv/test03
$ mv gitmv/test01 gitmv/test03
$ git add -A

③ 未追跡(untracked)ファイルをリネーム

echo "foo" > a.txt
git mv a.txt b.txt

fatal: not under version control, source=...

👉 エラー。
未追跡ファイルは Git 管理外なので git mv は使えない。
単純に OS コマンドの mv を使う必要がある。

④ ステージング済み+修正を加えたファイルをリネーム

echo "foo" > a.txt
git add a.txt
echo "bar" >> a.txt   # さらに修正
git mv a.txt b.txt

インデックスに「b.txt の新規ファイル(内容=foo)」が登録される

ワーキングツリーには「b.txt(内容=foo+bar)」が残る

👉 「ステージング内容」と「作業ツリー内容」が分離する。
コミット時に混乱しやすいので注意。


「4.」のより詳細な説明

1. ステージング済み+修正を加えたファイルを確認

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

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   gitmv/test01

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   gitmv/test01

2. ファイル名を変更

$ git mv gitmv/test01 gitmv/test02

3. ファイル名変更後の状態を確認

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

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    gitmv/test01
        new file:   gitmv/test02

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   gitmv/test02
  • gitmv/test01の削除ファイルがステージングに追加されている
  • gitmv/test02の変更前ファイルがステージングに追加されている
  • gitmv/test01の変更後ファイルが未ステージングとなっている
    git add .することでgitmv/test02の変更分も含めて新規ファイルとしてステージングに追加される

4. git mvを利用せずに同じ状態にする

  • 通常のmvコマンドでファイル名を変更する
$ mv gitmv/test01 gitmv/test02
  • 現在のファイルの状態を確認する
$ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   gitmv/test01

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    gitmv/test01

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        gitmv/test02

gitmv/test01への修正がステージングに追加されている
gitmv/test01の削除ファイルが未ステージングとなっている
gitmv/test02が未追跡ファイルとなっている

  • 変更を全てステージングに追加する
$ git add .
  • 現在のファイルの状態を確認する
$ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    gitmv/test01
        new file:   gitmv/test02

以上の結果から以下の2つは同じ挙動と言えます

$ git mv gitmv/test01 gitmv/test02
$ git add .
$ mv gitmv/test01 gitmv/test02
$ git add .

まとめ

git mvは複数のコマンドを実行しているため理解しづらく、かつファイルのステータスによっても挙動が微妙にことなるため今回はまとめてみました。
参考になると幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?