Git で特定のブランチだけクローンする single-branch オプションとそのリポジトリにブランチを追加する設定

試した環境

本題

通常git cloneコマンドでリポジトリをクローンすると、リモートリポジトリの全てのブランチを取得します。 1つのブランチだけcloneするには、--single-branch オプションを付けます。

git clone --single-branch <URL>

更に -b オプションでブランチを指定できます。

git clone --single-branch -b <name> url

こうしてクローンしたローカルリポジトリでは、git fetchコマンドもこのgit cloneで指定した1つのブランチに対して行われます。 これはこれで便利ですが、後から他のリモートブランチを追加したくなる場合もあります。 他のリモートブランチを追加したい場合、ローカルリポジトリの設定を変更します。

#リモートリポジトリ名が'origin'とした場合
git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'

参考

Git - git-clone Documentation

Git - git-config Documentation

cp コマンドの --parents オプションでディレクトリ構成を保持したまま特定のファイルだけコピーする。

試した環境

本題

cp コマンドで --parents オプションを指定することでディレクトリ構成を保持したままコピーできます。 つまりは以下のようにコピーできます。

$ mkdir -p source/subdir destination
$ touch source/subdir/example.txt  source/subdir/example2.txt
$ cd source
$ cp --parents subdir/example.txt ../destination/
$ cd ..
$ $ tree
.
├── destination
│   └── subdir
│       └── example.txt
└── source
    └── subdir
        ├── example.txt
        └── example2.txt

この --parents オプションは複数のディレクトリに対して特定のファイルをコピーしたいときに役立つと思います。 例えば、以下のようなディレクトリ構成を考えます。

$ tree
.
└── results
    ├── condition00
    │   ├── output.heavy
    │   ├── stderr.log
    │   └── stdout.log
    ├── condition01
    │   ├── output.heavy
    │   ├── stderr.log
    │   └── stdout.log
#   ...省略
    └── condition99
        ├── output.heavy
        ├── stderr.log
        └── stdout.log

output.heavy はサイズがとても大きいファイルだとします。 このとき全ての condition?? ディレクトリ下のlogファイルだけをコピーしたい場合、以下の通り実行します。

mkdir -p /path/to/destination/
cd results
find . -type f -name "*.log" -print0 | xargs -0 -I{} cp -a --parents {} /path/to/destination/
$ tree  /path/to/destination/
/path/to/destination/
├── condition00
│   ├── stderr.log
│   └── stdout.log
├── condition01
│   ├── stderr.log
│   └── stdout.log
#   ...省略
└── condition99
    ├── stderr.log
    └── stdout.log

もし output.heavy がコピーの負担が小さいファイルのならば、ディレクトリ全体をコピーしてから不要なファイルを削除する方法をとるかもしれません。

