File Coverage

blib/lib/App/Git/Workflow/Command/BranchConflicts.pm
Criterion Covered Total %
statement 71 74 95.9
branch 12 18 66.6
condition 2 6 33.3
subroutine 15 15 100.0
pod 4 4 100.0
total 104 117 88.8


line stmt bran cond sub pod time code
1             package App::Git::Workflow::Command::BranchConflicts;
2              
3             # Created on: 2015-04-12 06:56:18
4             # Create by: Ivan Wills
5             # $Id$
6             # $Revision$, $HeadURL$, $Date$
7             # $Revision$, $Source$, $Date$
8              
9 2     2   45249 use strict;
  2         5  
  2         52  
10 2     2   11 use warnings;
  2         3  
  2         49  
11 2     2   1749 use Pod::Usage ();
  2         116378  
  2         63  
12 2     2   2223 use Data::Dumper qw/Dumper/;
  2         13544  
  2         150  
13 2     2   1840 use English qw/ -no_match_vars /;
  2         8644  
  2         12  
14 2     2   2584 use App::Git::Workflow;
  2         140444  
  2         110  
15 2     2   1866 use App::Git::Workflow::Command qw/get_options/;
  2         28549  
  2         126  
16 2     2   1790 use Capture::Tiny qw/capture_stderr/;
  2         51625  
  2         2208  
17              
18             our $VERSION = 0.4;
19             our $workflow = App::Git::Workflow->new;
20             our ($name) = $PROGRAM_NAME =~ m{^.*/(.*?)$}mxs;
21             our %option;
22              
23             sub run {
24 3     3 1 12692 my ($self) = @_;
25              
26 3         19 get_options(
27             \%option,
28             'remote|r',
29             'both|a',
30             'merge|m=s',
31             'since|s=s',
32             'ignore|i=s',
33             'quiet|q',
34             );
35              
36 3 50       2100 my ($type, @arg) = $option{remote} ? (qw/remote -r/) : $option{both} ? (qw/both -a/) : ();
    100          
37             my @branches
38             = $option{merge}
39 0         0 ? map {/^\s+(.*)$/; $1} $workflow->git->branch(@arg, '--no-merged', $option{merge})
  0         0  
40 3 50       19 : $workflow->branches($type);
41 3         412 my %conflicts;
42              
43             # check all branches for conflicts with other branches
44 3         12 while (@branches > 1) {
45 6         1224 my $first_branch = shift @branches;
46 6 50 33     25 next if $option{since} && !$workflow->git->log(qw/-n1 --since/, $option{since}, $first_branch);
47              
48 6 50       19 print "Checking $first_branch\n" if $option{verbose};
49              
50 6         32 $self->checkout_branch($first_branch);
51              
52 6         14 for my $branch (@branches) {
53 12 50 33     38 next if $option{since} && !$workflow->git->log(qw/-n1 --since/, $option{since}, $branch);
54 12 100       77 if ( $self->merge_branch_conflicts($branch) ) {
55 2         3 push @{ $conflicts{$first_branch} }, $branch;
  2         10  
56             }
57             }
58              
59 6         20 $workflow->git->reset('HEAD');
60 6         198 $workflow->git->clean('-xfd');
61 6         172 $workflow->git->checkout('.');
62             capture_stderr {
63 6     6   3482 $workflow->git->checkout('-');
64 6         320 };
65             }
66              
67 3 100       1220 if (%conflicts) {
68 1         48 print "Conflicting branches:\n";
69 1         8 for my $branch (sort keys %conflicts) {
70 2         5 print " $branch\n", map {" $_\n"} @{ $conflicts{$branch} };
  2         22  
  2         6  
71             }
72             }
73             else {
74 2         91 print "No conflicts.\n";
75             }
76              
77 3         26 $self->cleanup();
78              
79 3         15 return;
80             }
81              
82             my @checkouts;
83             sub checkout_branch {
84 6     6 1 13 my ($self, $branch) = @_;
85              
86 6         27 my $local = 'branch-conflicts-' . sprintf '%03i', scalar @checkouts;
87             capture_stderr {
88 6     6   3582 $workflow->git->checkout('-b', $local, '--no-track', $branch);
89 6         177 };
90              
91 6         2251 push @checkouts, $local;
92              
93 6         13 return $local;
94             }
95              
96             sub merge_branch_conflicts {
97 12     12 1 22 my ($self, $branch) = @_;
98              
99             capture_stderr {
100 12     12   6772 eval { $workflow->git->merge('--no-commit', $branch) };
  12         39  
101 12         341 };
102 12         15959 my $status = $workflow->git->status;
103 12         404 eval { $workflow->git->merge('--abort'); };
  12         34  
104              
105 12 50       352 if ($option{ignore}) {
106 0         0 $status =~ s/both (?:added|modified): \s+ $option{ignore}//;
107             }
108              
109 12         62 return $status =~ /both (?:added|modified)/;
110             }
111              
112             sub cleanup {
113              
114 3     3 1 15 while ( my $branch = shift @checkouts) {
115 6         107 $workflow->git->branch('-D', $branch);
116             }
117              
118 3         107 return;
119             }
120             1;
121              
122             __DATA__
123              
124             =head1 NAME
125              
126             App::Git::Workflow::Command::BranchConflicts - Module to find git branches that would conflict if merged
127              
128             =head1 VERSION
129              
130             This documentation refers to App::Git::Workflow::Command::BranchConflicts version 0.4
131              
132             =head1 SYNOPSIS
133              
134             git-branch-conflicts [--remote|-r|--all|-a] [(--merge|-m) branch] [(--since|-s) date] [(--ignore|-i) regex]
135              
136             OPTIONS:
137             -r --remote List all remote branches
138             -a --all List all branches
139             -m --merge[=]branch
140             Operate only on branches not merged with this branch
141             -s --since[=]date
142             Only look at branches that have changes since this date
143             -i --ignore[=]regex
144             Ignore any files matching this regex that conflict during
145             test merges (e.g. pom.xml changes)
146             -q --quiet quite output
147              
148             --verbose Show more detailed option
149             --version Prints the version information
150             --help Prints this help information
151             --man Prints the full documentation for git-branch-grep
152              
153             =head1 DESCRIPTION
154              
155              
156             =head1 SUBROUTINES/METHODS
157              
158             =head2 C<run ()>
159              
160             Entry point to running conflict checking
161              
162             =head2 C<checkout_branch ($branch)>
163              
164             Checks out branch in temporary branch
165              
166             =head2 C<merge_branch_conflicts ($branch)>
167              
168             Tries merging branch into current branch
169              
170             =head2 C<cleanup ()>
171              
172             Deletes all temporary branches
173              
174             =head1 DIAGNOSTICS
175              
176             =head1 CONFIGURATION AND ENVIRONMENT
177              
178             =head1 DEPENDENCIES
179              
180             =head1 INCOMPATIBILITIES
181              
182             =head1 BUGS AND LIMITATIONS
183              
184             There are no known bugs in this module.
185              
186             Please report problems to Ivan Wills (ivan.wills@gmail.com).
187              
188             Patches are welcome.
189              
190             =head1 AUTHOR
191              
192             Ivan Wills - (ivan.wills@gmail.com)
193              
194             =head1 LICENSE AND COPYRIGHT
195              
196             Copyright (c) 2015 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077).
197             All rights reserved.
198              
199             This module is free software; you can redistribute it and/or modify it under
200             the same terms as Perl itself. See L<perlartistic>. This program is
201             distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
202             without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
203             PARTICULAR PURPOSE.
204              
205             =cut