【问题标题】:prevent file with merge conflicts from getting committed in git防止合并冲突的文件在 git 中提交
【发布时间】:2014-08-04 12:32:23
【问题描述】:

有什么方法可以防止合并冲突的文件在 git 中提交?没有人会故意提交有冲突的文件。但是有没有办法防止文件在 git 中被提交?

git 是否在任何地方都有任何设置或可配置值,它可以通过查找<<<<<<<=======>>>>>>> 符号来阻止文件?

【问题讨论】:

  • git rev-parse -q --verify HEAD && sed -n '/^<<<<<<< /Q1' $(git diff --diff-filter=M --name-only HEAD $(git write-tree)) || { echo "It looks like rain."; exit 1; } 添加到.git/hooks/pre-commit。这是键盘到编辑框,但它应该基本正确。
  • 你能告诉我上述条件的作用吗,因为它对我不起作用。我在预提交文件中添加了条件,并尝试在 git bash 中添加一个新文件,文件被添加,然后提交它也成功了。如果我错过了什么,请告诉我。
  • git 插件是否提供此限制?
  • @jthill 预提交按预期工作,但我在预接收中使用了相同的条件,但失败了。我在 Eclipse 中使用 egit 提交文件,但我在服务器中有预接收,但在推送冲突文件时,预接收挂钩被调用,但仍继续推送。我希望文件不会被推送。
  • @jthill:你会把它作为答案发布吗?在这个页面上发生的很多人将直接使用 git,而不是 Eclipse。 VonC 的答案对我不起作用,除非我找到一些 Perl 依赖项。我也不需要额外的 console.log 和其他检查。

标签: git github merge-conflict-resolution


【解决方案1】:

客户端解决方案使用git pre-commit hooks,它允许您在提交时执行特定命令(合并是一种提交),如果它们失败,则在解决之前无法合并。

pre-commit 是一种管理 git pre-commit 钩子的简单方法和标准化方法。

在存储库的根目录中创建一个名为 .pre-commit-config.yaml 的文件 与以下

# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.0.1
    hooks:
    -   id: check-merge-conflict
安装预提交

(首选方法是)使用 pipx 或在虚拟环境之外执行此操作,因为它是 CLI 应用程序

python3 -m pip install pre-commit 
安装挂钩
pre-commit install # you only do this once per "git clone"

下次合并时,如果检测到冲突标记,它会警告您并阻止您继续

$ git merge --continue
[INFO] Checking merge-conflict files only.
Check for merge conflicts................................................Failed
- hook id: check-merge-conflict
- exit code: 1

Merge conflict string "<<<<<<< " found in README.rst:1
Merge conflict string "=======
" found in README.rst:3
Merge conflict string ">>>>>>> " found in README.rst:5

