Change naming of local patch-related branches and unify
[rsync/rsync.git] / packaging / branch-from-patch
CommitLineData
06886d36
WD
1#!/usr/bin/perl
2
3use strict;
4use warnings;
5use Getopt::Long;
6
7&Getopt::Long::Configure('bundling');
8&usage if !&GetOptions(
9 'branch|b=s' => \( my $master_branch = 'master' ),
10 'skip-check' => \( my $skip_branch_check ),
11 'delete' => \( my $delete_local_branches ),
12 'help|h' => \( my $help_opt ),
13);
14&usage if $help_opt;
15
16my %local_branch;
17open PIPE, '-|', 'git branch -l' or die "Unable to fork: $!\n";
18while (<PIPE>) {
a01e3b49 19 if (m# patch/\Q$master_branch\E/(.*)#o) {
06886d36
WD
20 $local_branch{$1} = 1;
21 }
22}
23close PIPE;
24
25if ($delete_local_branches) {
26 foreach my $name (sort keys %local_branch) {
a01e3b49 27 my $branch = "patch/$master_branch/$name";
06886d36
WD
28 system 'git', 'branch', '-D', $branch and exit 1;
29 }
30 %local_branch = ( );
31}
32
a01e3b49
WD
33require 'packaging/git-status.pl';
34check_git_state($master_branch, !$skip_branch_check, 1);
06886d36
WD
35
36my @patch_list;
37foreach (@ARGV) {
38 if (!-f $_) {
39 die "File not found: $_\n";
40 }
41 die "Filename is not a .diff file: $_\n" unless /\.diff$/;
42 push @patch_list, $_;
43}
44
45exit unless @patch_list;
46
47my(%scanned, %created, %info);
48
49foreach my $patch (@patch_list) {
50 my($where, $name) = $patch =~ m{^(.*?)([^/]+)\.diff$};
51 next if $scanned{$name}++;
52
53 open IN, '<', $patch or die "Unable to open $patch: $!\n";
54
55 my $info = '';
56 my $commit;
57 while (<IN>) {
58 if (m#^based-on: (\S+)#) {
59 $commit = $1;
60 last;
61 }
62 last if m#^index .*\.\..* \d#;
63 last if m#^diff --git #;
64 last if m#^--- (old|a)/#;
65 $info .= $_;
66 }
67 close IN;
68
69 $info =~ s/\s+\Z/\n/;
70
71 my $parent = $master_branch;
72 my @patches = $info =~ m#patch -p1 <patches/(\S+)\.diff#g;
73 if (@patches) {
74 if ($patches[-1] eq $name) {
75 pop @patches;
76 } else {
77 warn "No identity patch line in $patch\n";
78 }
79 if (@patches) {
80 $parent = pop @patches;
81 if (!$scanned{$parent}) {
82 unless (-f "$where$parent.diff") {
83 die "Unknown parent of $patch: $parent\n";
84 }
85 # Add parent to @patch_list so that we will look for the
86 # parent's parent. Any duplicates will just be ignored.
87 push @patch_list, "$where$parent.diff";
88 }
89 }
90 } else {
91 warn "No patch lines found in $patch\n";
92 }
93
94 $info{$name} = [ $parent, $info, $commit ];
95}
96
97foreach my $patch (@patch_list) {
98 create_branch($patch);
99}
100
101system 'git', 'checkout', $master_branch and exit 1;
102
103exit;
104
105sub create_branch
106{
107 my($patch) = @_;
108 my($where, $name) = $patch =~ m{^(.*?)([^/]+)\.diff$};
109
110 return if $created{$name}++;
111
112 my $ref = $info{$name};
113 my($parent, $info, $commit) = @$ref;
114
115 my $parent_branch;
116 if ($parent eq $master_branch) {
117 $parent_branch = $master_branch;
118 $parent_branch = $commit if defined $commit;
119 } else {
120 create_branch("$where/$parent.diff");
a01e3b49 121 $parent_branch = "patch/$master_branch/$parent";
06886d36
WD
122 }
123
a01e3b49 124 my $branch = "patch/$master_branch/$name";
06886d36
WD
125 print "\n", '=' x 64, "\nProcessing $branch ($parent_branch)\n";
126
127 if ($local_branch{$name}) {
128 system 'git', 'branch', '-D', $branch and exit 1;
129 }
130
131 system 'git', 'checkout', '-b', $branch, $parent_branch and exit 1;
132
133 open OUT, '>', "PATCH.$name" or die $!;
134 print OUT $info;
135 close OUT;
136 system 'git', 'add', "PATCH.$name" and exit 1;
137
138 open IN, '<', $patch or die "Unable to open $patch: $!\n";
139 $_ = join('', <IN>);
140 close IN;
141
142 open PIPE, '|-', 'patch -p1' or die $!;
143 print PIPE $_;
144 close PIPE;
145
146 system 'rm -f *.orig */*.orig';
147
148 while (m#\nnew file mode (\d+)\s+--- /dev/null\s+\Q+++\E b/(.*)#g) {
149 chmod oct($1), $2;
150 system 'git', 'add', $2;
151 }
152
153 while (1) {
154 system 'git status';
155 print 'Press Enter to commit, Ctrl-C to abort, or type a wild-name to add a new file: ';
156 $_ = <STDIN>;
157 last if /^$/;
158 chomp;
159 system "git add $_";
160 }
161
162 while (system 'git', 'commit', '-a', '-m', "Creating branch from $name.diff.") {
163 exit 1 if system '/bin/zsh';
164 }
165}
166
167sub usage
168{
169 die <<EOT;
170Usage branch-from-patch [OPTIONS] patches/DIFF...
171
172Options:
173-b, --branch=BRANCH Create branches relative to BRANCH if no "based-on"
174 header was found in the patch file.
175 --skip-check Skip the check that ensures starting with a clean branch.
a01e3b49 176 --delete Delete all the local patch/BASE/* branches, not just the ones
06886d36
WD
177 that are being recreated.
178-h, --help Output this help message.
179EOT
180}