Skip to content

Git Timesync

Sets the modification time of each file in the job directory to the date of the commit that last changed it. A checkout stamps every file with the moment it was written, so a fresh job directory looks like a project where everything changed at once. Build tools that compare timestamps, packagers that record dates inside the archive, and copy tools that skip unchanged files all read that as a full rebuild.

The op reads history from the repository Clarive hosts and touches files sitting in the job directory on the Clarive server. Place it after the files are on disk and before anything copies them anywhere else.

each project in the job each repository linked to it filtered out, or not a git repository: skipped last commit date per file under Path set file times in the job dir file the history never mentions: left alone, warning logged

Fields

Path

The part of the repository to work on, written relative to the repository root. A new op arrives with . in the box, which covers every tracked file.

Narrow it to cut the work down. docs/en reads history for that subtree and touches nothing outside it. A single file name works too. The value is a path limiter, so a directory name means everything under it.

Clearing the box is not the same as typing .. The fallback to . applies only while the op has never been saved with a value. Save an empty box and an empty path reaches Git, which rejects it and errors the job. Type . when you want the whole repository.

${var} placeholders expand against the stash before the path is used.

One path per op. For two unrelated subtrees, add a second Git Timesync.

Git Repositories

Restricts the work to the repositories you pick. Leave it empty and every repository attached to every project in the job is processed, which is the setting most rules want.

The picker holds more than one entry. Alongside Git repository resources it offers the variables that hold them, so ${repository} is a legal entry and a rule can decide at run time which repository to stamp.

An entry naming a repository that no project in the job owns matches nothing. No error, no warning, no work done. Repositories on the project that are not Git repositories are skipped whether or not you filter, and the skip is recorded at debug level only.

Which files get a new time

The op asks the hosted repository two questions: which files exist at its head, and which commit last named each of them. Both answers come from the repository's own default branch, not from the revision the job checked out. A file that exists only on the branch being deployed is absent from both answers, so it keeps the time the checkout gave it and a warning names it in the log.

The time applied is the author date of the newest commit that lists the file, converted from the time zone recorded in that commit. Access time and modification time are both set. A rebased or cherry-picked commit keeps its author date, so file times follow the original authoring rather than the rewrite.

Merge commits do not list file names in history. A file whose only change arrived through a merge gets no date and is left alone.

Files are located at <job directory>/<project name>/<repository checkout path>. The checkout path is the repository's Relative path, and a new Git repository resource arrives with that field set to /, so in practice the files sit directly under the project directory. Empty the field and the repository name becomes the subdirectory instead. Either way the layout matches what Checkout Job Items and Checkout Job Environment (all repos) write.

If your rule put the files somewhere else, the job log will not tell you. The history scan still succeeds, the touched-files entry still lists the files, and no time on disk changes. The failed write goes to the server's standard error instead. Timestamps that stayed at the checkout time are the symptom to look for.

What lands in the job log

One info line per repository as it starts, carrying the history query used. One entry per repository listing the files the op meant to stamp and the date intended for each. That list is written before the time is written, so a file the op failed to touch appears in it exactly like one it changed; read it as attempts, not results. One warning per file at the repository head that had no date to apply. The wording is fixed and there is no field to change it.

Nothing is written to the stash. A Return Key set on this op stores an empty value, so it is no use as a success flag.

When nothing happens

Three configurations look correct and do no work at all:

  • The rule never loaded the job's projects, so there is nothing to walk. Put Load Job Items into Stash ahead of this op.
  • Git Repositories lists repositories that are not attached to a project in the job.
  • Path names a directory that does not exist in the repository. Both history questions come back empty and the log shows a touched-files entry with nothing in it.

Failures behave differently. A Git error stops the op and errors the job: an empty Path, or a repository whose head does not resolve because it has no commits yet. Set Error Handling to trap or ignore errors, or wrap the op in TRY statement, when a job should survive that.

The op registers no undo. It runs again on a rollback pass unless you untick Run Rollback, and it does not restore whatever the file times were before.

On a repository with a long history the scan is the slow part, because every commit touching the path has to be read. Narrowing Path is the only lever you have.

Combining with other ops

Order matters more here than in most ops. The projects have to be in the stash and the files have to be on disk, so Load Job Items into Stash comes first, then Checkout Job Items or an equivalent, then this op.

Put it before anything that moves the files off the server, or the old times travel with them: Ship File Remotely, Sync a Remote Directory and Zip local path all copy what is on disk at the moment they run. A build launched by Run command or local script sees the corrected times only if this op ran first.

To stamp several subtrees with different settings, chain two or three copies of the op rather than looking for a multi-path syntax.

Examples

Every tracked file in every repository the job carries. This is the setting that fits most jobs.

Path               .
Git Repositories   (empty)

One subtree of one repository, which keeps the history scan short on a large repository.

Path               docs/en
Git Repositories   myapp_docs

Decide the repository at run time, from a variable an earlier op set.

Path               ${build_path}
Git Repositories   ${repository}