有没有办法防止在Git中提交冲突的文件?没有人会故意提交有冲突的文件。但是,有没有一种方法可以防止Git提交这些文件?
Git是否具有任何设置或可配置的值,可以通过查找<<<<<<<
,=======
或>>>>>>>
符号来防止文件被提交?
有没有办法防止在Git中提交冲突的文件?没有人会故意提交有冲突的文件。但是,有没有一种方法可以防止Git提交这些文件?
Git是否具有任何设置或可配置的值,可以通过查找<<<<<<<
,=======
或>>>>>>>
符号来防止文件被提交?
VonC的回答已经解释了可能需要检查合并提交的不同种类钩子。
如果你只想要一个简单的解决方案来避免提交冲突,git中默认的pre-commit hook示例已经包含了这个功能。只需通过将.git/hooks/pre-commit.sample
重命名为.git/hooks/pre-commit
启用这个hook。然后,如果你试图提交一个冲突:
$ 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;不知道是何时引入的。
git diff-index --check
命令:https://github.com/git/git/blob/master/templates/hooks--pre-commit.sample。尝试创建一个新的 repo(git init
)。如果你仍然没有得到 pre-commit sample hook,请提出一个新的问题 :-)。 - sleskepre-commit
hook,但请注意,git commit --no-verify
将有效地忽略它。pre-receive
hook以便在(更)中央的位置控制推送的内容。pre-commmit
允许更及时地检测(在开发周期的早期)。git diff-index -p -M --cached HEAD
,即git diff-index
而不是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;
git diff
的输出中分离出文件路径:如果输出以 (^
) diff --git a/
开始,则其余部分是文件路径(直到下一个空格)。 - VonC一个简单的方法是使用预提交挂钩,在这里进行了改编,以使其更加谨慎和彻底:
#!/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
)!客户端解决方案是使用git pre-commit hooks,当您提交时(合并是一种提交类型),它允许您执行特定命令,如果失败,则无法合并,直到解决为止。
pre-commit是管理git pre-commit hooks的简单和标准化的方法。
在您的存储库根目录中创建一个名为.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
我添加了一个单元测试,以便遍历解决方案目录中的所有文件,查找冲突标记字符串
[TestClass]
public class SolutionValidationTests
{
[TestMethod]
public void CheckForMergeConflicts()
{
var solutionValidationScripts = new SolutionValidationScripts();
var mergeConflictCheckOkay = solutionValidationScripts.CheckForGitMergeConflict();
Assert.IsTrue(mergeConflictCheckOkay);
}
}
解决方案验证脚本在下面单独定义:
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);
}
}
}
}
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
中。这是从键盘到编辑框的过程,但应该基本正确。 - jthill