はじめに
ファイル整理をしていて、過去のプロジェクトをgitで管理したいと思った。
だけど、ファイルの更新日時がすべて管理した日になるのは、なんかもったいない。
なので、あくまでもコミットしたのはその過去更新した日にしたいと思ったのがきっかけでいろいろ調べて、うまくいったので投稿した。
今回使用したスクリプトファイルはすべて、スクリプト集(github)に管理しているので、ここの説明を見るのが億劫な場合は、いきなりコードを見て、実行してみてもいいです。
目次
前準備
前提条件
試した環境
- OS
- windows10 Pro
- 必須ソフトウェア
- git for windows(git bash付き)
おそらくできるであろう環境
- OS
- linux, mac, windows10
- 必須ソフトウェア
- 何らかのgit
- linuxコマンドのdateコマンドが機能するターミナル
gitのインストール方法
windows10
今回のメインではないので、詳しい説明は省きますが、いまさらGit for Windowsのインストール、GitHubに接続してみた。に書いてある通り、インストールすれば、git bashも一緒にインストールされるはずです。
mac
触ったことがなく、あまり知らないので、ご容赦ください。
以下のサイトが参考になるかもしれません。
linux(ubuntu18.04LTS)
大体はプリインストールされています。
インストールされていない場合は、以下のコマンドをターミナルで打てば、インストールできると思います。
他のディストリビューションに関しては、触ったことがないので、ご容赦ください。
インストールされていない場合は、すいませんが、検索してください。
$ sudo apt install git
使用するコマンドの説明
今回かなり回りくどく、普通の使い方ではない使い方をしようとしているので、いろいろとコマンドが複雑に絡み合い、難しくなってしまっているため、今回使用したコマンドの中で、意味が分かっていた方がいいと思うコマンドの意味を紹介します。
GIT_COMMITTER_DATE=\"<date>\" git commit --allow-empty -m "<comment>" --date "<date>"
gitの初期コミット時に空のコミットをするためのコマンド
さらに、そのコミット日時を<date>
にする。
GIT_COMMITTER_DATE=\"<date>\" git commit -m "<comment>" --date "<date>"
gitのコミットをするためのコマンド
さらに、そのコミット日時を<date>
にする。
date -r "<filename>" '+%Y-%m-%dT%H:%M:%S%z'
ファイルの更新日のみを表示するコマンド
ls
コマンドでも、ファイルの更新日は表示可能だが、その後につなげにくいので、date
コマンドを使用
ls -1atrd $(find "$(pwd)" -type f) | head -1
現在いるフォルダ配下のすべてのファイルの更新日の中で、一番古い更新日のファイルを出力するコマンド。
head -1
は一行目を抜き出すだけのコマンド。
よって、ls -1atrd $(find "$(pwd)" -type f)
がこのコマンドの重要な部分です。
これに関しては、以下の参考サイトに書いてあることを組み合わせたものです。
git rev-parse --show-toplevel
gitレポジトリのルートディレクトリを表示してくれるコマンドです。
つまり、.git
ディレクトリが存在するディレクトリの名前を示します。
git ls-files "<filename>" --full-name
ファイル<filename>
が、git管理化にあるファイルであれば、先ほどのルートディレクトリからの相対パスを表示します。
今回は、これを逆手に取り、git add
できない.gitignoreで除外されたファイルを特定するのに使用しました。
つまり、このコマンドの表示がファイル名であれば、除外されていないファイルなので、コミットできるようにしました。
最終的なコマンド
基本方針はコミット日時をファイルの更新日に上書きしてしまうという方針です。
この方針で、ファイルの更新日にコミットの日時を合わせる場合は、以下のコマンドでできます。
また、以下のコマンドを利用したスクリプト(bash スクリプト)はスクリプト集(github)で管理しているので、よければ、参照してください。
複数ファイル(ディレクトリ)
以下のbashファイルは新規作成でも、既存レポジトリ使用する場合でも使えます。
gitで管理したいディレクトリのルートディレクトリでこのスクリプトを実行すれば完了
ただし、コミットの数は、ファイルの数だけになり、多くなってしまいます。
#!/bin/bash
IFS=$'\n'
root_dir=$(git rev-parse --show-toplevel 2>tmp.txt)
rm tmp.txt
if [ -z "$root_dir" ]; then
git init
fi
pushd "$root_dir" || exit
file_list=$(find "$(pwd)" -type f -not -path "*/.git/*")
is_first_commit=$(git branch)
if [ -z "$is_first_commit" ]; then
oldest_file_name=$(ls -1atrd $file_list | head -1)
date_info=$(date -r "$oldest_file_name" '+%Y-%m-%dT%H:%M:%S%z')
GIT_COMMITTER_DATE=\"$date_info\" git commit --allow-empty -m "first commit" --date "$date_info"
fi
old_file_list=$(ls -1atrd $file_list)
for file in ${old_file_list}; do
echo "$file"
base_name=$(basename "$file")
dir_name=$(dirname "$file")
pushd "$dir_name" || exit
date_info=$(date -r "$base_name" '+%Y-%m-%dT%H:%M:%S%z')
git add "$base_name"
git_relative_path=$(git ls-files "$base_name" --full-name)
popd || exit
if [ -f "$git_relative_path" ]; then
GIT_COMMITTER_DATE=\"$date_info\" git commit -m "feat: add $git_relative_path" --date "$date_info"
fi
done
popd || exit
単一ファイル
コミットに上書き
GIT_COMMITTER_DATE=\"$(date -r "<filename>" '+%Y-%m-%dT%H:%M:%S%z')\" git commit --amend --date \"$(date -r "<filename>" '+%Y-%m-%dT%H:%M:%S%z')\"
新たなコミット作成
GIT_COMMITTER_DATE=\"$(date -r "<filename>" '+%Y-%m-%dT%H:%M:%S%z')\" git commit --date \"$(date -r "<filename>" '+%Y-%m-%dT%H:%M:%S%z')\"
空コミットの場合(初期コミット)
GIT_COMMITTER_DATE=\"$(date -r "<filename>" '+%Y-%m-%dT%H:%M:%S%z')\" git commit --allow-empty --date \"$(date -r "<filename>" '+%Y-%m-%dT%H:%M:%S%z')\"
空コミットを上書き(初期コミット)
GIT_COMMITTER_DATE=\"$(date -r "<filename>" '+%Y-%m-%dT%H:%M:%S%z')\" git commit --allow-empty --amend --date \"$(date -r "<filename>" '+%Y-%m-%dT%H:%M:%S%z')\"
試行錯誤
ここは、僕の今回のコマンドにたどり着くまでの思考の変遷をメモしたものなので、本当に読み飛ばして構いません。
システムの時刻をいじる
参考文献のGitがファイルの日付を管理しない問題を何とかしたい(1)
を最初に見つけ、まさにやりたいことはこれだったが、システムの時刻を変更するのは抵抗があったので、やりませんでした。
この参考文献にあったgitにだけ時刻をファイル更新日に認識できるようにしたいとかんがえました。
gitにだけシステムの時刻が違うように見せたい
残念ながら、僕の検索能力、技術力では、直接それを行う方法は見つけられませんでした。
そこで、検索しているうちに偶然見つけたGitのコミット日時を上書きする2つの方法というサイトから
発想を転換して、コミットした後に書き換えてしまえればいいのではないかと考えました。
なので、この記事で紹介するコマンドは端的に言えば、ファイルの更新日になるようにコミット日時を上書きしたいというのが基本方針です。