いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

git pull した後にファイルの日付をコミット時のものに変更する

概要

たまーに必要になるときがあるので、ここにメモメモ。。。

gitとかの最近のソース管理ソフトウェアは、「コミット時の日付」を復元してくれません。pullするとその時点の日付でファイルが作成されます。(当たり前ですが)

SVNではオプションがあるので、コミット時の日付を復元できたりします。(昔々のVisual SourceSafeもこのオプションがあったはず)

んで、大企業さんとかとお仕事していると、結構な割合で「ファイルの更新日付で管理する人」がいます。

どれが変更されたのかをエクスプローラー上のファイルの更新日付で確認したいんですね。なので、全部同じ更新日付となっていると、文句言われますw

(日付なんてどうとでも変更できる値に依存するな。diff取れよっていう意見もあると思いますが、シカタガナイデス)

なので、ちょっちょいと日付を調整するプログラムを何回か作っていました。んで、作る度に忘れてしまうので以下にメモしておきます。

同じような悩みを抱えてらっしゃる方の参考になれば。

以下のように処理すればオッケイです。

  • git ls-files で git管理下のファイルリストを取得
  • それぞれのファイルに対して git log で最新コミット情報を取得して、その日付を元にファイルの日付を設定し直す

pythonで作ろうが、dotnetで作ろうが、pwsh で作ろうが何でも良かったのですが、Goで書きました。

サンプル

以下のサンプルは、内部でpowershellを使っているので windows 専用です。

//go:build windows

package main

import (
    "bufio"
    "bytes"
    "fmt"
    "log"
    "os"
    "os/exec"
    "time"
)

const (
    parseLayout  = "2006-01-02 15:04:05 -0700"
    formatLayout = "2006-01-02 15:04:05"
)

var (
    appLog = log.New(os.Stdout, "", 0)
    errLog = log.New(os.Stderr, "", 0)
)

func exitOnErr(err error) {
    if err != nil {
        errLog.Fatalln(err)
    }
}

func main() {
    err := os.Chdir(os.Args[1])
    exitOnErr(err)

    cmd := exec.Command("git", "ls-files")
    out, err := cmd.Output()
    exitOnErr(err)

    buf := bytes.NewReader(out)
    scanner := bufio.NewScanner(buf)

    appLog.Println("# Results")
    appLog.Println("")

    for scanner.Scan() {
        fpath := scanner.Text()

        cmd = exec.Command("git", "log", "-n", "1", "--no-merges", "--pretty=format:%ai", fpath)
        out, err = cmd.Output()
        exitOnErr(err)

        t, err := time.Parse(parseLayout, string(out))
        exitOnErr(err)
        dt := t.Local().Format(formatLayout)

        for _, field := range []string{"CreationTime", "LastWriteTime", "LastAccessTime"} {
            pwshCmd := fmt.Sprintf("Set-ItemProperty %s -Name %s -Value \"%s\"", fpath, field, dt)

            cmd = exec.Command("powershell", "-command", pwshCmd)
            _, err = cmd.Output()

            if err != nil {
                errLog.Println(err)
                appLog.Printf("- [ ] %s\n", fpath)

                continue
            }
        }

        appLog.Printf("- [x] %s\n", fpath)
    }

    appLog.Println("")
}
$ go run main.go 対象ディレクトリ

とすると処理が実行されます。

元ファイルのバックアップなどは取らないので、心配な場合は手動でバックアップを取ってから実行ください。

出力は、そのまま markdown として貼り付けできるようにしています。


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。