git涂抹/清除分支之间的过滤器

时间:2014-04-07 10:20:21

标签: git gitattributes

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

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


TL;博士

这是一个详细的问题,但摘要是:

  • 我可以将DEBUG = false存储在一个分支上的文件中,将DEBUG = true存储在另一个分支中,使用涂抹/清除过滤器来管理该文件吗?怎么样?

背景

我在bitbucket上有各种远程回购。我在Win8上使用SourceTree,将远程存储库克隆到我的笔记本电脑上。我为开发,功能,发布等创建了不同的分支(在A successful Git branching model之后更好或更差)。

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

public static final boolean DEBUG = false;

我希望这个值在{"生产"}上false。 (主)分支,并且在我的功能分支上为true

  • 这可能是使用过滤器,还是我已经误解了用例?
  • 我不确定过滤器是否在同一本地托管仓库的两个分支之间如此工作,或者过滤器仅在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
  • 不应该"涂抹"我检查文件时运行过滤器了吗?

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

如果我在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 - >是的,合并回来的变化是真的 - >假的。

将更改限制在生产(主)分支所需的自定义脚本需要知道正在运行的分支。所以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's answer,因为它回答了我提出的基本问题。

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

5 个答案:

答案 0 :(得分:7)

  

我希望在文件

中看到值true

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

要强制涂抹,请在回购顶部执行:

git checkout HEAD --
  

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

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

为了让每个分支的涂抹效果不同,我建议调用一个脚本,该脚本首先查看当前分支的名称。
请参阅旧答案中的示例" Best practice - Git + Build automation - Keeping configs separate"。

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

答案 1 :(得分:3)

看看expandr。这是一个脚本,允许您使用涂抹/清洁在不同的分支上设置不同的配置。基本上就是你原来要求的东西。

现在最大的问题就是切换分支后,有时我需要做一个git checkout HEAD -- "$(git rev-parse --show-toplevel)"来正确弄脏工作目录。但是,其他时候,似乎工作正常;我还没弄明白为什么。我认为它可能与“merge reormalize”被打开有关,导致一些问题?我不确定。 (我有它。)

另一个问题是,您必须使用merge=ours添加一行来保护每个分支的.gitattributes文件本身.gitattributes merge=ours,然后为此启用驱动程序(如您所述) 。这里的 gotcha 是在创建每个单独的分支之后,现在您必须进入每个.gitattributes文件并修改每个分支(我建议现在添加#touched for merge=ours on master之类的评论,{{1}等等,所以你会记住它为什么存在)。您必须执行此操作,因为如果在传入分支及其父分支上创建分支后该文件已更改,#touched for merge=ours on test branch将仅保护文件不会更改为合并中传入分支的版本。 (记住git处理更改,而不是文件。)

答案 2 :(得分:2)

VonC's advice解决了我提出的确切问题,但我无法确定最终细节(根据我对问题的更新)。这个答案给出了我如何做事的细节。


更新

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

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

还尝试使用exit 0touch %A或自定义脚本合并驱动程序(https://stackoverflow.com/a/930495/383414)代替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

每当合并回到“production”分支时,git将查找定义为“ours”的合并策略,并阻止debug_flag.txt被覆盖。

3) 在其他分支上,设置.gitattributes文件而不使用该自定义合并策略。

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

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

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

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

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

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


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

答案 3 :(得分:0)

最直接的解决方案是更新您的makefile以包括检查当前检出的分支。如果分支是命名列表的一部分,则定义新的构建参数-DDEBUG = true或-DDEBUG = false。

请参阅How to programmatically determine the current checked out Git branch

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

答案 4 :(得分:0)

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

详细报道:https://c1.eagen.net/git-smudge-clean.html

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