mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-22 10:51:02 +01:00
feature: merge conflict detection and resolution (#6)
- pulls now correctly identify merge conflicts and enter a merge state - user resolves each file individually - commit resolve merge state - allows users to keep custom changes and pull in updates - improve commit message component - seperated commit / add functionality
This commit is contained in:
96
backend/app/git/operations/merge.py
Normal file
96
backend/app/git/operations/merge.py
Normal file
@@ -0,0 +1,96 @@
|
||||
# git/operations/merge.py
|
||||
import git
|
||||
import logging
|
||||
import os
|
||||
from typing import Dict, Any, Tuple
|
||||
from .commit import commit_changes
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def finalize_merge(repo) -> Dict[str, Any]:
|
||||
"""
|
||||
Finalize a merge by committing all staged files after conflict resolution.
|
||||
"""
|
||||
try:
|
||||
if not os.path.exists(os.path.join(repo.git_dir, 'MERGE_HEAD')):
|
||||
return {
|
||||
'success': False,
|
||||
'error': 'Not currently in a merge state'
|
||||
}
|
||||
|
||||
# Get unmerged files
|
||||
unmerged_files = []
|
||||
status = repo.git.status('--porcelain', '-z').split('\0')
|
||||
for item in status:
|
||||
if item and len(item) >= 4:
|
||||
x, y, file_path = item[0], item[1], item[3:]
|
||||
if 'U' in (x, y):
|
||||
unmerged_files.append(file_path)
|
||||
|
||||
# Force update the index for unmerged files
|
||||
for file_path in unmerged_files:
|
||||
# Remove from index first
|
||||
try:
|
||||
repo.git.execute(['git', 'reset', '--', file_path])
|
||||
except git.GitCommandError:
|
||||
pass
|
||||
|
||||
# Add back to index
|
||||
try:
|
||||
repo.git.execute(['git', 'add', '--', file_path])
|
||||
except git.GitCommandError as e:
|
||||
logger.error(f"Error adding file {file_path}: {str(e)}")
|
||||
return {
|
||||
'success': False,
|
||||
'error': f"Failed to stage resolved file {file_path}"
|
||||
}
|
||||
|
||||
# Create commit message
|
||||
commit_message = "Merge complete: resolved conflicts"
|
||||
|
||||
# Commit
|
||||
try:
|
||||
repo.git.commit('-m', commit_message)
|
||||
logger.info("Successfully finalized merge")
|
||||
return {'success': True, 'message': 'Merge completed successfully'}
|
||||
except git.GitCommandError as e:
|
||||
logger.error(f"Git command error during commit: {str(e)}")
|
||||
return {
|
||||
'success': False,
|
||||
'error': f"Failed to commit merge: {str(e)}"
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to finalize merge: {str(e)}")
|
||||
return {
|
||||
'success': False,
|
||||
'error': f"Failed to finalize merge: {str(e)}"
|
||||
}
|
||||
|
||||
|
||||
def abort_merge(repo_path):
|
||||
try:
|
||||
repo = git.Repo(repo_path)
|
||||
|
||||
# Try aborting the merge using git merge --abort
|
||||
try:
|
||||
repo.git.execute(['git', 'merge', '--abort'])
|
||||
return True, "Merge aborted successfully"
|
||||
except git.GitCommandError as e:
|
||||
logger.warning(
|
||||
"Error aborting merge with 'git merge --abort'. Trying 'git reset --hard'."
|
||||
)
|
||||
|
||||
# If git merge --abort fails, try resetting to the previous commit using git reset --hard
|
||||
try:
|
||||
repo.git.execute(['git', 'reset', '--hard'])
|
||||
return True, "Merge aborted and repository reset to the previous commit"
|
||||
except git.GitCommandError as e:
|
||||
logger.exception(
|
||||
"Error resetting repository with 'git reset --hard'")
|
||||
return False, str(e)
|
||||
|
||||
except Exception as e:
|
||||
logger.exception("Unexpected error aborting merge")
|
||||
return False, str(e)
|
||||
Reference in New Issue
Block a user