App-Git-Autofixup
view release on metacpan or search on metacpan
git-autofixup view on Meta::CPAN
my $upstream = rev_parse("${raw_upstream}^{commit}");
push @upstreams, $upstream;
} else {
@upstreams = find_merge_bases();
if (!@upstreams) {
die "Can't find tracking branch. Please specify a revision.\n";
}
}
if ($num_context_lines < 0) {
die "number of context lines must be zero or greater\n";
}
if (!grep { $strict == $_ } @STRICTNESS_LEVELS) {
die "invalid strictness level: $strict\n";
} elsif ($strict > 0 && $num_context_lines == 0) {
die "strict hunk assignment requires context\n";
}
my $toplevel = toplevel_dir();
chdir $toplevel or die "cd to toplevel: $!\n";
my $hunks = diff_hunks($num_context_lines);
my $summary_for = summary_for_commits(@upstreams);
my $alias_for = sha_aliases($summary_for);
my $grafts_file = create_grafts_file(@upstreams);
my %blame_for = map {$_ => blame($_, $alias_for, $grafts_file)} @{$hunks};
my $hunks_for = fixup_hunks_by_sha({
hunks => $hunks,
blame_for => \%blame_for,
summary_for => $summary_for,
strict => $strict,
});
my @ordered_shas = ordered_shas($hunks, sha_for_hunk_map($hunks_for));
if ($dryrun) {
if ($use_detailed_exit_codes) {
return exit_code($hunks, $hunks_for);
}
return 0;
}
my $old_index = $ENV{GIT_INDEX_FILE};
local $ENV{GIT_INDEX_FILE}; # Throw away changes between main() calls.
if (is_index_dirty()) {
# Limit the tempfile's lifetime to the execution of main().
my $tempfile = create_temp_index($old_index);
}
for my $sha (@ordered_shas) {
my $fixup_hunks = $hunks_for->{$sha};
commit_fixup($sha, $fixup_hunks);
}
if ($use_detailed_exit_codes) {
return exit_code($hunks, $hunks_for);
}
return 0;
}
if (!caller()) {
exit main();
}
1;
__END__
=pod
=head1 NAME
App::Git::Autofixup - create fixup commits for topic branches
=head1 SYNOPSIS
git-autofixup [<options>] [<revision>]
=head1 DESCRIPTION
F<git-autofixup> parses hunks of changes in the working directory out of C<git diff> output and uses C<git blame> to assign those hunks to commits in C<E<lt>revisionE<gt>..HEAD>, which will typically represent a topic branch, and then creates fixup c...
If any changes have been staged to the index using C<git add>, then F<git-autofixup> will only consider staged hunks when trying to create fixup commits. A temporary index is used to create any resulting commits.
By default a hunk will be included in a fixup commit if all the lines in the hunk's context blamed on topic branch commits refer to the same commit, so there's no ambiguity about which commit the hunk corresponds to. If there is ambiguity the assignm...
For example, the added line in the hunk below is adjacent to lines committed by commits C<99f370af> and C<a1eadbe2>. If these are both topic branch commits then it's ambiguous which commit the added line is fixing up and the hunk will be ignored.
COMMIT |LINE|HEAD |WORKING DIRECTORY
99f370af| 1|first line | first line
| | |+added line
a1eadbe2| 2|second line | second line
But if that second line were instead blamed on an upstream commit (denoted by C<^>), the hunk would be added to a fixup commit for C<99f370af>:
99f370af| 1|first line | first line
| | |+added line
^ | 2|second line | second line
Output similar to this example can be generated by setting verbosity to 2 or greater by using the verbosity option multiple times, eg. C<git-autofixup -vv>, and can be helpful in determining how a hunk will be handled.
F<git-autofixup> is not to be used mindlessly. Always inspect the created fixup commits to ensure hunks have been assigned correctly, especially when used on a working directory that has been changed with a mix of fixups and new work.
=head2 Articles
=over
=item
L<Jordan Torbiak: Absorb changes across a topic branch in git|https://torbiak.com/post/autofixup/>
=item
L<Symflower: Effortlessly correct your Git commits with git-autofixup|https://symflower.com/en/company/blog/2021/git-autofixup/>
=back
=head1 OPTIONS
=over
=item -h
( run in 2.240 seconds using v1.01-cache-2.11-cpan-5a3173703d6 )