如何用脚本自动解决Git冲突?

wen 实用脚本 3

本文目录导读:

如何用脚本自动解决Git冲突?

  1. 使用Git内置的合并策略(最简单)
  2. 自动识别并解决特定文件的冲突
  3. 通用的自动冲突解决脚本
  4. 智能冲突解决脚本(准守特定规则)
  5. 特定场景的自动化脚本示例
  6. 使用Git hooks自动处理
  7. 全自动合并脚本
  8. ⚠️ 重要警告
  9. 使用建议

用脚本自动解决Git冲突是一个有风险的操作,因为冲突通常需要人工判断上下文,不过在某些特定场景下(比如自动生成的代码、配置文件、或确定性的合并策略),可以通过脚本来自动化处理。

以下提供几种方法,从简单到复杂:

使用Git内置的合并策略(最简单)

#!/bin/bash
# 自动使用"ours"或"theirs"策略解决冲突
# 策略1: 总是使用当前分支的版本
git merge --strategy-option ours branch-name
# 策略2: 总是使用被合并分支的版本
git merge --strategy-option theirs branch-name
# 策略3: 如果在rebase中
git rebase -X theirs branch-name

自动识别并解决特定文件的冲突

#!/bin/bash
# 只对特定模式的文件自动解决冲突
# 对package-lock.json使用theirs策略
git checkout --theirs package-lock.json
git add package-lock.json
# 对配置文件使用ours策略
git checkout --ours config.yml
git add config.yml

通用的自动冲突解决脚本

#!/bin/bash
# auto_resolve_conflict.sh
echo "开始处理Git冲突..."
# 获取所有冲突文件
conflict_files=$(git diff --name-only --diff-filter=U)
if [ -z "$conflict_files" ]; then
    echo "没有发现冲突文件"
    exit 0
fi
for file in $conflict_files; do
    echo "处理: $file"
    # 方案A: 使用theirs版本(接受来自他们的更改)
    git checkout --theirs "$file"
    # 或者方案B: 使用ours版本(保留自己的更改)
    # git checkout --ours "$file"
    # 或者方案C: 使用合并工具自动合并
    # git mergetool --tool=vimdiff "$file"
    git add "$file"
done
echo "冲突解决完成"
git commit -m "自动解决冲突"

智能冲突解决脚本(准守特定规则)

#!/usr/bin/env python3
"""
智能冲突解析器 - 根据文件类型和冲突内容自动解决
"""
import subprocess
import re
import os
def get_conflict_files():
    """获取冲突文件列表"""
    result = subprocess.run(
        ['git', 'diff', '--name-only', '--diff-filter=U'],
        capture_output=True, text=True
    )
    return result.stdout.strip().split('\n') if result.stdout.strip() else []
def resolve_file(file_path):
    """根据文件类型采取不同策略"""
    ext = os.path.splitext(file_path)[1].lower()
    # 对于自动生成的文件,使用theirs
    if file_path in ['package-lock.json', 'yarn.lock', 'Gemfile.lock']:
        print(f"  → 自动生成文件,接受theirs: {file_path}")
        subprocess.run(['git', 'checkout', '--theirs', file_path])
        return True
    # 对于代码文件,尝试保留双方更改
    if ext in ['.py', '.js', '.java', '.go']:
        print(f"  → 代码文件,尝试自动合并: {file_path}")
        return smart_merge_code(file_path)
    # 对于配置文件,使用ours
    if file_path in ['config.yml', '.env', 'docker-compose.yml']:
        print(f"  → 配置文件,保留ours: {file_path}")
        subprocess.run(['git', 'checkout', '--ours', file_path])
        return True
    return False
def smart_merge_code(file_path):
    """尝试智能合并代码文件"""
    try:
        with open(file_path, 'r') as f:
            content = f.read()
        # 解析冲突标记
        conflict_pattern = r'<<<<<<< HEAD\n(.*?)\n=======\n(.*?)\n>>>>>>> [^\n]+'
        conflicts = re.findall(conflict_pattern, content, re.DOTALL)
        if not conflicts:
            return False
        new_content = content
        for ours, theirs in conflicts:
            # 简单策略:如果变更很小则使用theirs
            if len(ours.split('\n')) <= 3 and len(theirs.split('\n')) <= 3:
                new_content = new_content.replace(
                    f'<<<<<<< HEAD\n{ours}\n=======\n{theirs}\n>>>>>>>',
                    theirs.strip()
                )
            else:
                # 复杂变更,标记为手动处理
                print(f"  ⚠️  {file_path} 包含复杂冲突,需要手动处理")
                return False
        # 检查是否还有未解决的冲突
        if re.search(r'<<<<<<<|=======|>>>>>>>', new_content):
            print(f"  ⚠️  {file_path} 仍有未处理冲突")
            return False
        with open(file_path, 'w') as f:
            f.write(new_content)
        return True
    except Exception as e:
        print(f"  ❌ 处理 {file_path} 时出错: {e}")
        return False
