Git リポジトリのディレクトリ名やファイル名を、履歴も含めて変更する

git-filter-repo

久々に git filter-branch してたら git-filter-repo をお勧めされた。

$ git filter-branch
WARNING: git-filter-branch has a glut of gotchas generating mangled history
         rewrites.  Hit Ctrl-C before proceeding to abort, then use an
         alternative filtering tool such as 'git filter-repo'
         (https://github.com/newren/git-filter-repo/) instead.  See the
         filter-branch manual page for more details; to squelch this warning,
         set FILTER_BRANCH_SQUELCH_WARNING=1.

pip で導入すればよい。

$ python -m pip install --user git-filter-repo
$ git filter-repo -h
Rewrite (or analyze) repository history

    git-filter-repo destructively rewrites history (unless --analyze or
    --dry-run are given) according to specified rules.  It refuses to do any
    rewriting unless either run from a clean fresh clone, or --force was
    given.

    Basic Usage:
      git-filter-repo --analyze
      git-filter-repo [FILTER/RENAME/CONTROL OPTIONS]

    See EXAMPLES section for details.

操作してるリポジトリが他のリポジトリclone でないときは警告してくれる。優しい。

$ git filter-repo --path-rename src/b/main.txt:src/BBB/main.txt
Aborting: Refusing to overwrite repo history since this does not
look like a fresh clone.
  (expected freshly packed repo)
To override, use --force.

実験

用意した Git リポジトリ

$ find ./src -ls
13229323906180897      0 drwxr-xr-x   1 yujiorama 197609          0 1月 29 09:42 ./src
 3096224744604375      0 drwxr-xr-x   1 yujiorama 197609          0 1月 29 09:42 ./src/a
 6473924464988327      1 -rw-r--r--   1 yujiorama 197609          4 1月 29 09:43 ./src/a/main.txt
 9570149208962417      0 drwxr-xr-x   1 yujiorama 197609          0 1月 29 09:43 ./src/b
11540474045506226      1 -rw-r--r--   1 yujiorama 197609          4 1月 29 09:43 ./src/b/main.txt

$ git log --decorate --stat=120
commit ee9fbc0ebd8b4f4a1a71e8384f683a6a4f57a306 (HEAD -> master)
Author: yujiorama <yujiorama@gmail.com>
Date:   Wed Jan 29 09:43:51 2020 +0900

    modify a/main

 src/a/main.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit e4f87b7ce3868d7a6bd441a30400e54751c858fb
Author: yujiorama <yujiorama@gmail.com>
Date:   Wed Jan 29 09:43:25 2020 +0900

    add b/main

 src/b/main.txt | 1 +
 1 file changed, 1 insertion(+)

commit a9b0731a7e8c728fc89c1151287ffea4fde0cdcb
Author: yujiorama <yujiorama@gmail.com>
Date:   Wed Jan 29 09:43:01 2020 +0900

    add a/main

 src/a/main.txt | 1 +
 1 file changed, 1 insertion(+)

完全なファイルパス名を指定して変更する

src/b/main.txt から src/BBB/main.txt に変更する実験。

ファイル名を指定して変更するときは --path-rename src:dst を使う。

複数あるときはオプションを複数並べるみたい。

$ git filter-repo --force --path-rename src/b/main.txt:src/BBB/main.txt

$ find ./src -ls
13229323906180897      0 drwxr-xr-x   1 yujiorama 197609          0 1月 29 09:55 ./src
21673573206722352      0 drwxr-xr-x   1 yujiorama 197609          0 1月 29 09:47 ./src/AAA
22236523160143678      1 -rw-r--r--   1 yujiorama 197609          4 1月 29 09:47 ./src/AAA/main.txt
11821949022216882      0 drwxr-xr-x   1 yujiorama 197609          0 1月 29 09:55 ./src/BBB
 9851624185673073      1 -rw-r--r--   1 yujiorama 197609          4 1月 29 09:55 ./src/BBB/main.txt

$ git log --decorate --stat=120
commit 42d3455d44ed53f1fda2029b31770c961516afee (HEAD -> master)
Author: yujiorama <yujiorama@gmail.com>
Date:   Wed Jan 29 09:43:51 2020 +0900

    modify a/main

 src/AAA/main.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 7e9778b484494927bf6aab45ac3295feb2d2559f
Author: yujiorama <yujiorama@gmail.com>
Date:   Wed Jan 29 09:43:25 2020 +0900

    add b/main

 src/BBB/main.txt | 1 +
 1 file changed, 1 insertion(+)

commit 61b3eabc87830afefde3311739d5d7ea558e9c22
Author: yujiorama <yujiorama@gmail.com>
Date:   Wed Jan 29 09:43:01 2020 +0900

    add a/main

 src/AAA/main.txt | 1 +
 1 file changed, 1 insertion(+)

src/a/main.txtsrc/AAA/main.txt に変わってるのは別のスクリプトで実験してたから。

特に問題なく変更できている。

部分的なファイルパスを指定して変更する

どちらかというとこちらが本題。

src/BBBsrc/CCC に変更したい。

部分的なファイルパスを指定するときは --path-rename-match src:dst を使う。

$ git filter-repo --force --path-rename-match src/BBB:src/CCC

$ find ./src -ls
13229323906180897      0 drwxr-xr-x   1 yujiorama 197609          0 1月 29 09:56 ./src
21673573206722352      0 drwxr-xr-x   1 yujiorama 197609          0 1月 29 09:47 ./src/AAA
22236523160143678      1 -rw-r--r--   1 yujiorama 197609          4 1月 29 09:47 ./src/AAA/main.txt
12103423998927538      0 drwxr-xr-x   1 yujiorama 197609          0 1月 29 09:56 ./src/CCC
10133099162383729      1 -rw-r--r--   1 yujiorama 197609          4 1月 29 09:56 ./src/CCC/main.txt

$ git log --decorate --stat=120
commit da89007ace5d48d6c45466c1adaaace9f4488ed9 (HEAD -> master)
Author: yujiorama <yujiorama@gmail.com>
Date:   Wed Jan 29 09:43:51 2020 +0900

    modify a/main

 src/AAA/main.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit c85fcc4c99fa1b1b9cd55ccb90b0d9b3b696a996
Author: yujiorama <yujiorama@gmail.com>
Date:   Wed Jan 29 09:43:25 2020 +0900

    add b/main

 src/CCC/main.txt | 1 +
 1 file changed, 1 insertion(+)

commit 61b3eabc87830afefde3311739d5d7ea558e9c22
Author: yujiorama <yujiorama@gmail.com>
Date:   Wed Jan 29 09:43:01 2020 +0900

    add a/main

 src/AAA/main.txt | 1 +
 1 file changed, 1 insertion(+)

ちゃんと変更できている。

複数ファイルがあるときも上手く動くようだった。