summaryrefslogtreecommitdiffstats
path: root/bin/git/git-rebase-under
blob: 7d425842d2360f0e70b3a0bfb9e1f0cac797dcba (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;

use Path::Class 'dir';

sub git {
    if (!defined wantarray) {
        system('git', @_);
    }
    elsif (wantarray) {
        chomp(my @ret = qx{git @_});
        return @ret;
    }
    else {
        chomp(my $ret = qx{git @_});
        return $ret;
    }
}

my $git_dir = dir(scalar(git qw(rev-parse --show-toplevel)))->subdir('.git');
my $state_file = $git_dir->file('rebase-under-state');

my ($continuing, $onto, $branch, @commits);
if ($ARGV[0] eq '--continue') {
    die "can't continue: no state file" unless -r $state_file;
    ($onto, $branch, @commits) = split("\n", $state_file->slurp);
    $continuing = 1;
}
else {
    $onto = $ARGV[0] // 'master';
    $branch = git qw(symbolic-ref -q HEAD);
    $branch =~ s+^refs/heads/++;

    my $remote_branch = "origin/$branch";
    @commits = git 'rev-list', '--reverse', "$remote_branch..$branch";
}

$state_file->openw->print(join("\n", $onto, $branch, @commits));

if ($continuing) {
    git 'commit';
}
else {
    git 'checkout', $onto;
}

while (@commits) {
    my $commit = shift @commits;
    $state_file->openw->print(join("\n", $onto, $branch, @commits));
    git 'cherry-pick', $commit;
    if ($?) {
        die <<DIE;
Conflict detected. Fix the conflict, and run `git rebase-under --continue`.
DIE
    }
}
git 'checkout', $branch;
git 'rebase', $onto;

$state_file->remove;