Git排除了分支的文件

时间:2015-04-11 15:24:32

标签: git gitignore git-config

我想忽略分支中的某些文件,而不必依赖于在与其他分支合并期间将被覆盖的跟踪.gitignore文件。

我密切关注a Stack Overflow answerthe linked blog post,但我的回购似乎没有认出我excludesfile中指定的.git/config。 Git文档(git-configgitignore)似乎没有显示如何指定和解决特定分支的排除文件。

我的.git/config看起来像这样:

[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
        ignorecase = true
        precomposeunicode = true
        excludesfile = +/info/exclude

[branch "myspecialbranch"]
        excludesfile = +/info/exclude_specialbranch

我的.git/info/exclude文件看起来像这样(默认情况下,我没有触摸它):

# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
.DS_Store

我的“specialbranch”中没有.gitignore文件。

如果我尝试忽略info.php这样的文件,我的.git/info/exclude_specialbranch文件如下所示:

info.php

...但它不会忽略该文件。

如果我运行git status --ignored,它只列出默认.DS_Store文件中的exclude文件。

但是,如果我将info.php添加到我的.git/info/exclude文件中:

# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
.DS_Store
info.php

它完全忽略了文件。

请注意,如果excludesfile = +/info/exclude中的[core]下的.git/config行仍然有效,它仍可正常使用。 Git似乎知道系统范围exclude在哪里,而我不必告诉它。

我感觉.git/config无法识别我的自定义排除文件的地址:

excludesfile = +/info/exclude_specialbranch

...很可能是因为使用+来描述.git目录的位置。

在(最近的)Git版本中解决自定义排除文件的正确方法是什么?

我正在运行OSX 10.9.5和Git 2.2.1版。

2 个答案:

答案 0 :(得分:25)

Git不支持每个分支排除文件

你正在努力实现Git不支持的东西。 blog post是这个恶作剧的原始来源the Stack Overflow answer只是鹦鹉学舌。正如在该答案的评论中所指出的那样,即使是原始博客文章也包含的讨论表明该解决方案不起作用,并且它链接到newer blog post,提到即使作者也无法重现该行为。

为什么它不起作用?如果您阅读man gitignoreman git-config,则会发现只有core.excludesfile被引用。那里没有branch.<name>.excludesfilecore.excludesfile旨在让您排除,例如Vim .swp文件或您的软件使用的其他临时文件。

  

core.excludesfile

     

除了.gitignore(每个目录)和.git/info/exclude之外,Git还会查看此文件中是否存在无意跟踪的文件模式。 &#34; ~/&#34;被扩展为$HOME和&#34; ~user/&#34;到指定用户的主目录。其默认值为$XDG_CONFIG_HOME/git/ignore。如果$XDG_CONFIG_HOME未设置或为空,则会使用$HOME/.config/git/ignore。请参阅gitignore(5)

变通

我相信使用post-checkout hook.gitignore通过符号链接实现每个分支排除文件的最佳近似值。

每个分支都有例如一个.gitignores目录,其中的文件以相应的分支命名。然后会有一个.gitignores/__default文件默认使用。 .gitignore将被所有排除文件排除,并且将由post-checkout挂钩创建为.gitignores中相应文件的符号链接。

如果您不想跟踪排除文件,则可以使用.git/info/exclude文件作为.git/info/excludes/__default等的符号链接执行相同操作。

答案 1 :(得分:2)

这是我写的一个脚本:

#!/bin/bash                                                                      

# This is designed to allow per-branch un-ignoring of certain files.
# Use case: Compiled CSS files on master to push to server.
# A special .gitignore file will be present on master at
# {$gitignorePath}/{$disabledMasterGitignoreName} and that file should 
# enable the css files using the ! flag. @https://git-scm.com/docs/gitignore

# When the branch specified by script parameters
# is checked out, {$gitignorePath}/{$disabledMasterGitignoreName} is 
# copied to .gitignore. 
# On other branches this gitignore file is named $disabledMasterGitignoreName, versioned,
# and {$gitignorePath}.gitignore will be deleted. Note, you must ignore 
# {$gitignorePath}.gitignore from your main .gitignore file
#
# To enable put this file in your path and call this script
# in .git/hooks/post-checkout with pass a list of single-space-separated branches that
# will enable the branch-specific .gitignore.

# One caveat is that you can only merge into the branch containing the .gitignore
# file. Otherwise you'll end up re-committing the files. This is fine if you are
# using gitflow and `master` contains your special .gitigore using the ! syntax
# that is un-ignoring files.
#
# Background: @http://stackoverflow.com/questions/29579546/git-excludesfile-for-a-branch

set -e                                                                           

gitignorePath='docroot/sites/all/themes'
disabledMasterGitignoreName='.gitignore_master--disabled'
#branchWithGitignoreEnabled='master'

branch=$(git rev-parse --abbrev-ref HEAD)

gitignoreRoot="$(git rev-parse --show-toplevel)/${gitignorePath}"

if [ -f "${gitignorePath}/.gitignore" ]
then
    masterGitignoreExists=true
fi

if [ -f "${gitignorePath}/${disabledMasterGitignoreName}" ]
then
    disabledMasterGitignoreExists=true
fi

IFS=' ' read -a params <<< "$@"

if [[ " ${params[@]} " =~ " ${branch} " ]]
then
  if [ $disabledMasterGitignoreExists ]
  then
    cp -f "${gitignoreRoot}/${disabledMasterGitignoreName}" "${gitignoreRoot}/.gitignore"
    echo "Enabled ${gitignorePath}/.gitignore"
  fi
elif [ $masterGitignoreExists ]
then
    rm -f "${gitignorePath}/.gitignore"
    if [ masterGitignoreExists ]
    then
      echo "Disabled ${gitignorePath}/.gitignore"
    fi
fi