Last active
August 29, 2015 14:00
-
-
Save simonrad/5c43b2e3f0d0c10dfac4 to your computer and use it in GitHub Desktop.
A script framework for programmatically resolving merge conflicts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ''' | |
| This script is a framework for programmatically resolving merge conflicts in a text file. | |
| You should overwrite resolve_conflict() with your own logic. | |
| Assumes the conflicts were generated inline by git, with the diff3 conflictstyle. | |
| To enable the diff3 conflictstyle, run this command: | |
| git config --global merge.conflictstyle diff3 | |
| Backup your source file before running with "overwrite" mode enabled. | |
| ''' | |
| # The conflict resolution logic goes here. | |
| # Should return the replacement_string, or None if you don't wish to resolve this conflict. | |
| def resolve_conflict(head, base, theirs, entire_conflict): | |
| return head | |
| # ---------------------------------------- | |
| import re | |
| import sys | |
| if __name__ == '__main__': | |
| usage = ''' | |
| Usage: | |
| First argument is the path of the source file. | |
| Second argument, if specified, should be "overwrite" and means that the source file will be overwritten. (Use with care, obviously.) | |
| ''' | |
| if not (2 <= len(sys.argv) <= 3): | |
| print usage | |
| sys.exit('Bad number of args.') | |
| do_overwrite_source_file = False | |
| if len(sys.argv) == 3: | |
| if sys.argv[2].lower() == 'overwrite': | |
| do_overwrite_source_file = True | |
| else: | |
| sys.exit('Last argument should be "overwrite" if specified.') | |
| source_filename = sys.argv[1] | |
| with open(source_filename) as source_file: | |
| source_text = source_file.read() | |
| pattern = re.compile( | |
| '''\\n<<<<<<< HEAD''' | |
| '''(?P<head>.*?)''' | |
| '''\\n\|\|\|\|\|\|\| merged common ancestors''' | |
| '''(?P<base>.*?)''' | |
| '''\\n=======''' | |
| '''(?P<theirs>.*?)''' | |
| '''\\n>>>>>>> (?P<branch_name>[^\\n]+)''', re.DOTALL) | |
| resolved_count = 0 | |
| total_count = 0 | |
| replacements = [] # List of (start_index, end_index, replacement_string) tuples. | |
| for match in re.finditer(pattern, source_text): | |
| head = match.groupdict()['head'] | |
| base = match.groupdict()['base'] | |
| theirs = match.groupdict()['theirs'] | |
| match_string = match.string[match.start() : match.end()] | |
| replacement_string = resolve_conflict(head, base, theirs, match_string) | |
| if replacement_string is not None: | |
| replacements.append((match.start(), match.end(), replacement_string)) | |
| resolved_count += 1 | |
| total_count += 1 | |
| print 'branch_name: ', repr(match.groupdict()['branch_name']) | |
| print 'head: ', repr(head) | |
| print 'base: ', repr(base) | |
| print 'theirs: ', repr(theirs) | |
| print 'match_string: ', repr(match_string) | |
| print 'replacement_string:', repr(replacement_string) | |
| print '--------------------' | |
| # Perform the replacements in reverse, so as not to mess up the indices. | |
| result_text = source_text | |
| replacements.sort(reverse=True) | |
| for (start, end, replacement_string) in replacements: | |
| result_text = result_text[:start] + replacement_string + result_text[end:] | |
| if do_overwrite_source_file: | |
| print 'Overwriting file.' | |
| with open(source_filename, 'w') as source_file: | |
| source_file.write(result_text) | |
| else: | |
| print 'Dry run (Not overwriting file).' | |
| print 'Resolved %d out of %d conflicts.' % (resolved_count, total_count) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment