Table of Contents
What Do I Want?: 複数のファイルを別ディレクトリにgit mvしたい
次のような構成を持つgit管理されたフォルダが存在するとします. このとき, test_10 ~ test_15
の
名称を持つ .txt
ファイルを全て./data/old/
ディレクトリへ移動させたいとします.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.
├── data
│ ├── old
│ ├── test_10.txt
│ ├── test_11.txt
│ ├── test_12.txt
│ ├── test_13.txt
│ ├── test_14.txt
│ ├── test_15.txt
│ ├── test_20.txt
│ ├── test_21.txt
│ ├── test_22.txt
│ ├── test_23.txt
│ ├── test_24.txt
│ └── test_25.txt
├── docs
│ └── hogehoge.md
├── LICENSE
└── README.md
Solution: xargs -I
と git mv
コマンドの組合せ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
% find ./data/test_1[0-9].txt | xargs -I{} git mv {} ./data/old
% tree
.
├── data
│ ├── old
│ │ ├── test_10.txt
│ │ ├── test_11.txt
│ │ ├── test_12.txt
│ │ ├── test_13.txt
│ │ ├── test_14.txt
│ │ └── test_15.txt
│ ├── test_20.txt
│ ├── test_21.txt
│ ├── test_22.txt
│ ├── test_23.txt
│ ├── test_24.txt
│ └── test_25.txt
├── docs
│ └── git_command.md
├── LICENSE
└── README.md
ファイルが見つからなかった場合
1
2
% find ./data/test_1[0-9].txt | xargs -P2 -I{} git mv {} ./data/old
zsh: no matches found: ./data/test_1[0-9].txt
移動先に同じ名称のファイルが存在する場合
移動先に重複するファイル名が存在する場合, デフォルトでは重複するファイルに関してはエラーが返ってくるが その他のファイルは移行される.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
% echo hogehoge > ./data/test_11.txt
% echo foofoo > ./data/old/test_11.txt
% find ./data/test_1[0-9].txt | xargs -P2 -I{} git mv {} ./data/old
fatal: destination exists, source=data/test_11.txt, destination=data/old/test_11.txt
% tree
.
├── data
│ ├── old
│ │ ├── test_10.txt
│ │ ├── test_11.txt
│ │ ├── test_12.txt
│ │ ├── test_13.txt
│ │ ├── test_14.txt
│ │ └── test_15.txt
│ ├── test_11.txt
│ ├── test_20.txt
│ ├── test_21.txt
│ ├── test_22.txt
│ ├── test_23.txt
│ ├── test_24.txt
│ └── test_25.txt
├── docs
│ └── git_command.md
├── LICENSE
└── README.md
% cat data/old/test_11.txt
foofoo
REMARKS
- Overwriteで移行させたい場合は,
git mv -f
のオプションを付与して実行する
How Does It Work?
コマンドの出力をパイプで xargs
コマンドに送り込み, git mv
の引数として指定し実行することで
複数のファイルを別ディレクトリにgit mv
しています.
-I
optionを利用することで, 引数の位置を{}
で指定しています. このとき, 内部的には
git mv old_fild new_file
を1行ずつコマンドで実行する挙動となっています.
そのため, 移動先に同じ名称のファイルが存在する場合, 重複するファイルに関してはエラーが返ってくるが その他のファイルは移行されるという挙動になっています.
xargsのオプション
オプション | 効果 |
---|---|
-I replace-str |
xargs実行時に指定したコマンドの引数のうち, 置換文字部分を標準入力から読み込んだ名前で置き換える. -L1 が自動的に指定される. |
-P max-procs |
一度に最大でmax-procs個のプロセスを実行. デフォルトは1. max-procsが0の場合, xargsは可能な限り多くのプロセスを同時に実行. |
How to Check the Command Works Properly?: Define gtree
command
What Do I Want?
git mv
の結果, repositoryのファイル構成が意図したもの通りになっているか確認できればよい
Solution: Piping git ls-tree
and tree
commands
git ls-tree -r --name-only HEAD
コマンドでHEADの状態におけるレポジトリーのファイルをリストとして出力- パイプで
tree
コマンドへ渡し, 意図通りのファイル構成になっているか確認する
How to set up gtree
command
以下のようにgtree
コマンドを定義することで, gitignoreファイルに則したレポジトリtreeが取得できるようになります.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#!/usr/bin/bash
## Tree-display git-tracked files
## Author: Ryo Nakagami
## Revised: 2021-01-01
## REQUIREMENT
function usage {
cat <<EOM
NAME
$(basename "$0") - Lists the contents of a given tree object, like what "/bin/tree" does in the current git working directory.
Syntax
$(basename "$0") <folder path>
DESCRIPTION
This is a wrapper function of tree.
When your current directory is a git-tracked folder, this allows you to show files that are not ignored in .gitignore.
When you specify a directory which is not tracked by git as an input, gtree returns
<folder name>
0 directories, 0 files
When your current directory is not a git-tracked one, this returns the following error:
<folder name>
0 directories, 0 files
fatal: not a git repository (or any of the parent directories): .git
OPTIONS
-h, --help
Display help
EOM
exit 0
}
function error_message {
echo 'fatal: something wrong! Check the input'
exit 1
}
function directory_error_message {
echo 'fatal: $1 does not exist. Check the folder input'
exit 1
}
if [[ $1 == '-h' || $1 == '--help' ]]; then
usage
elif [[ $# == 0 ]]; then
git ls-tree -r --name-only HEAD | tree --fromfile;
elif [[ $# == 1 ]]; then
if [ -d $1 ]; then
git ls-tree -r --name-only HEAD $1 | tree --fromfile;
else
directory_error_message;
fi
else
error_message;
fi
git ls-tree
Description
- git管理されたワークスペースにおいて, 指定されたツリーオブジェクトの内容をリスト表示
/bin/ls -a
と似た挙動をする(pathを指定した際の挙動は異なる)HEAD
などcommit時点を指定する必要がある
使用例として,
1
% git ls-tree HEAD <folder-name>
もし, git管理されていないフォルダで使用すると
1
2
3
4
5
% git ls-tree HEAD
fatal: not a git repository (or any of the parent directories): .git
.
0 directories, 0 files
Options
-r |
Recurse into sub-trees |
--name-only |
List only filenames, one per line. |
tree --fromfile
tree
を --fromfile
optionとともに実行することで, ファイルシステムではなくコマンドラインで指定されたパスのファイルからディレクトリのリストを読み取ります.
パイプでつなぐことで, treeがパスを標準入力から読み取ることが可能となります.
References
tree with gitignore
xargsコマンド
(注意:GitHub Accountが必要となります)