Git 可以忽略某一行吗?

我正在使用 git 在手机的本地浏览器上测试时同步到 phone Gap。因此,我有以下几句话:

var isPhoneGap = false;

很明显,我在构建时改变了这一点,但是有没有什么办法可以设置 git 来忽略这一行,或者我必须把它放到它自己的文件中,以这种方式忽略它?

我在 OSX 10.6上使用 Gitx 和终端。

47671 次浏览

Gitx 应该允许您提交或忽略单独的行(您可能已经知道这一点) ,但是您必须在每次提交时都这样做。我认为为每个部署目标提供一个配置文件(您可以对其进行版本控制)和一些运行时参数(比如 ./myserver --config=whatever.js)会更好。

没有。中的行,因此只能忽略单个文件(以及更多)。Gitignore 匹配文件名,而不匹配文件内容。您已经提到了这个问题的解决方案,即忽略包含您想要忽略的内容的单个文件。

你可以用

git update-index --assume-unchanged [file]

忽略您不希望跟踪的一个文件的更改。我使用这个解决方案时,我需要有一个文件在存储库中,但这个文件有一些部分的变化,我不需要跟踪总是。

当文件有重要的更改时,你必须这样做:

git update-index --no-assume-unchanged [file]

此外,请参阅 Git 文档更新索引了解 --[no-]assume-unchanged参数。

如果指定了这些标志,则不更新为路径记录的对象名称。相反,这些选项设置和取消设置路径的“假设未改变”位。如果启用了“假设未更改”位,git 将停止检查工作树文件是否存在可能的修改,因此需要手动取消该位的设置,以便在更改工作树文件时告诉 git。

你可以这样用 Git 过滤器:

  1. 创建/打开 gitproperties 文件:
    • < project root >/. gittribute (将提交到 repo)
      或者
    • < project root >/. git/info/properties (不会提交到 repo 中)
  2. 添加一行来定义要筛选的文件:
    • *.rb filter=gitignore,即在所有 *.rb文件上运行名为 gitignore的过滤器
  3. 定义 gitconfig中的 gitignore过滤器:
    • $ git config --global filter.gitignore.clean "sed '/#gitignore$/'d",即删除这些行
    • $ git config --global filter.gitignore.smudge cat,即从回购文件中提取文件时什么也不做

备注:
当然,这是针对 Ruby 文件的,当一行以 #gitignore结束时应用,在 ~/.gitconfig中全局应用。根据您的需要对此进行修改。

警告! !
这使您的工作文件不同于回购(当然)。任何检出或重新基地将意味着这些线路将丢失!这个技巧可能看起来没什么用,因为这些行在签出、重建基础或拉取时会反复丢失,但是我有一个特定的用例来使用它。

只是 git stash save "proj1-debug" 当过滤器处于非活动状态时(只是暂时禁用它在 gitconfig或东西)。这样,我的调试代码总是可以在任何时候对我的代码进行 git stash apply,而不用担心这些代码行会被意外提交。

对于如何处理这些问题,我有一个可能的想法,但我会在其他时间尝试实现它。

感谢 Rudi 和 jw013提到了 git 过滤器和 gittribute。

如果您的文件是特定类型的,您可以声明一个 内容过滤器驱动程序,您可以在 .gitattributes文件中声明(如“ Git 属性”的“关键字扩展”所示) :

http://git-scm.com/figures/18333fig0702-tn.png

*.yourType filter=yourFilterName

(你甚至可以 为特定文件设置过滤器,如果你想)

实施:

  • yourFilterName.smudge(在 git checkout触发)及

      git config --global filter.yourFilterName.smudge 'sed "s/isPhoneGap = .*/isPhoneGap = true/"'
    
  • yourFilterName.clean(在 git add触发)

      git config --global filter.yourFilterName.clean 'sed "s/isPhoneGap = .*/isPhoneGap = false/"'
    

您的文件在 git status上看起来没有什么变化,但是它的签出版本将为 isPhoneGap提供正确的值。


