commitFileModifications function

Future<void> commitFileModifications(
  1. FutureOr<void> block(), {
  2. required String commitMessage,
})

Commits only the file changes that have been done in block

Implementation

Future<void> commitFileModifications(
  FutureOr<void> Function() block, {
  required String commitMessage,
}) async {
  final stashName = 'pre-bump-${DateTime.now().toIso8601String()}';

  // stash changes
  'git stash save --include-untracked "$stashName"'
      .start(progress: Progress.printStdErr());

  try {
    // apply modifications
    await block();

    // commit
    'git add -A'.start(progress: Progress.printStdErr());
    'git commit -m "$commitMessage" --no-verify'
        .start(progress: Progress.printStdErr());
    'git --no-pager log -n1 --oneline'.run;
  } catch (e) {
    printerr('Detected error, discarding modifications');
    // discard all modifications
    'git reset --hard'.start(progress: Progress.printStdErr());
    rethrow;
  } finally {
    final stashes = 'git stash list'.start(progress: Progress.capture()).lines;
    final stash = stashes.firstOrNullWhere((line) => line.contains(stashName));
    if (stash != null) {
      final stashId = RegExp(r'stash@{(\d+)}').firstMatch(stash)?.group(1);
      // restore changes
      'git merge --squash --strategy-option=theirs stash@{$stashId}'
          .start(progress: Progress.print());
      try {
        // apply modifications again to make sure the stash did not overwrite already made changes
        await block();
      } catch (e) {
        // ignore
      }
    }
  }
}