git 污迹/清洁分支之间的过滤器



有许多涉及污迹/清洁过滤器的相关问题 - 我花了一些时间阅读它们,并尝试了各种选项,但仍然失败。我希望我能以一种适合我的方式提问。

具体来说,我已经阅读了大多数这些答案链接回的页面:

  • 自定义 Git - Git 属性

博士

这是一个详细的问题,但总结是:

  • 我是否可以使用污迹/清洁过滤器将DEBUG = false存储在一个分支上的文件中,DEBUG = true存储在另一个分支中?又如何?

背景

我在位桶上托管了各种远程存储库。我正在使用Win8上的SourceTree将远程存储库克隆到我的笔记本电脑。我为开发、功能、发布等创建了不同的分支(遵循一个成功的 Git 分支模型,无论好坏)。

我有一个名为 Dbug.java 的 Android java 类,其中包含一个布尔值,它可以打开/关闭代码中的各种调试日志记录、模拟等功能。

public static final boolean DEBUG = false;

我希望此值在我的"生产"(主)分支上false,并在功能分支上true

  • 使用过滤器是否可以做到这一点,或者我已经误解了用例?
  • 我不确定过滤器是否在同一本地托管存储库的 2 个分支之间像这样工作,或者过滤器是否仅在 2 个存储库之间工作。

创建筛选器

在当地工作,我检查了生产分支。我创建了一个名为 debug_flag.txt 的测试文件,其中包含以下内容:

// false on production branch
// true on other branches
DEBUG = false;

我在本地存储库的根目录中创建了一个名为 .gitattributes 的文件,并向其添加了过滤器引用:

debug_flag.txt filter=debug_on_off

我用过滤器定义更新了.git/config文件:

[filter "debug_on_off"]
    clean = sed -e 's/DEBUG = true/DEBUG = false/'
    smudge = sed -s 's/DEBUG = false/DEBUG = true/'
  • 据我了解,这应该确保我的文件始终具有生产中的假值,但当我从分支时将具有真值生产。
  • 这是正确的理解吗?

测试过滤器

我创建了一个新的分支test使用以下方法:

git checkout -b test

我检查了文件的内容:

$ cat debug_flag.txt
// false on production branch
// true on other branches
DEBUG = false;
  • 我希望在文件中看到true的值
  • 当我签出文件时,"污迹"过滤器不应该运行吗?

我在文件中添加了一行新行,并提交了。然后我切换回生产部门,这就是事情变得奇怪的地方。

如果我在源代码树中查看该文件,则自创建以来此分支上没有任何更改。这就是我所期望的,因为唯一的更改是在另一个分支上进行的。

如果我查看终端或记事本++中的文件,我看到我的值已更改:

$ cat debug_flag.txt
// false on production branch
// true on other branches
DEBUG = true;

我尚未合并测试分支之间的更改,尚未在生产分支上进行提交,但文件已更改

  • 看起来污迹过滤器是在此分支中的文件上运行的,而不是跨分支运行的。

我错过了拼图中至关重要的部分,希望这是一件简单的事情,可以被有经验的人发现。

我敢打赌,这是对这个概念的简单误解。

请提示任何缺少的信息...


根据冯氏的回复进行更新

设置基本过滤器效果很好。将config文件中的筛选器定义为:

[filter "debug_on_off"]
    clean = sed -e 's/DEBUG = true/DEBUG = false/'
    smudge = sed -s 's/DEBUG = false/DEBUG = true/'

创建新分支修复 false -> true,合并回来更改 true -> false。

将更改限制为仅生产(主)分支需要自定义脚本,这些脚本知道要从哪个分支运行它们。所以config文件变成了:

[filter "debug_on_off"]
    clean = ./scripts/master_clean.sh
    smudge = ./scripts/master_smudge.sh

master_clean.sh:

#!/bin/sh
branch=$(git rev-parse --symbolic --abbrev-ref HEAD)
if [ "master" = "$branch" ]; then
    sed -e s/DEBUG = true/DEBUG = false/ $1
else
    cat $1
fi

master_smudge.sh:

#!/bin/sh
branch=$(git rev-parse --symbolic --abbrev-ref HEAD)
if [ "master" = "$branch" ]; then
    sed -e s/DEBUG = false/DEBUG = true/ $1
else
    cat $1
fi

在这一点上,我遇到了SourceTree所看到的内容与Notepad++中显示的调试文件内容之间的不一致。SourceTree 显示了更改,但 Notepad++ 没有。

接受VonC的回答,因为它回答了我提出的基本问题。

但是,我

可能会实现我编写的解决方案,因为它以一种更简单的方式(对我来说)解决了我试图解决的潜在问题:在单独的分支上保留不同的配置文件。

我希望在文件中看到值为 true

您刚刚创建了一个新分支,没有签出其内容(其内容与您所在的分支相同)

若要强制运行污迹,请在存储库的顶部执行以下操作:

git checkout HEAD --

我尚未合并测试分支之间的更改,尚未在生产分支上进行提交,但文件已更改。

这就是内容过滤器驱动程序的想法:它修改内容,而不影响git status(它仍然将修改后的文件报告为"未更改")。