def main():
    """主函数"""
    print("🔍 扫描冲突文件...")
    conflict_files = get_conflict_files()
    if not conflict_files:
        print("✅ 没有冲突文件")
        return
    print(f"发现 {len(conflict_files)} 个冲突文件")
    resolved = 0
    failed = []
    for file_path in conflict_files:
        if file_path:  # 确保文件路径不为空
            if resolve_file(file_path):
                subprocess.run(['git', 'add', file_path])
                resolved += 1
            else:
                failed.append(file_path)
    print(f"\n📊 统计:")
    print(f"  - 自动解决: {resolved}")
    print(f"  - 需要手动处理: {len(failed)}")
    if failed:
        print("\n⚠️  以下文件需要手动处理:")
        for f in failed:
            print(f"  - {f}")
    if resolved > 0:
        print("\n💡 运行 git commit 来完成合并")
if __name__ == "__main__":
    main()

特定场景的自动化脚本示例

1 自动解决package.json冲突

#!/bin/bash
# 针对package.json的智能合并
# 保留两个版本的依赖
resolve_package_json() {
    local file="package.json"
    if [ ! -f "$file" ]; then
        return
    fi
    # 使用git的合并策略
    git checkout --theirs "$file"
    git add "$file"
}
# 在合并后运行
resolve_package_json

2 CI/CD环境中的自动冲突处理

# .gitlab-ci.yml 或 GitHub Actions
stages:
  - merge
auto_merge:
  stage: merge
  script:
    - git config user.email "bot@example.com"
    - git config user.name "Auto Merge Bot"
    - git checkout main
    - git merge --no-edit develop || true
    - |
      # 自动解决已知类型的冲突
      for file in $(git diff --name-only --diff-filter=U); do
        case "$file" in
          *.lock | package-lock.json | yarn.lock)
            git checkout --theirs "$file"
            git add "$file"
            ;;
          *.md | *.txt)
            git checkout --ours "$file"
            git add "$file"
            ;;
          *)
            echo "需要手动处理: $file"
            ;;
        esac
      done
    - git commit -m "自动合并开发分支" || true
    - git push

使用Git hooks自动处理

#!/bin/bash
# post-merge hook - 自动解决特定文件的冲突
echo "检查合并后的冲突..."
if [ -f "package-lock.json" ]; then
    echo "自动更新package-lock.json"
    npm install 2>/dev/null || true
fi
# 检查是否有未解决的冲突
if git diff --check 2>/dev/null | grep -q "conflict"; then
    echo "⚠️  仍有未解决的冲突"
fi

全自动合并脚本

#!/bin/bash
# git_auto_merge.sh - 完全自动化合并
set -e
# 配置
SOURCE_BRANCH=${1:-"develop"}
TARGET_BRANCH=${2:-"main"}
AUTO_RESOLVE_FILES=(
    "package-lock.json"
    "yarn.lock"
    "pnpm-lock.yaml"
    ".gitignore"
)
echo "🔄 自动合并 $SOURCE_BRANCH → $TARGET_BRANCH"
# 切换到目标分支并拉取最新代码
git checkout "$TARGET_BRANCH"
git pull origin "$TARGET_BRANCH"
# 合并源分支
echo "📥 合并 $SOURCE_BRANCH..."
git merge "$SOURCE_BRANCH" --no-edit || true
# 自动解决特定文件的冲突
echo "🔧 自动解决已知冲突文件..."
for file in "${AUTO_RESOLVE_FILES[@]}"; do
    if [ -f "$file" ]; then
        echo "  → 解决: $file"
        git checkout --theirs "$file" 2>/dev/null || git checkout --ours "$file" 2>/dev/null || true
        git add "$file" 2>/dev/null || true
    fi
done
# 提交合并
if git diff --cached --quiet; then
    echo "✅ 没有需要提交的更改"
else
    git commit -m "chore: 自动合并 $SOURCE_BRANCH 到 $TARGET_BRANCH"
    echo "✅ 合并完成"
fi

⚠️ 重要警告

  1. 自动解决冲突有风险:可能会引入错误或丢失重要更改
  2. 只适用于特定场景
    • 自动生成的文件(锁文件、编译产物)
    • 配置文件(格式化或注释差异)
    • 确定性的代码变更
  3. 建议的实践
    • 先在小范围测试
    • 保留备份或使用reflog
    • 添加详细的日志记录
    • 对关键文件不自动处理

使用建议

  1. 始终先检查哪些文件有冲突
  2. 对不同类型的文件采用不同的策略
  3. 添加日志和回滚机制
  4. 在CI/CD中使用时,对于无法自动解决的情况要报警

自动化是工具,不是替代品,对于复杂的业务逻辑冲突,人工检查永远是必要的。

抱歉,评论功能暂时关闭!