【讨论】:

    【解决方案2】:

    一种使用预提交挂钩的简单方法,改编自 here,但经过改进后更加谨慎和彻底:

    #!/bin/sh
    
    changed=$(git diff --cached --name-only)
    
    if [[ -z "$changed" ]]; then
        exit 0
    fi
    
    echo $changed | xargs egrep '^[><=]{7}( |$)' -H -I --line-number
    
    # If the egrep command has any hits - echo a warning and exit with non-zero status.
    if [ $? == 0 ]; then
        echo "WARNING: You have merge markers in the above files. Fix them before committing."
        echo "         If these markers are intentional, you can force the commit with the --no-verify argument."
        exit 1
    fi
    

    别忘了让钩子可执行 (chmod u+x pre-commit)!

    我已经把它放在了 github 上:https://github.com/patrickvacek/git-reject-binaries-and-large-files/blob/master/pre-commit

    【讨论】:

      【解决方案3】:

      我为冲突标记字符串添加了一个单元测试来遍历解决方案目录中的所有文件

      [TestClass]
      public class SolutionValidationTests
      {
          [TestMethod]
          public void CheckForMergeConflicts()
          {
              var solutionValidationScripts = new SolutionValidationScripts();
              var mergeConflictCheckOkay = solutionValidationScripts.CheckForGitMergeConflict();
              Assert.IsTrue(mergeConflictCheckOkay);
          }
      }
      

      SolutionValidationScripts 单独定义如下:

      public class SolutionValidationScripts
      {
          public bool CheckForGitMergeConflict()
          {
              var failCount = 0;
              System.Diagnostics.Debug.WriteLine($"{DateTime.Now.ToString(@"dd-MMM-yyyy HH:mm:ss")}: Starting");
      
              var currentDirectory = System.IO.Directory.GetCurrentDirectory();
              var sourceFolder = "";
      
              // Change to suit the build location of your solution
              sourceFolder = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(System.IO.Directory.GetCurrentDirectory())));
              // break up the string so this file doesn't get flagged in the test
              string searchWord = "<<<<<<< " + "HEAD";
      
              List<string> allFiles = new List<string>();
              AddFileNamesToList(sourceFolder, allFiles);
              for (int i = 0; i < allFiles.Count; i++)
              {
                  // 35 sec
                  var fileName = allFiles[i];
                  string contents = File.ReadAllText(fileName);
                  if (contents.Contains(searchWord))
                  {
                      // For faster result.. no need to continue once a problem is found
                      // throwing an exception here actually works better than an early return to help resolve the issue
                      throw new Exception(fileName);
                  }
              }
              return (failCount == 0);
          }
      
          private void AddFileNamesToList(string sourceDir, List<string> allFiles)
          {
              string[] fileEntries = Directory.GetFiles(sourceDir);
              foreach (string fileName in fileEntries)
              {
                  allFiles.Add(fileName);
              }
      
              //Recursion    
              string[] subdirectoryEntries = Directory.GetDirectories(sourceDir);
              foreach (string item in subdirectoryEntries)
              {
                  // Avoid "reparse points"
                  if ((File.GetAttributes(item) & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint)
                  {
                      AddFileNamesToList(item, allFiles);
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案4】:

        VonC 的回答已经解释了您可能想要检查合并提交的不同类型的钩子。

        如果你只是想要一个简单的解决方案来避免提交冲突,那么它已经包含在 git 默认的预提交钩子示例中。只需将.git/hooks/pre-commit.sample 重命名为.git/hooks/pre-commit 即可启用该钩子。如果您随后尝试提交冲突:

        $ git commit -am "Fix crash in frobnicate"
        src/foo.c:239: leftover conflict marker
        

        注意:

        该脚本在内部使用git diff --check,它还会检查各种空白问题——因此您也可能会遇到空白错误。您也可以在提交查找问题之前运行git diff --check。有关详细信息和配置选项,请参阅 git diff 的手册页。

        这对 git V2.0 有效;不知道什么时候推出的。

        【讨论】:

        • 我得到的预提交钩子示例是关于已提交文件名中的非 ASCII 字符。能否给出无冲突样本的内容?
        • @Janis:没错。该脚本调用git diff-index --check,它将检查冲突标记。试试吧:-)。
        • 我知道,自从您对此做出反应以来已经过去了一段时间,但是......在我的 pre-commit.sample 中没有 git diff-index --check;无论如何,它也不会在激活时检测到剩余的合并制造商:(
        • @ConfusedMerlin:嗯,默认的示例预提交钩子仍然包含 git diff-index --check: github.com/git/git/blob/master/templates/… 。尝试创建一个新的 repo (git init)。如果您仍然没有获得预提交示例挂钩,请提出一个新问题 :-)。
        • 啊,发现它就在我的终端外一行sigh;无论如何,即使启用了该钩子,我也可以愉快地提交合并标记:(所以,是的,它应该是一个新问题。
        【解决方案5】:

        您可以使用pre-commit hook,但请注意git commit --no-verify 会有效地忽略它。

        我通常会放置一个pre-receive 挂钩,以便在(更多)中心点控制正在推送的内容。

        pre-commmit 允许更及时的检测(在开发周期的早期)。

        这里是 another example(除了 jthillcomment),在 perl 中。
        它使用git diff-index -p -M --cached HEAD,即git diff-index instead of git diff
        我留下了一些由这个钩子完成的其他控件,只是为了展示您可以在这样的脚本中执行的检查类型。

        #!/usr/bin/perl
        
        use Modern::Perl;
        use File::Basename;
        
        my $nb_errors = 0;
        my $filepath;
        for my $l ( split '\n', `git diff-index -p -M --cached HEAD` ) {
            if ( $l =~ /^diff --git a\/([^ ]*) .*$/ ) {
                $filepath = $1;
            }
            given ( $l ) {
                # if there is a file called *.log, stop
                when ( /\.log/ ) {
                    say "$filepath contains console.log ($l)";
                    $nb_errors++;
                }
                # check if there is a warn, that could be unconditionnal, but just warn, don't stop
                when ( /^[^(\#|\-)]+warn/ ) {
                    # stay silent if we're in a template, a "warn" here is fair, it's usually a message or a css class
                    unless ($filepath =~ /\.tt$/) {
                    say "$filepath contains warn ($l)";
                    }
                }
                # check if there is a ` introduced, that is a mysqlism in databases. Can be valid so don't stop, just warn
                when (/^\+.*`.*/) {
                    say "$filepath contains a ` ($l)";
                }
                # check if there is a merge conflict marker and just warn (we probably could stop if there is one)
                when ( m/^<<<<<</ or m/^>>>>>>/ or m/^======/ ) {
                    say "$filepath contains $& ($l)";
                }
            }
        }
        
        if ( $nb_errors ) {
            say "\nAre you sure you want to commit ?";
            say "You can commit with the --no-verify argument";
            exit 1;
        }
        exit 0;
        

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-04-22
        • 2023-03-21
        • 1970-01-01
        • 2021-01-20
        • 2011-12-19
        • 2012-03-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多