📄 resolve-changelogs
字号:
if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) { $line = " " . substr($line, 1); } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") { next; # Discard } } $newPatch .= $line . "\n"; } return $newPatch;}sub fixMergedChangeLogs($;@){ my $revisionRange = shift; my @changedFiles = @_; if (scalar(@changedFiles) < 1) { # Read in list of files changed in $revisionRange open GIT, "-|", $GIT, "diff", "--name-only", $revisionRange || die; push @changedFiles, <GIT>; close GIT || die; die "No changed files in $revisionRange" if scalar(@changedFiles) < 1; chomp @changedFiles; } my @changeLogs = grep { defined $_ } map { findChangeLog($_) } @changedFiles; die "No changed ChangeLog files in $revisionRange" if scalar(@changeLogs) < 1; system("$GIT filter-branch --tree-filter 'PREVIOUS_COMMIT=\`$GIT rev-parse \$GIT_COMMIT^\` && MAPPED_PREVIOUS_COMMIT=\`map \$PREVIOUS_COMMIT\` $0 -f \"" . join('" "', @changeLogs) . "\"' $revisionRange"); # On success, remove the backup refs directory if (WEXITSTATUS($?) == 0) { rmtree(qw(.git/refs/original)); }}sub fixOneMergedChangeLog($){ my $file = shift; my $patch; # Read in patch for incorrectly merged ChangeLog entry { local $/ = undef; open GIT, "-|", $GIT, "diff", ($ENV{GIT_COMMIT} || "HEAD") . "^", $file || die; $patch = <GIT>; close GIT || die; } # Always checkout the previous commit's copy of the ChangeLog system($GIT, "checkout", $ENV{MAPPED_PREVIOUS_COMMIT} || "HEAD^", $file); # The patch must have 0 or more lines of context, then 1 or more lines # of additions, and then 1 or more lines of context. If not, we skip it. if ($patch =~ /\n@@ -(\d+),(\d+) \+(\d+),(\d+) @@\n( .*\n)*((\+.*\n)+)( .*\n)+$/m) { # Copy the header from the original patch. my $newPatch = substr($patch, 0, index($patch, "@@ -${1},${2} +${3},${4} @@")); # Generate a new set of line numbers and patch lengths. Our new # patch will start with the lines for the fixed ChangeLog entry, # then have 3 lines of context from the top of the current file to # make the patch apply cleanly. $newPatch .= "@@ -1,3 +1," . ($4 - $2 + 3) . " @@\n"; # We assume that top few lines of the ChangeLog entry are actually # at the bottom of the list of added lines (due to the way the patch # algorithm works), so we simply search through the lines until we # find the date line, then move the rest of the lines to the top. my @patchLines = map { $_ . "\n" } split(/\n/, $6); foreach my $i (0 .. $#patchLines) { if ($patchLines[$i] =~ /^\+\d{4}-\d{2}-\d{2} /) { unshift(@patchLines, splice(@patchLines, $i, scalar(@patchLines) - $i)); last; } } $newPatch .= join("", @patchLines); # Add 3 lines of context to the end open FILE, "<", $file || die; for (my $i = 0; $i < 3; $i++) { $newPatch .= " " . <FILE>; } close FILE; # Apply the new patch open(PATCH, "| patch -p1 $file > /dev/null") || die; print PATCH $newPatch; close(PATCH) || die; # Run "git add" on the fixed ChangeLog file system($GIT, "add", $file); showStatus($file, 1); } elsif ($patch) { # Restore the current copy of the ChangeLog file since we can't repatch it system($GIT, "checkout", $ENV{GIT_COMMIT} || "HEAD", $file); print STDERR "WARNING: Last change to ${file} could not be fixed and re-merged.\n" if $printWarnings; }}sub mergeChanges($$$){ my ($fileMine, $fileOlder, $fileNewer) = @_; my $traditionalReject = $fileMine =~ /\.rej$/ ? 1 : 0; local $/ = undef; my $patch; if ($traditionalReject) { open(DIFF, "<", $fileMine); $patch = <DIFF>; close(DIFF); rename($fileMine, "$fileMine.save"); rename($fileOlder, "$fileOlder.save"); } else { open(DIFF, "-|", qw(diff -u), $fileOlder, $fileMine) || die; $patch = <DIFF>; close(DIFF); } unlink("${fileNewer}.orig"); unlink("${fileNewer}.rej"); open(PATCH, "| patch --fuzz=3 $fileNewer > /dev/null") || die; print PATCH fixChangeLogPatch($patch); close(PATCH); my $result; # Refuse to merge the patch if it did not apply cleanly if (-e "${fileNewer}.rej") { unlink("${fileNewer}.rej"); unlink($fileNewer); rename("${fileNewer}.orig", $fileNewer); $result = 0; } else { unlink("${fileNewer}.orig"); $result = 1; } if ($traditionalReject) { rename("$fileMine.save", $fileMine); rename("$fileOlder.save", $fileOlder); } return $result;}sub parseFixMerged($$;$){ my ($switchName, $key, $value) = @_; if (defined $key) { if (defined findChangeLog($key)) { unshift(@ARGV, $key); $fixMerged = ""; } else { $fixMerged = $key; } } else { $fixMerged = ""; }}sub removeChangeLogArguments(){ my @results = (); for (my $i = 0; $i < scalar(@ARGV); ) { my $file = findChangeLog($ARGV[$i]); if (defined $file) { splice(@ARGV, $i, 1); push @results, $file; } else { $i++; } } return @results;}sub resolveChangeLog($){ my ($file) = @_; my ($fileMine, $fileOlder, $fileNewer) = conflictFiles($file); return unless $fileMine && $fileOlder && $fileNewer; if (mergeChanges($fileMine, $fileOlder, $fileNewer)) { if ($file ne $fileNewer) { unlink($file); rename($fileNewer, $file) || die; } unlink($fileMine, $fileOlder); resolveConflict($file); showStatus($file, 1); } else { showStatus($file); print STDERR "WARNING: ${file} could not be merged using fuzz level 3.\n" if $printWarnings; unlink($fileMine, $fileOlder, $fileNewer) if isGit(); }}sub resolveConflict($){ my ($file) = @_; if (isSVN()) { system($SVN, "resolved", $file); } elsif (isGit()) { system($GIT, "add", $file); } else { die "Unknown version control system"; }}sub showStatus($;$){ my ($file, $isConflictResolved) = @_; if (isSVN()) { system($SVN, "status", $file); } elsif (isGit()) { my @args = qw(--name-status); unshift @args, qw(--cached) if $isConflictResolved; system($GIT, "diff", @args, $file); } else { die "Unknown version control system"; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -