首页 > 解决方案 > Git合并导致不合理的冲突

问题描述

我基本上在几乎所有从 current_iteration 合并到我的分支中的文件上都遇到了冲突。这令人发狂,让许多人惊讶地看着和挠头。

我目前正在使用带有 git version 的 mac 工作2.18.0。我的同行都在 Windows git 版本上工作2.12.2.windows.2

MacBook 配置

macbook-pro:~ chris$ git config -l
credential.helper=osxkeychain
user.email=chris.hinshaw@foo.com
user.name=Chris Hinshaw
user.autocrlf=false

视窗配置

C:> git config -l
core.symlinks=false
core.autocrlf=true
core.fscache=true
color.diff=auto
color.status=auto
color.branch=auto
color.interactive=true
help.format=html
rebase.autosquash=true
http.sslcainfo=C:/Users/…
diff.astextplain.textconv=astextplain
filter.lfs.clean=git-lfs clean -- %f
filter.lfs.smudge=git-lfs smudge -- %f
filter.lfs.required=true
filter.lfs.process=git-lfs filter-process
credential.helper=manager
merge.tool=kdiff3
mergetool.kdiff3.cmd="C:\\Program Files\\KDiff3\\kdiff3" $BASE $LOCAL $REMOTE -o $MERGED
difftool.kdiff3.path="C:\\Program Files\\KDiff3\\kdiff3"
difftool.kdiff3.keepbackup=false
difftool.kdiff3.trustexitcode=false
alias.lg=!git lg1
alias.lg1=!git lg1-specific --all
alias.lg2=!git lg2-specific --all
alias.lg3=!git lg3-specific --all
alias.lg1-specific=log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)'
alias.lg2-specific=log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
alias.lg3-specific=log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset) %C(bold cyan)(committed: %cD)%C(reset) %C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset)%n''          %C(dim white)- %an <%ae> %C(reset) %C(dim white)(committer: %cn <%ce>)%C(reset)'
core.whitespace=cr-at-eol
core.autocrlf=true
credential.helper=manager
http.emptyauth=true 

当前迭代分支更改

在这里,我正在检查 current_iteration 并确保它完全是最新的。我表明差异是从类中删除组件注释的单行更改。

macbook-pro:devel chris$ git checkout current_iteration
macbook-pro:devel chris$ git pull origin 

commit 81dea298657c882a5c32ee3f30b459643035024e
Author: Them
Date:   Wed Aug 1 11:12:12 2018 -0500


commit 0676ffd81a83cfbdf18a3b1fc93f31439d7e3a00
Author: Me
Date:   Mon Jul 30 18:01:53 2018 -0500


commit 0d8f7a2dfe35d43ef03af339694479189ff86b79
Author: Me
Date:   Wed Jul 25 15:04:44 2018 -0500

将应用于我当前分支的差异

git diff 81dea~1 ./somepath/OjaiLifecycleListener.java
./somepath/OjaiLifecycleListener.javaindex 08c3e66c..f0864c52 100644
--- a/somepath/OjaiLifecycleListener.java
+++ b/somepath/OjaiLifecycleListener.java
@@ -14,7 +14,7 @@ import java.util.Collection;
 import java.util.Map;
 import java.util.function.Supplier;

