git

xargs: 複数のファイルを別ディレクトリにgit mvしたい

How to use git command 4/N

公開日: 2021-01-01
更新日: 2023-05-29

  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 -Igit 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

  1. git ls-tree -r --name-only HEADコマンドでHEADの状態におけるレポジトリーのファイルをリストとして出力
  2. パイプで 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コマンド



Share Buttons
Share on:

Feature Tags
Leave a Comment
(注意:GitHub Accountが必要となります)