Skip to content

Commit

Permalink
Merge pull request #98 from mhagger/empty-autocommits
Browse files Browse the repository at this point in the history
Support autocommitting merges with no changes
  • Loading branch information
mhagger committed Jul 9, 2016
2 parents 56dcbfb + 6d44fc4 commit 7334f53
Showing 1 changed file with 103 additions and 38 deletions.
141 changes: 103 additions & 38 deletions git-imerge
Expand Up @@ -288,21 +288,7 @@ class UncleanWorkTreeError(Failure):
pass


def require_clean_work_tree(action):
"""Verify that the current tree is clean.
The code is a Python translation of the git-sh-setup(1) function
of the same name."""

process = subprocess.Popen(
['git', 'rev-parse', '--verify', 'HEAD'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
)
err = communicate(process)[1]
retcode = process.poll()
if retcode:
raise UncleanWorkTreeError(err.rstrip())

def refresh_index():
process = subprocess.Popen(
['git', 'update-index', '-q', '--ignore-submodules', '--refresh'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
Expand All @@ -312,18 +298,52 @@ def require_clean_work_tree(action):
if retcode:
raise UncleanWorkTreeError(err.rstrip() or out.rstrip())

error = []

def unstaged_changes():
"""Return True iff there are unstaged changes in the working copy"""

try:
check_call(['git', 'diff-files', '--quiet', '--ignore-submodules'])
return False
except CalledProcessError:
error.append('Cannot %s: You have unstaged changes.' % (action,))
return True


def uncommitted_changes():
"""Return True iff the index contains uncommitted changes."""

try:
check_call([
'git', 'diff-index', '--cached', '--quiet',
'--ignore-submodules', 'HEAD', '--',
])
return False
except CalledProcessError:
return True


def require_clean_work_tree(action):
"""Verify that the current tree is clean.
The code is a Python translation of the git-sh-setup(1) function
of the same name."""

process = subprocess.Popen(
['git', 'rev-parse', '--verify', 'HEAD'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
)
err = communicate(process)[1]
retcode = process.poll()
if retcode:
raise UncleanWorkTreeError(err.rstrip())

refresh_index()

error = []
if unstaged_changes():
error.append('Cannot %s: You have unstaged changes.' % (action,))

if uncommitted_changes():
if not error:
error.append('Cannot %s: Your index contains uncommitted changes.' % (action,))
else:
Expand Down Expand Up @@ -359,6 +379,18 @@ def rev_list(*args):
]


git_dir_cache = None

def git_dir():
global git_dir_cache

if git_dir_cache is None:
git_dir_cache = check_output(
['git', 'rev-parse', '--git-dir']
).rstrip('\n')
return git_dir_cache


def get_type(arg):
"""Return the type of a git object ('commit', 'tree', 'blob', or 'tag')."""

Expand Down Expand Up @@ -2581,6 +2613,57 @@ def request_user_merge(merge_state, i1, i2):
)


def simple_merge_in_progress():
# Check if a merge (of a single branch) is in progress:
try:
with open(os.path.join(git_dir(), 'MERGE_HEAD')) as f:
heads = [line.rstrip() for line in f]
except IOError:
return False

return len(heads) == 1


def commit_user_merge(merge_state, edit_log_msg=None):
"""If a merge is in progress and ready to be committed, commit it.
If a simple merge is in progress and any changes in the working
tree are staged, commit the merge commit and return True.
Otherwise, return False.
"""

if not simple_merge_in_progress():
return False

# Check if all conflicts are resolved and everything in the
# working tree is staged:
refresh_index()
if unstaged_changes():
raise UncleanWorkTreeError(
'Cannot proceed: You have unstaged changes.' % (action,)
)

# A merge is in progress, and either all changes have been staged
# or no changes are necessary. Create a merge commit.
cmd = ['git', 'commit', '--no-verify']

if edit_log_msg is None:
edit_log_msg = get_default_edit()

if edit_log_msg:
cmd += ['--edit']
else:
cmd += ['--no-edit']

try:
check_call(cmd)
except CalledProcessError:
raise Failure('Could not commit staged changes.')

return True


def incorporate_user_merge(merge_state, edit_log_msg=None):
"""If the user has done a merge for us, incorporate the results.
Expand Down Expand Up @@ -2652,31 +2735,13 @@ def incorporate_user_merge(merge_state, edit_log_msg=None):
# If we reach this point, then the scratch reference exists and is
# checked out. Now check whether there is staged content that
# can be committed:

merge_frontier = MergeFrontier.map_known_frontier(merge_state)

try:
check_call(['git', 'diff-index', '--cached', '--quiet', 'HEAD', '--'])
except CalledProcessError:
# There are staged changes; commit them if possible.
cmd = ['git', 'commit', '--no-verify']

if edit_log_msg is None:
edit_log_msg = get_default_edit()

if edit_log_msg:
cmd += ['--edit']
else:
cmd += ['--no-edit']

try:
check_call(cmd)
except CalledProcessError:
raise Failure('Could not commit staged changes.')
if commit_user_merge(merge_state, edit_log_msg=edit_log_msg):
commit = get_commit_sha1('HEAD')

require_clean_work_tree('proceed')

merge_frontier = MergeFrontier.map_known_frontier(merge_state)

# This might throw ManualMergeUnusableError:
(i1, i2) = merge_state.incorporate_manual_merge(commit)

Expand Down

0 comments on commit 7334f53

Please sign in to comment.