注意: 在评论中Ohaal罗尔德建议在单独的 helper.sh脚本中隔离 sed呼叫:

sed "s/isPhoneGap = .*/isPhoneGap = true/" "$@"

我猜你的线人可能不止一次提到过这个。

我觉得最干净的方式就是。Userbuildconfig 文件的某种类型,只需要包含并签入默认值即可。然后您可以使用 卡洛斯的建议将该文件单独标记为假设未更改。这样,您需要检查设置的文件的其他更改就不会丢失。

这可以允许您在本地调优预处理器宏(或者为 java 调优类似 https://stackoverflow.com/a/1813873/1270965的宏)。

内容过滤器驱动程序不是一个好的解决方案。您可能能够在 git status/etc 中隐藏这一行,但是它并没有被真正忽略。一旦你更改了值,你的工作目录就会被标记为脏的,即使这个更改可能看不见。

如果您真的希望这一行不受版本控制,那么将其更改为命令行参数或将其放在忽略的包含或生成文件中可能是唯一可行的方法。

继续 https://stackoverflow.com/a/20574486/4935114@ Mike建议创建一个 pre-commit钩子,它将 grep在阶段文件中的行,人们可能想要忽略。钩子会检查这些台词是不是设计好的。如果是这样,它会发出一个警告,并且它的 exit代码是 1,因此提交进程将不会继续。

受到 @ Mike 的回答的启发,我发现自己可能使用了他的钩子的改进版本,其中 自然而然地 reset(带有 -p标志)的特定行,我们想要忽略。

我不确定这个钩子是否适用于这样的情况,即有许多文件与这一行被忽略,但是这个 pre-commit钩子在特定的文件 buildVars.java中查找这一行中的更改。钩子脚本在我的机器上测试时看起来是这样的。

#!/bin/sh


# this hook looks for lines with the text `var isPhoneGap = false;` in the file `buildVars.java` and it resets these lines to the previous state before staged with `reset -p`


if [[ $(git diff --no-ext-diff --cached buildVars.java | grep --count -e "var\ isPhoneGap[\ ]*=[\ ]*") -ne 0 ]]; then
cat <<EOW
WARNING: You are attempting to commit changes which are not supposed to be commited according to this \`pre-commit\` hook
This \`pre-commit\` hook will reset all the files containing this line to it's previous state in the last commit.
EOW
echo /$'\n'isPhoneGap$'\n'y$'\n'q | git reset -p
# BONUS: Check if after reseting, there is no actual changes to be commited and if so, exit 1 so the commit process will abort.
if [[ $(git diff --no-ext-diff --cached | wc -l) -eq 0 ]]; then
echo there are no actual changes to be commited and besides the change to the variable \'isPhoneGap\' so I won\'t commit.
exit 1
fi
fi

解释

我所做的是回显在交互式 reset进程中搜索正则表达式 isPhoneGap的控制序列。因此,模拟用户按 /搜索 isPhoneGap,按 y时,问他是否要放弃这个补丁,最后按 q退出交互式 reset

交互式反向补丁过程记录在这里: https://git-scm.com/docs/git-add#git-add-patch


注意: 上面的脚本假设变量 interactive.singleKeyfalse。如果您将您的命令配置为 true,请在警告之后立即从 echo命令中删除任何 $'\n'

我认为没有人提供这种方法来解决这个问题,所以,这是我的技巧。我一直在本地回购的私有分支中的一个修订版中记录/调试/等内容(实际上,它可以是多个修订版)。因此,当我启动一个特性分支并希望拥有所有的好东西(在 my-goodies分支中)时,我只需要这样做:

git checkout my-feature
git cherry-pick my-feature..my-goodies # assuming both started from the same main branch, say, my-goodies started a few (or many) revisions back

现在我开始做这个功能。完成之后,我会重写特性分支的历史,这样那些修订就不复存在了:

git rebase -i @{u} # set all the goodies revisions to skip, save, and go

现在我的树枝已经被清理干净了,我可以随便推动任何地方。