22

有许多涉及涂抹/清洁过滤器的相关问题 - 我花了几个小时阅读它们,并尝试了各种选项,但仍然失败。我希望我能以一种我得到适合我的答案的方式提问。

具体来说,我已经阅读了大部分答案链接回的页面:


tl;博士

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

  • 我可以将DEBUG = false文件存储在一个分支和DEBUG = true另一个分支中,使用涂抹/清洁过滤器来管理该文件吗?如何?

背景

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

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

public static final boolean DEBUG = false;

我希望这个值出现false在我的“生产”(主)分支上,并且出现true在我的特性分支上。

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

创建过滤器

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

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

我在本地 repo 的根目录中创建了一个文件,.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文件中的值
  • 当我签出文件时,“涂抹”过滤器不应该运行吗?

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

如果我查看 SourceTree 中的文件,则该分支自创建以来没有任何更改。这是我所期望的,因为唯一的更改是在不同的分支上进行的。

如果我查看终端或 Notepad++ 中的文件,我发现我的值已更改:

$ cat debug_flag.txt

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

我还没有合并测试分支对面的更改,我还没有在生产分支上提交,但是文件已经更改

  • 看起来污迹过滤器是在这个分支内的文件上运行的,但不是跨分支。

我错过了这个难题的一个重要部分,希望它是一些简单的东西,可以被有经验的人发现。

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

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


根据 VonC 的回复更新

设置基本过滤器效果很好。将文件中的过滤器定义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 的回答,因为它回答了我提出的基本问题。

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

4

5 回答 5

9

我希望在文件中看到值 true

您刚刚创建了一个新分支,没有检查它的内容(因为它的内容与您所在的分支相同)

要强制涂抹运行,请在 repo 的顶部执行:

git checkout HEAD --

我还没有合并测试分支对面的更改,我还没有在生产分支上提交,但文件已经更改。

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

要让每个分支的污迹表现不同,我建议调用一个脚本,该脚本首先查看当前分支的名称。
请参阅我较早的答案“最佳实践 - Git + 构建自动化 - 保持配置分开”中的示例。

#!/bin/sh
branch=$(git rev-parse --symbolic --abbrev-ref HEAD)
于 2014-04-07T10:41:42.053 回答
3

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


更新

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

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

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


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

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

我根据这个问题的信息得出以下信息:.gitattributes & individual merge strategy for a file

1)在文件中定义一个自定义的合并驱动程序.git/config如下:

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

我不确定是否需要此步骤 - 但似乎它可能是某些(较旧?)系统上的错误的解决方法。

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

2) 在 build/production/pristine 分支中设置一个.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 个不同配置文件的目标,这样您就可以轻松地将调试与生产代码等分开。这似乎是一个常见的用例,在这个论坛上有很多相关的问题,但我还是花了一些时间几天才能把事情做好。

于 2014-04-07T13:37:23.603 回答
3

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

现在最大的问题就是在切换分支之后,有时我需要做一个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 处理更改,而不是文件。)

于 2014-09-15T23:24:14.940 回答
0

最直接的解决方案是更新您的 makefile 以检查当前签出的分支。如果分支是命名列表的一部分,则定义一个新的构建参数 -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
于 2016-06-01T13:53:52.893 回答
0

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

详细记录在:https ://c1.eagen.net/git-smudge-clean.html

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

于 2021-05-03T08:02:36.600 回答