May the happiness be with you!

分类: 技术

  • git file control

    简单记录下git控制仓库内文件忽略提交的方法

    主要依靠在仓库下创建.gitignore文件来控制文件是否被追踪记录并提交。

    git的仓库中的所有文件应当处于下述三种状态之一:

    1. tracked:使用git add命令和git commit命令添加并提交到仓库的文件
    2. untracked:在仓库目录下已创建,但是并未被git add命令添加的文件
    3. ignored:git知道要全部排除,保持不被追踪并提交的文件

    标记文件/文件夹为ignore的优势于,当你的仓库中创建了较多的需要提交的文件,在使用git add的时候并不需要一一给出需要追踪的文件名。只需要使用git add -A命令添加仓库内的所有文件,并使用预先编辑好的.gitignore文件告诉git排除那些并不想跟踪的文件和文件夹,让仓库的更新和提交更加方便和自动化。

    .gitignore是一个纯文本文件,通常位于仓库根目录下,包含一个从根目录开始的文件/文件夹的列表。这些文件和文件夹git不会跟踪并提交。

    有关.gitignore文件的逻辑如下,来源于git document


    描述

    gitignore 文件指定了 Git 追踪时应忽略的文件。 已被 Git 追踪的文件不受影响,详见下面的注释。

    gitignore 文件中的每一行都指定了一个模式。 在决定是否忽略路径时,Git 通常会检查多个来源的 gitignore 模式,优先级从高到低(在一个优先级内,由最后匹配的模式决定结果):

    从支持这些模式的命令行中读取的模式。

    模式从与路径相同目录下的 .gitignore 文件或任何父目录(直到工作树的顶层)中读取,上层文件中的模式会被下层文件中的模式覆盖,直到包含该文件的目录。这些模式相对于 .gitignore 文件的位置进行匹配。 项目通常会在其资源库中包含此类 .gitignore 文件,其中包含项目构建过程中生成的文件的模式。

    从 $GIT_DIR/info/exclude 中读取的模式。

    从配置变量 core.excludesFile 指定的文件中读取的模式。

    将模式放入哪个文件取决于模式的使用方式。

    应受版本控制并通过克隆分发到其他仓库的模式(即所有开发人员都想忽略的文件)应放入 .gitignore 文件。

    特定于某个仓库但无需与其他相关仓库共享的模式(例如,存在于仓库内部但特定于某个用户工作流程的辅助文件)应放入 $GIT_DIR/info/exclude 文件。

    用户希望 Git 在任何情况下都忽略的模式(例如,由用户选择的编辑器生成的备份或临时文件),一般会放入用户的 ~/.gitconfig 中由 core.excludesFile 指定的文件。它的默认值是 $XDG_CONFIG_HOME/git/ignore。如果 $XDG_CONFIG_HOME 未设置或为空,则使用 $HOME/.config/git/ignore 代替。

    底层的 Git 工具,如 git ls-files 和 git read-tree,会读取命令行选项指定的 gitignore 模式,或从命令行选项指定的文件中读取。 更高层次的 Git 工具,如 git status 和 git add,会使用上述指定来源的模式。

    日期格式

    空行不匹配任何文件,因此可以作为分隔符,以提高可读性。

    以 # 开头的一行为注释。 对于以散列开头的模式,在第一个散列前面加上反斜杠( “\” )。

    除非使用反斜线(”\”)引号,否则尾部空格将被忽略。

    一个可选的前缀 “!”,用于否定模式;任何被先前模式排除的匹配文件都将被重新包含。如果文件的父目录已被排除,则无法重新包含该文件。出于性能考虑,Git 不会列出排除的目录,因此无论在哪里定义,任何包含文件的模式都不会产生影响。 对于以 “!” 开头的模式,在第一个 “!” 前面加反斜杠(”\”),例如 “!important!.txt”。

    斜线 “/” 用作目录分隔符。分隔符可以出现在 .gitignore 搜索模式的开头、中间或结尾。

    如果在模式的开头或中间(或两者都有)有分隔符,则该模式是相对于特定 .gitignore 文件本身的目录层级而言的。否则,该模式也可能匹配 .gitignore 层级以下的任何层级。

    如果模式末尾有分隔符,则模式只能匹配目录,否则模式既可以匹配文件,也可以匹配目录。

    例如,模式 doc/frotz/ 匹配 doc/frotz 目录,但不匹配 a/doc/frotz 目录;而 frotz/ 则匹配 frotz 和 a/frotz 这两个目录(所有路径都是从 .gitignore 文件开始的相对路径)。

    星号 “*” 匹配斜线以外的任何字符。 字符 “?” 匹配除 “/” 以外的任何一个字符。 范围符号,如 “[a-zA-Z]”,可用于匹配范围中的一个字符。更详细的说明请参见 fnmatch(3) 和 FNM_PATHNAME 标志。

    在与全路径名匹配的模式中,两个连续的星号(”**”)可能有特殊含义:

    “在带斜杠目录之前,表示在所有目录中匹配。例如,”/foo”匹配任何文件或目录的”foo”,与模式”foo”相同。”**/foo/bar”匹配任何文件或目录中直接位于目录”foo”之下的”bar”。

    路径后跟有 “/” 表示匹配这个目录里面的所有文件。例如,”abc/” 匹配相对于 .gitignore 文件的位置中目录 “abc” 内的所有文件,深度无限。

    一个斜杠后面是两个连续的星号再接上一个斜杠,匹配零个或多个目录。例如,”a/**/b” 匹配 “a/b”、”a/x/b”、”a/x/y/b”,等等,依此类推。

    其他连续星号被视为普通星号,将根据前面的规则进行匹配。

    配置

    可选的配置变量 core.excludesFile 表示包含要排除的文件名模式的文件路径,类似于 $GIT_DIR/info/exclude。 除 $GIT_DIR/info/exclude 中的模式外,还将使用排除文件中的模式。

    注释

    使用 gitignore 文件的目的是确保某些不被 Git 追踪的文件不被追踪。

    要停止跟踪当前已被跟踪的文件,可使用 git rm –cached 从索引中移除该文件。文件名随后会被添加到 .gitignore 文件中,以防止该文件在以后的提交中被重新引入。

    访问工作树中的 .gitignore 文件时,Git 不会跟踪符号链接。这样,当从索引或工作树访问文件时,与从文件系统访问文件时的行为保持一致。

    实例

    模式 hello.* 匹配名称以 hello. 开头的任何文件或目录。如果只想将其限制在目录中,而不限制在其子目录中,则可以在模式前加上斜线,即 /hello.*;现在该模式可匹配 hello.txt 和 hello.c 但不匹配 a/hello.java。

    模式 foo/ 将匹配目录 foo 及其下的路径,但不会匹配常规文件或符号链接 foo(这与 Git 中 pathspec 的一般工作方式一致)

    doc/frotz 和 /doc/frotz 模式在任何 .gitignore 文件中都有同样的效果。换句话说,如果模式中已经有中间斜线,那么前导斜线就无关紧要了。

    模式 foo/* 匹配 foo/test.json(一个正则文件)和 foo/bar(一个目录),但不匹配 foo/bar/hello.c(一个正则文件),因为模式中的星号不匹配 bar/hello.c,因为 bar/hello.c 中含有斜线。

    $ git status
    [...]
    # 未追踪的文件:
    [...]
    #       Documentation/foo.html
    #       Documentation/gitignore.html
    #       file.o
    #       lib.a
    #       src/internal.o
    [...]
    $ cat .git/info/exclude
    # 忽略在目录树中的所有对象和存档文件
    *.[oa]
    $ cat Documentation/.gitignore
    # 忽略 html 文件,
    *.html
    # 但追踪自己写的 foo.html
    !foo.html
    $ git status
    [...]
    # 未追踪的文件:
    [...]
    #       Documentation/foo.html
    [...]

    再举一个例子:

    $ cat .gitignore
    vmlinux*
    $ ls arch/foo/kernel/vm*
    arch/foo/kernel/vmlinux.lds.S
    $ echo '!/vmlinux*' >arch/foo/kernel/.gitignore

    第二个 .gitignore 阻止 Git 忽略 arch/foo/kernel/vmlinux.lds.S。

    示例排除除特定目录 foo/bar 以外的所有内容(注意 /* – 如果没有斜线,通配符也会排除 foo/bar 中的所有内容):

    $ cat .gitignore
    # 排除 foo/bar 以外的所有内容
    /*
    !/foo
    /foo/*
    !/foo/bar