为了使污迹在每个分支上具有不同的作用,我建议调用一个脚本,该脚本首先查找当前分支的名称。
请参阅我较早的答案"最佳实践 - Git + 构建自动化 - 保持配置分离"中的示例。

#!/bin/sh
branch=$(git rev-parse --symbolic --abbrev-ref HEAD)

VonC 的建议解决了我提出的确切问题,但我无法确定最终细节(根据我对问题的更新)。这个答案详细介绍了我是如何做事的。


更新

下面的方法适用于第一次合并。但在那之后它不再工作。我把它留在这里,因为它代表了我调查的当前状态。

似乎不再调用合并驱动程序。

还尝试了使用 exit 0touch %A 或自定义脚本合并驱动程序 (https://stackoverflow.com/a/930495/383414) 而不是如下所示的true对相关问题进行各种修改。


我找到了一种解决方法,它使用自定义merge策略来解决根本问题,即:

  • 我希望在我的构建分支中始终将构建文件设置为关闭所有调试值。
  • 这可以防止在模拟设置、本地主机设置、日志记录等打开的情况下意外发布产品。

我基于这个问题中的以下信息:文件的.gitattributes和单个合并策略

1)在.git/config文件中定义自定义合并驱动程序,如下所示:

[merge "ours"]
    name = "Keep ours merge"
    driver = true

我不确定此步骤是否是必需的 - 但似乎这可能是某些(较旧?

(详情:https://stackoverflow.com/a/13000959/383414)

2)在构建/生产/原始分支中设置一个.gitattributes文件,以便特殊调试标志使用上述合并策略。

因此,使用我问题中的文件,转到"生产"分支,并将以下行添加到.gitattributes文件中:

debug_flag.txt merge=ours
每当合并回到

"生产"分支时,git 都会寻找定义为"我们的"的合并策略,并防止debug_flag.txt被覆盖。

3)在其他分支上,设置没有该自定义合并策略的.gitattributes文件。

4)配置过程的最后一步(但很重要)是在所有分支中正确设置debug_flag.txt文件,并将更改提交到每个分支。

您现在应该有 2 个分支,每个分支包含不同版本的 .gitattributes 和 debug_flag.txt 文件。这可确保每次合并时都存在冲突。

如果没有冲突,则不会调用自定义的"我们的"合并策略,并且文件可能会被覆盖。

(详情:https://stackoverflow.com/a/16739788/383414)

5)最后,将您的新分支合并回"生产"。由于步骤3和4,您将遇到合并冲突。解决冲突,使 2 个分支保持差异。提交更改。

这两个分支之间的所有未来合并都将无缝忽略debug_flag.txt文件。


这实现了在不同分支上拥有 2 个不同配置文件的目标,以便您可以轻松地将调试与生产代码等分开。这似乎是一个常见的用例,在这个论坛上有很多相关的问题,但我仍然花了几天时间才把它做好。

看看扩展器。这是一个脚本,可让您使用涂抹/清洁在不同的分支上设置不同的配置。基本上就是你最初要求的。

现在最大的问题是,在切换分支后,有时我需要做一个git checkout HEAD -- "$(git rev-parse --show-toplevel)"才能正确涂抹工作目录。然而,其他时候,它似乎工作正常;我还没想出为什么。我认为这可能与打开"合并重整化"有关,导致一些问题?我不确定。(我戴着它。

另一个问题是,您必须使用merge=ours保护每个分支的 .gitattributes 文件本身,方法是在.gitattributes merge=ours上放一行,当然还要为此打开驱动程序(正如您已经提到的)。这里的问题是,在创建每个单独的分支后,现在您必须进入每个 .gitattributes 文件并修改每个文件(我建议现在添加一个注释,如 #touched for merge=ours on master#touched for merge=ours on test branch 等,这样你就会记住它为什么在那里)。您必须执行此操作,因为只有在传入分支及其父分支上创建分支后更改了该文件后,merge=ours才会保护文件不更改为合并中传入分支的版本。(请记住,git 处理的是更改,而不是文件。

最直接的解决方案是更新您的生成文件,以包括对当前签出哪个分支的检查。 如果分支是命名列表的一部分,则定义一个新的生成参数 -DDEBUG=true 或 -DDEBUG=false,否则。

请参阅如何以编程方式确定当前签出的 Git 分支

branch_name=$(git symbolic-ref -q HEAD)
branch_name=${branch_name##refs/heads/}
branch_name=${branch_name:-HEAD}
PROD_BRANCHES := master 
                QA
debug_flag=
ifneq ($(filter $(branch_name),$(PROD_BRANCHES)),)
    debug_flag="-DDEBUG=true"
endif
ifeq($debug_flag,)
    debug_flag="-DDEBUG=false"
endif

我有一个类似的用例,并且能够通过过滤器和结帐后钩子来解决它。 钩子很好,因为它为您完成了清理+涂抹,并在通过 GitHub Desktop 切换分支时立即更新文件。 使用此方法时,每个沙盒/层在每个分支都有自己的配置。

详细文章:https://c1.eagen.net/git-smudge-clean.html

示例存储库位于:https://github.com/vinnyjames/git-filter-demo.git

相关内容

  • 没有找到相关文章

最新更新