createBackup method
Snapshots the index and working tree without modifying either.
Returns the snapshot commit sha, or null when there is nothing to back
up (clean tree) or a snapshot cannot be taken (unborn HEAD, i.e. the
very first commit in a repository). Never throws: a hook must still be
able to run when backups are unavailable.
Implementation
Future<String?> createBackup() async {
// `stash create` writes a commit object but leaves the index, the working
// tree, and the stash stack untouched -- unlike `stash push`.
final result = await _git(['stash', 'create']);
if (result.exitCode != 0) {
logger.detail(
'Could not create a backup (exit ${result.exitCode}); '
'continuing without one. Error: ${result.stderr}',
);
return null;
}
final sha = switch (result.stdout) {
final String out => out.trim(),
final Future<String> out => (await out).trim(),
};
if (sha.isEmpty) {
logger.detail('Nothing to back up, the index and working tree are clean');
return null;
}
final anchored = await _git(['update-ref', backupRef, sha]);
if (anchored.exitCode != 0) {
// The snapshot still exists and [restoreBackup] still works; it is only
// unprotected from `git gc`, so keep going rather than failing the hook.
logger.detail(
'Failed to anchor the backup at $backupRef. '
'Error: ${anchored.stderr}',
);
}
logger.detail('Backed up the index and working tree at $sha');
return sha;
}