cp -a results/* /path/to/destination/
find /path/to/destination/ -type f -name "output.heavy" -delete

logファイル以外のファイルサイズが大きかったり、logファイル以外のファイル数が多い場合は、 --parents オプションを使った cp が有効なのではないかと思います。

参考

man cp

GitLab の Compare revisions の結果は多分 git log とトリプルドットの git diff

試した環境

  • 2023/06/04時点のgitlab.com (多分 16.0.1)
  • git version 2.41.0.windows.1

本題

以下のように2つのブランチを用意します。 1つはもう一つのブランチを squash merge します。

$ ## edit and commit in develop branch 
$ git switch main
$ git merge --squash develop
$ git log --oneline --graph --all
* 0209881 (HEAD -> main, origin/main, origin/HEAD) Squashed commit of the following:
| * aaf2826 (origin/develop) edit 2
| * de5eb78 edit 1
| * 132257d add file
|/
* 3361c61 Initial commit

この2つのブランチをダブルドットのgit diffをしても差分はありません。

$ git diff main..develop

しかしこれら2つのブランチを GitLab のリポジトリにpushし Compare revisions で確認すると差分が表示されます。

この差分の結果はダブルドットのgit diffコマンドではなく、トリプルドットのgit diffコマンドの結果に相当します。

$ git diff main...develop
diff --git a/compare-test.txt b/compare-test.txt
new file mode 100644
index 0000000..4f8d76e
--- /dev/null
+++ b/compare-test.txt
@@ -0,0 +1,2 @@
+edittext 1
+edittext 2

それの裏付けになるか分かりませんが、URLを見るとmain...developとトリプルドットになっています。 URLの左右とGitLabの画面の左右が逆になるのは注意が必要です。

https://gitlab.com/[groupname]/[projectname]/-/compare/main...develop?from_project_id=XXXXXXXX&straight=false

ちなみにURLの最後のstraight=falsestraight=trueにすると差分が出なくなります。

コミットの表示はダブルドットのgit logコマンドの結果に近いです。 コマンドの左右とGitLabの画面の左右が逆になるのは注意が必要です。

$ git log --oneline main..develop
aaf2826 (HEAD -> develop, origin/develop) edit 2
de5eb78 edit 1
132257d add file

参考

Git - リビジョンの選択

bash で複数のコマンドの合計の時間計測するにはコマンドを括弧で囲む

試した環境

本題

ワンラインでtime command1; command2;とすると、command1の時間計測だけ行われます。

$ time sleep 1; sleep 2;

real    0m1.001s
user    0m0.001s
sys     0m0.000s

複数のコマンドの合計の時間計測をしたい場合はtime { command1; command2; }のように波括弧で囲みます。 開始の{の後にはスペースが必要です。

$ time { sleep 1; sleep 2; }

real    0m3.005s
user    0m0.005s
sys     0m0.000s

もしくは丸括弧で囲みます。 こちらは開始の(の後にはスペースがあってもなくても動きます。

$ time (sleep 1; sleep 2;)

real    0m3.003s
user    0m0.003s
sys     0m0.000s

ちなみに上記の波括弧や丸括弧を使う方法は GNU time では利用できません。

$ /usr/bin/time --version
GNU time 1.7
$ /usr/bin/time { sleep 1; sleep 2; }
-bash: syntax error near unexpected token `}'
$ /usr/bin/time (sleep 1; sleep 2;)
-bash: syntax error near unexpected token `sleep'

参考

Man page of TIME

unzip の -v オプションはファイルを展開しない

試した環境

本題

unzip コマンドの -v オプションはzipファイルの情報を詳しく表示しますが、実際には展開しません。

$ ls -a
.  ..  test.zip
$ unzip -v test.zip
Archive:  test.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
     109  Stored      109   0% 2023-01-16 21:59 8ac69895  202301.txt
    1121  Defl:N      693  38% 2023-02-25 15:53 3c9c170b  202302.txt
    2771  Defl:N     1475  47% 2023-03-25 17:48 2b3550ab  202303.txt
    6611  Defl:N     3357  49% 2023-04-30 17:03 c230ac77  202304.txt
--------          -------  ---                            -------
   10612             5634  47%                            4 files
$ ls -a
.  ..  test.zip

man unzipunzip -hhコマンドで表示される -v オプションの説明を読みましたが、ファイルを展開しない旨がこの記述からは私は読み取れませんでした。

$ man unzip
...
       -v     list  archive  files (verbose format) or show diagnostic version info.  This option has evolved and now
              behaves as both an option and a modifier.  As an option it has two purposes:  when a zipfile is  speci‐
              fied  with no other options, -v lists archive files verbosely, adding to the basic -l info the compres‐
              sion method, compressed size, compression ratio and 32-bit CRC.  In contrast to most of  the  competing
              utilities,  unzip  removes the 12 additional header bytes of encrypted entries from the compressed size
              numbers.  Therefore, compressed size and compression ratio figures are independent of the  entry's  en‐
              cryption status and show the correct compression performance.  (The complete size of the encrypted com‐
              pressed data stream for zipfile entries is reported by the more verbose  zipinfo(1)  reports,  see  the
              separate manual.)  When no zipfile is specified (that is, the complete command is simply ``unzip -v''),
              a diagnostic screen is printed.  In addition to the normal header with release date and version,  unzip
              lists  the  home  Info-ZIP ftp site and where to find a list of other ftp and non-ftp sites; the target
              operating system for which it was compiled, as well as (possibly) the hardware on  which  it  was  com‐
              piled,  the  compiler  and version used, and the compilation date; any special compilation options that
              might affect the program's operation (see also DECRYPTION below); and any options stored in environment
              variables  that  might do the same (see ENVIRONMENT OPTIONS below).  As a modifier it works in conjunc‐
              tion with other options (e.g., -t) to produce more verbose or debugging output; this is not  yet  fully
              implemented but will be in future releases.
...

$ unzip -hh
...
  -v   Use verbose list format.  If given alone as unzip -v show version
         information.  Also can be added to other list commands for more
         verbose output.
...
  -v  List zipfile information in verbose, multi-page format.
...

-d オプションを加えると、-d オプションは無視され、ファイルを展開しない旨のメッセージが見られます。

$ unzip -vd . test.zip
caution:  not extracting; -d ignored
Archive:  test.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
     109  Stored      109   0% 2023-01-16 21:59 8ac69895  202301.txt
    1121  Defl:N      693  38% 2023-02-25 15:53 3c9c170b  202302.txt
    2771  Defl:N     1475  47% 2023-03-25 17:48 2b3550ab  202303.txt
    6611  Defl:N     3357  49% 2023-04-30 17:03 c230ac77  202304.txt
--------          -------  ---                            -------
   10612             5634  47%                            4 files

参考

man unzip
unzip -hh

bashでパラメータ展開の文字列をシングルクォートとダブルクォートで二重に囲った時の動作

試した環境

本題

bashにおいてパラメータ展開の文字列$HOGEをシングルクォートで囲った場合はパラメータは展開されません。 ダブルクォートで囲った場合はパラメータが展開されます。

$ WIDTH=1920
$ HEIGHT=1920
$ echo $WIDTH
1920
$ echo '$WIDTH'
$WIDTH
$ echo "$WIDTH"
1920

ただし、シングルクォートで囲ってそれをさらにダブルクォートで囲った場合は、パラメータが展開されます。

$ echo "size='$WIDTH $HEIGHT'"
size='1920 1080'

逆にダブルクォートで囲ってそれをさらにシングルクォートで囲った場合は、パラメータが展開されません。

$ echo 'size="$WIDTH $HEIGHT"'
size="$WIDTH $HEIGHT"

おまけとして、三重に囲おうとした場合は、パラメータ文字列の部分が結果的にクォート(ダブルクォート)で囲われていないことになるので、パラメータが展開されます。

$ echo 'parameter "--size='$WIDTH $HEIGHT'"'
parameter "--size=1920 1080"

$ echo "parameter '--size="$WIDTH $HEIGHT"'"
parameter '--size=1920 1080'

ヒアドキュメントで変数やコマンドを展開したくない場合は終了文字列をクォートする

試した環境

本題

通常のヒアドキュメントはドキュメント内の変数やコマンドを展開します。

$ cat << EOT
pi = $(echo | awk '{print atan2(0, -1)}')
EOT
pi = 3.14159

終了文字列を指定する際に終了文字列をクォートすると展開されなくなります。

$ cat << 'EOT'
pi = $(echo | awk '{print atan2(0, -1)}')
EOT
pi = $(echo | awk '{print atan2(0, -1)}')

終了する際の文字列はクォートしないことに注意します。

これを利用することでヒアドキュメントでシェルスクリプトが作りやすくなると思います。

$ cat << 'EOT' > pi.sh
#!/bin/bash

PI=$(echo | awk '{print atan2(0, -1)}')
echo pi = ${PI}
EOT
$ chmod 755 pi.sh
$ ./pi.sh
pi = 3.14159

参考

https://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html#lbBO