Git合并导致不合理的冲突

Chr*_*haw 5 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
Run Code Online (Sandbox Code Playgroud)

视窗配置

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 
Run Code Online (Sandbox Code Playgroud)

当前迭代分支更改

在这里,我正在检查 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
Run Code Online (Sandbox Code Playgroud)

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

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);
Run Code Online (Sandbox Code Playgroud)

我的分行

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;
Run Code Online (Sandbox Code Playgroud)

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

合并

git merge -s recursive -Xignore-space-at-eol -Xignore-space-change current_iteration
Run Code Online (Sandbox Code Playgroud)

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

<<<<<<< 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
        }
    }
Run Code Online (Sandbox Code Playgroud)

我查看了空格问题,并尝试了忽略空格的所有可能组合。我曾尝试将他们的配置选项与 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();
    }
Run Code Online (Sandbox Code Playgroud)

更新 2

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

macbook-pro:fido-service chris$ git merge-base current_iteration feature/mapr-autoinit
295c022c9f3d6da92e87f2addec1bbd7be30c5d7
Run Code Online (Sandbox Code Playgroud)

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

@@ -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,
:
Run Code Online (Sandbox Code Playgroud)

更新 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
Run Code Online (Sandbox Code Playgroud)

这导致合并必须找到一个共同的祖先,这将是 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
Run Code Online (Sandbox Code Playgroud)

我假设我需要使用 master 重新设置 c