-@Component
+
 public class OjaiLifecycleListener implements SmartLifecycle {

     private static final Logger logger = LoggerFactory.getLogger(OjaiLifecycleListener.class);

我的分行

macbook-pro:devel chris$ git checkout feature/mapr-autoinit
macbook-pro:devel chris$ git pull origin 

git diff feature/feature/mapr-autoinit..current_iteration  ./somepath/OjaiLifecycleListener.java diff --git a/somepath/OjaiLifecycleListener.java index 5d29f3eb..f0864c52 100644
--- a/somepath/OjaiLifecycleListener.java
+++ b/somepath/OjaiLifecycleListener.java @@ -14,7 +14,7 @@ import java.util.Collection;  import java.util.Map;  import java.util.function.Supplier;  
-@Component
+  public class OjaiLifecycleListener implements SmartLifecycle {

     private static final Logger logger = LoggerFactory.getLogger(OjaiLifecycleListener.class); @@ -52,23 +52,25 @@ public class OjaiLifecycleListener implements SmartLifecycle {
     }

     private void createIfMissing(Class<? extends OjaiRepository> cls) throws IOException {
-        logger.debug("Configuring reopsitory {}", cls.getName());
+        logger.info("configuring reopsitory {}", cls.getName());
         // final Table table = cls.getAnnotation(Table.class); // No worky cuz of cglib
         final Table table = AnnotationUtils.findAnnotation(cls, Table.class);
         if (table != null) {
-            logger.debug("Found table annotation for class {} with table id {}", cls.getSimpleName(), table.name());
+            logger.info("Found table annotation for class {} with table id {}", cls.getSimpleName(), table.name());
             final String tablePath = tableAdmin.getEnvironmentQualifiedPath(table.name()).toString();
             boolean exists = tableAdmin.tableExists(tablePath);
-            logger.info("Repository => {},  Path => {}, Exists => {} ", cls.getSimpleName(), tablePath, exists);
+            logger.info("Table for class {} with table path {} exists : {} ", cls.getSimpleName(), tablePath, exists);
+
             if (! exists) {
                 logger.info("Creating table for class {} with table path {}", cls.getSimpleName(), tablePath);
                 tableAdmin.createTable(tablePath, defaultTablePerms, defaultCFPerms);
             }
         } else {
-            logger.warn("Repository {} is missing @Table annotation", cls);
+            logger.warn("Found table without table annotation {} ", cls);
         }
     }  
+
     @Override
     public boolean isAutoStartup() {
         return true;

对我来说,上面的补丁看起来完全合理,应该可以正常应用。没有重复的公共行被更改。

合并

git merge -s recursive -Xignore-space-at-eol -Xignore-space-change current_iteration

这会导致大量的冲突。但是我们可以查看单个文件

<<<<<<< HEAD
@Component
public class OjaiLifecycleListener implements SmartLifecycle {
=======
>>>>>>> current_iteration

public class OjaiLifecycleListener implements SmartLifecycle {

<<<<<<< HEAD
    private final Supplier<Collection<Class<? extends OjaiRepository>>> ojaiRepositorySupplier;
    private final OjaiTableAdmin tableAdmin;
    private final Map<String, String> defaultTablePerms;
    private final Map<String, String> defaultCFPerms;

    private volatile boolean isStarted = false;

=======
    private static final Logger logger = LoggerFactory.getLogger(OjaiLifecycleListener.class);

    private final Supplier<Collection<Class<? extends OjaiRepository>>> ojaiRepositorySupplier;
    private final OjaiTableAdmin tableAdmin;
    private final Map<String, String> defaultTablePerms;
    private final Map<String, String> defaultCFPerms;

    private volatile boolean isStarted = false;

>>>>>>> current_iteration
    @Inject
    public OjaiLifecycleListener(Supplier<Collection<Class<? extends OjaiRepository>>> ojaiRepositorySupplier, OjaiTableAdmin tableAdmin,
                                 @Named("mapr.mapr.ojai.table.perms") Map<String, String> defaultTablePerms,
                                 @Named("mapr.mapr.ojai.cf.perms") Map<String, String> defaultCFPerms) {
        this.ojaiRepositorySupplier = ojaiRepositorySupplier;
        this.tableAdmin = tableAdmin;
        this.defaultTablePerms = defaultTablePerms;
        this.defaultCFPerms = defaultCFPerms;
    }

    @Override
    public void start() {
        logger.info("Configuring Ojai Tables");
        if (isStarted) return;

        ojaiRepositorySupplier.get().forEach(c -> {
            try {
                createIfMissing(c);
            } catch (IOException e) {
               throw new RuntimeException("Failed to create ojai table: " +  c.getName(), e);
            }
        });
        isStarted = true;
    }

    private void createIfMissing(Class<? extends OjaiRepository> cls) throws IOException {
<<<<<<< HEAD
        logger.debug("Configuring reopsitory {}", cls.getName());
        // final Table table = cls.getAnnotation(Table.class); // No worky cuz of cglib
        final Table table = AnnotationUtils.findAnnotation(cls, Table.class);
        if (table != null) {
            logger.debug("Found table annotation for class {} with table id {}", cls.getSimpleName(), table.name());
            final String tablePath = tableAdmin.getEnvironmentQualifiedPath(table.name()).toString();
            boolean exists = tableAdmin.tableExists(tablePath);
            logger.info("Repository => {},  Path => {}, Exists => {} ", cls.getSimpleName(), tablePath, exists);
=======
        logger.info("configuring reopsitory {}", cls.getName());
        // final Table table = cls.getAnnotation(Table.class); // No worky cuz of cglib
        final Table table = AnnotationUtils.findAnnotation(cls, Table.class);
        if (table != null) {
            logger.info("Found table annotation for class {} with table id {}", cls.getSimpleName(), table.name());
            final String tablePath = tableAdmin.getEnvironmentQualifiedPath(table.name()).toString();
            boolean exists = tableAdmin.tableExists(tablePath);
            logger.info("Table for class {} with table path {} exists : {} ", cls.getSimpleName(), tablePath, exists);

>>>>>>> current_iteration
            if (! exists) {
                logger.info("Creating table for class {} with table path {}", cls.getSimpleName(), tablePath);
                tableAdmin.createTable(tablePath, defaultTablePerms, defaultCFPerms);
            }
        } else {
<<<<<<< HEAD
            logger.warn("Repository {} is missing @Table annotation", cls);
=======
            logger.warn("Found table without table annotation {} ", cls);
>>>>>>> current_iteration
        }
    }

我查看了空格问题,并尝试了所有可能的忽略空格组合。我尝试使用他们的配置选项和 kdiff 合并选项。我曾尝试使用 dos2unix 工具重新格式化文件。我唯一能想到的是,这是 autosquash 选项的一个问题,它并不总是在我的本地分支上正确地重放更改。我们正在使用 TFS btw,它是一个 Windows git 存储库,如果这有什么不同的话。

更新 1

抱歉,我正在重命名分支以使其更符合 git 标准。只有两个分支 current_iteration 和 features/mapr-autoinit。

import javax.inject.Named;
import javax.persistence.Table;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.function.Supplier;

<<<<<<< HEAD
@Component
public class OjaiLifecycleListener implements SmartLifecycle {
||||||| merged common ancestors
@Service
public class OjaiLifecycleListener implements Lifecycle {
=======
>>>>>>> current_iteration

public class OjaiLifecycleListener implements SmartLifecycle {

<<<<<<< HEAD
    private final Supplier<Collection<Class<? extends OjaiRepository>>> ojaiRepositorySupplier;
    private final OjaiTableAdmin tableAdmin;
    private final Map<String, String> defaultTablePerms;
    private final Map<String, String> defaultCFPerms;
||||||| merged common ancestors
=======
    private static final Logger logger = LoggerFactory.getLogger(OjaiLifecycleListener.class);
>>>>>>> current_iteration

<<<<<<< HEAD
    private volatile boolean isStarted = false;
||||||| merged common ancestors
    private final ApplicationContext context;
=======
    private final Supplier<Collection<Class<? extends OjaiRepository>>> ojaiRepositorySupplier;
    private final OjaiTableAdmin tableAdmin;
    private final Map<String, String> defaultTablePerms;
    private final Map<String, String> defaultCFPerms;
>>>>>>> current_iteration

<<<<<<< HEAD
    @Inject
    public OjaiLifecycleListener(Supplier<Collection<Class<? extends OjaiRepository>>> ojaiRepositorySupplier, OjaiTableAdmin tableAdmin,
                                 @Named("mapr.mapr.ojai.table.perms") Map<String, String> defaultTablePerms,
                                 @Named("mapr.mapr.ojai.cf.perms") Map<String, String> defaultCFPerms) {
        this.ojaiRepositorySupplier = ojaiRepositorySupplier;
        this.tableAdmin = tableAdmin;
        this.defaultTablePerms = defaultTablePerms;
        this.defaultCFPerms = defaultCFPerms;
||||||| merged common ancestors
    public OjaiLifecycleListener(ApplicationContext context) {

        this.context = context;
=======
    private volatile boolean isStarted = false;

    @Inject
    public OjaiLifecycleListener(Supplier<Collection<Class<? extends OjaiRepository>>> ojaiRepositorySupplier, OjaiTableAdmin tableAdmin,
                                 @Named("mapr.mapr.ojai.table.perms") Map<String, String> defaultTablePerms,
                                 @Named("mapr.mapr.ojai.cf.perms") Map<String, String> defaultCFPerms) {
        this.ojaiRepositorySupplier = ojaiRepositorySupplier;
        this.tableAdmin = tableAdmin;
        this.defaultTablePerms = defaultTablePerms;
        this.defaultCFPerms = defaultCFPerms;
>>>>>>> current_iteration
    }

    @Override
    public void start() {
<<<<<<< HEAD
        logger.info("Configuring Ojai Tables");
        if (isStarted) return;
||||||| merged common ancestors
        logger.info("starting ojai listener");
        final Map<String, OjaiRepository> repositories = context.getBeansOfType(OjaiRepository.class);
        logger.info("found {} ojai repositories", repositories.size());
        repositories.forEach(OjaiLifecycleListener::createIfMissing);
=======
        logger.info("Configuring Ojai Tables");
        if (isStarted) return;

        ojaiRepositorySupplier.get().forEach(c -> {
            try {
                createIfMissing(c);
            } catch (IOException e) {
               throw new RuntimeException("Failed to create ojai table: " +  c.getName(), e);
            }
        });
        isStarted = true;
    }
>>>>>>> current_iteration

<<<<<<< HEAD
        ojaiRepositorySupplier.get().forEach(c -> {
            try {
                createIfMissing(c);
            } catch (IOException e) {
               throw new RuntimeException("Failed to create ojai table: " +  c.getName(), e);
            }
        });
        isStarted = true;
    }

    private void createIfMissing(Class<? extends OjaiRepository> cls) throws IOException {
        logger.debug("Configuring reopsitory {}", cls.getName());
        // final Table table = cls.getAnnotation(Table.class); // No worky cuz of cglib
        final Table table = AnnotationUtils.findAnnotation(cls, Table.class);
        if (table != null) {
            logger.debug("Found table annotation for class {} with table id {}", cls.getSimpleName(), table.name());
            final String tablePath = tableAdmin.getEnvironmentQualifiedPath(table.name()).toString();
            boolean exists = tableAdmin.tableExists(tablePath);
            logger.info("Repository => {},  Path => {}, Exists => {} ", cls.getSimpleName(), tablePath, exists);
            if (! exists) {
                logger.info("Creating table for class {} with table path {}", cls.getSimpleName(), tablePath);
                tableAdmin.createTable(tablePath, defaultTablePerms, defaultCFPerms);
            }
        } else {
            logger.warn("Repository {} is missing @Table annotation", cls);
        }
||||||| merged common ancestors
=======
    private void createIfMissing(Class<? extends OjaiRepository> cls) throws IOException {
        logger.info("configuring reopsitory {}", cls.getName());
        // final Table table = cls.getAnnotation(Table.class); // No worky cuz of cglib
        final Table table = AnnotationUtils.findAnnotation(cls, Table.class);
        if (table != null) {
            logger.info("Found table annotation for class {} with table id {}", cls.getSimpleName(), table.name());
            final String tablePath = tableAdmin.getEnvironmentQualifiedPath(table.name()).toString();
            boolean exists = tableAdmin.tableExists(tablePath);
            logger.info("Table for class {} with table path {} exists : {} ", cls.getSimpleName(), tablePath, exists);

            if (! exists) {
                logger.info("Creating table for class {} with table path {}", cls.getSimpleName(), tablePath);
                tableAdmin.createTable(tablePath, defaultTablePerms, defaultCFPerms);
            }
        } else {
            logger.warn("Found table without table annotation {} ", cls);
        }
>>>>>>> current_iteration
    }


    @Override
    public boolean isAutoStartup() {
        return true;
    }

    @Override
    public void stop(Runnable callback) {
        stop();
        callback.run();
    }

更新 2

@Torek 现在正在帮助我理解这一点。他指出了一个我对 git merge base 不熟悉的命令

macbook-pro:fido-service chris$ git merge-base current_iteration feature/mapr-autoinit
295c022c9f3d6da92e87f2addec1bbd7be30c5d7

根据输出,这将解释冲突。

@@ -1,58 +1,97 @@
 package com.apc.its.services.fido.persistence.mapr;

-import com.mapr.fs.tables.MapRAdmin;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.Lifecycle;
-import org.springframework.stereotype.Service;
+import org.springframework.context.SmartLifecycle;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.stereotype.Component;

+import javax.inject.Inject;
+import javax.inject.Named;
 import javax.persistence.Table;
+import java.io.IOException;
+import java.util.Collection;
 import java.util.Map;
+import java.util.function.Supplier;

-@Service
-public class OjaiLifecycleListener implements Lifecycle {
+@Component
+public class OjaiLifecycleListener implements SmartLifecycle {

     private static final Logger logger = LoggerFactory.getLogger(OjaiLifecycleListener.class);

+    private final Supplier<Collection<Class<? extends OjaiRepository>>> ojaiRepositorySupplier;
+    private final OjaiTableAdmin tableAdmin;
+    private final Map<String, String> defaultTablePerms;
+    private final Map<String, String> defaultCFPerms;

-    private final ApplicationContext context;
+    private volatile boolean isStarted = false;

-    public OjaiLifecycleListener(ApplicationContext context) {
-
-        this.context = context;
+    @Inject
+    public OjaiLifecycleListener(Supplier<Collection<Class<? extends OjaiRepository>>> ojaiRepositorySupplier, OjaiTableAdmin tableAdmin,
+                                 @Named("mapr.mapr.ojai.table.perms") Map<String, String> defaultTablePerms,
:

更新 3

我想我可能对导致此问题的原因有所了解。我经常遇到冲突的原因是我的分支正在跟踪另外两个分支。一个是 master,另一个是 master 的一个分支,即 current_iteration。看来我的分支正在破译最好的

git remote show origin
... 

  Local branches configured for 'git pull':
    current_iteration     merges with remote current_iteration
    feature/mapr-autoinit merges with remote feature/mapr-autoinit
    master                merges with remote master

这导致合并必须找到一个共同的祖先,这将是最后一次将 current_iteration 合并到 master 中(显然是前一段时间)。

这表明 git merge 正在尝试从几个月前的修订版 1b813c6 合并。这将解释为什么要重新应用更改等。

git checkout feature/mapr-autoinit
Switched to branch 'feature/mapr-autoinit'
Your branch is up to date with 'origin/feature/mapr-autoinit'.
macbook-pro:fido-service rkh477$ git show-branch --merge-base
1b813c6c48f1c11d65862331f6667258d536adf9
macbook-pro:fido-service rkh477$ git log 1b813c6c48f1c11d65862331f6667258d536adf9
commit 1b813c6c48f1c11d65862331f6667258d536adf9
Author: Somebody
Date:   Wed Feb 28 16:30:02 2018 -0600

我假设我需要用 master 重新设置 current_iteration 来解决这个问题?任何帮助,将不胜感激。

标签: git

解决方案


推荐阅读