Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么git使用不同的文本属性给出不同的diff结果?_Git - Fatal编程技术网

为什么git使用不同的文本属性给出不同的diff结果?

为什么git使用不同的文本属性给出不同的diff结果?,git,Git,我发现当我更改.gittributes中的text属性时,git会给我一个不同的diff结果。谁能给我解释一下吗 以下是我所做的: 添加一个.gittributes文件,其内容为*-text 添加另一个包含某些内容的文本文件 承诺 然后我添加了一行“ddd”和git diff,结果与预期一致 diff --git a/abc.txt b/abc.txt index aa3b7ba..911ddef 100644 --- a/abc.txt +++ b/abc.txt @@ -2,3 +2,5 @

我发现当我更改.gittributes中的text属性时,git会给我一个不同的diff结果。谁能给我解释一下吗

以下是我所做的:

  • 添加一个.gittributes文件,其内容为
    *-text
  • 添加另一个包含某些内容的文本文件
  • 承诺
  • 然后我添加了一行“ddd”和
    git diff
    ,结果与预期一致

    diff --git a/abc.txt b/abc.txt
    index aa3b7ba..911ddef 100644
    --- a/abc.txt
    +++ b/abc.txt
    @@ -2,3 +2,5 @@ aaa
     bbb
     ccc
    +ddd^M
    +
    
    但当我再次将.gittributes更改为
    *text
    和diff时,git给了我以下信息:

    diff --git a/abc.txt b/abc.txt
    index aa3b7ba..9a3ed4f 100644
    --- a/abc.txt
    +++ b/abc.txt
    @@ -1,4 +1,6 @@
    -aaa
    -bbb
    -ccc
    +aaa
    +bbb
    +ccc
    +ddd
    +
    

    据我所知,text属性仅用于eol规范化。为什么它会影响差异结果?

    这一切变得有点复杂,因为这里有许多运动部件。首先,让我们讨论一下git diff和“树”。然后让我们看看Git可以做什么样的线端修改,以及Git什么时候做。然后,让我们具体看看
    .gittributes
    中的
    *-text
    *text
    是什么意思。最后,让我们一起考虑所有的代码:<代码> git diff > /p>
    git diff
    命令比较两个“树” 默认情况下,有一些特定的模式用于比较文件,但我们不打算在这里讨论那些运行
    git diff
    比较两个git称之为树的模式。树是文件的集合,其中每个文件都有一个名称:
    A.txt
    abc.txt
    dir/c.txt
    dir/sub/d.txt
    ,等等(但本例到此为止)。此树的顶层是包含
    a.txt
    abc.txt
    、子目录/文件夹
    dir
    ,Git称之为子树的目录/文件夹(使用您喜欢的术语)。名为
    dir
    的子树包含
    c.txt
    和另一个子树
    sub
    ,最后一个子树包含
    d.txt

    Git想要两棵这样的树。一个通常是提交,另一个通常也是第二个(可能不同)提交。这种
    git diff
    比较两个提交树的内容

    但是,默认情况下,
    git diff
    以索引作为第一棵树开始。您的索引(Git称之为索引,有时称之为暂存区域或缓存)是Git主要用于构建下一次提交的特殊实体。索引也有一系列子任务,这就是为什么它有这三个不同的名称。(我们将在这个答案的末尾看到一个额外的任务。)索引从当前提交中所有内容的副本开始:您在上运行的提交
    git checkout
    。因此,至少在最初,索引与当前提交匹配

    你也有一个工作树。工作树非常简单:它是你工作的地方。Git需要有一个工作树,因为Git存储的所有文件,无论是提交还是索引,都是一种特殊的、高度压缩的、仅限Git的格式。(从技术上讲,这些是Git blob对象。)计算机上的大多数程序,包括您自己的文本编辑器和编译器等,都不能处理仅Git文件。这些程序需要文件具有正常的每日文件格式,因此Git会在工作树中将仅限Git的文件提取为正常格式

    每次您
    git添加一个类似
    abc.txt
    的文件时,git都会将该文件从您的工作树复制到特殊的git-only格式,并将特殊的blob hash ID填充到索引中。因此,如果您在工作树中更改了一个文件,然后git添加更改后的文件,git会将更改复制到存储库中(作为blob对象),并将新的哈希ID放入索引中,将以前的索引版本替换为从工作树复制的版本。请注意,索引中不断有一些版本的
    abc.txt
    。首先,它具有当前提交的版本。然后,在
    git add abc.txt
    之后,它就有了工作树的版本(尽管现在是只使用git的特殊格式)

    无论如何,这就是我们需要知道的关于索引的大部分内容:作为Git“树”的一个变体,它包含将进入下一次提交的所有内容。最初,这与我们刚刚签出的提交中的所有内容相同

    我们已经提到了工作树,它是一种普通的、不适合Git的形式。尽管如此,各种Git命令也可以将其作为树来使用,而
    Git diff
    就是其中之一。Git将把每个目录/文件夹视为一个子树,而工作树本身就是顶层树。树中的每个文件都像一个Git blob对象,但每个文件都有自己的格式,在计算机上是正常的,而不是只使用Git的特殊格式

    因此:在没有参数的情况下运行
    git diff
    ,将索引与工作树进行比较。在这两种情况下,Git使用它们就像它们是Git的内部“树”对象一样。不过,重要的是要记住Git正在比较什么:现在是索引和工作树。这一点在一瞬间变得更加重要

    线端修改 Git的特殊的、内部的、仅限Git的格式是为了适合Git而设计的。它也是由Linus Torvalds设计的,所以正如您所预料的,它对Linux非常友好。因此,您可以说它更希望文本文件的行以纯换行符
    \n
    字符结尾,而不是DOS/Windows样式的CRLF(或
    \r\n
    )序列。这有点言过其实:Git真的一点都不在乎这件事。但是很多使用Git的人都很在意,不管出于什么原因,不管你喜欢与否,
    \n
    -目前只是文本文件的正常Git内部格式。你不必用这个,但很多人都用这个

    同时,你的工作树,在你的计算机上使用你的计算机的首选(“正常”)格式,很可能有文本文件有CR-LF(我将从这里开始拼写没有连字符)行结尾,如果y
    current commit       index       work-tree
    --------------      -------      ---------
           a.txt          a.txt         a.txt
         abc.txt        abc.txt       abc.txt
    
    $ vis foo.txt
    this file has\^M
    crlf line endings\^M
    
    $ git status
    On branch master
    nothing to commit, working tree clean
    
    $ echo '* text' > .gitattributes
    
    $ git status
    On branch master
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
    
            .gitattributes
    
    nothing added to commit but untracked files present (use "git add" to track)
    
    $ touch foo.txt
    $ git status
    On branch master
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
    
            modified:   foo.txt
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
    
            .gitattributes
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
    $ git diff | vis
    warning: CRLF will be replaced by LF in foo.txt.
    The file will have its original line endings in your working directory.
    diff --git a/foo.txt b/foo.txt
    index 257cbae..6bf00d0 100644
    --- a/foo.txt
    +++ b/foo.txt
    @@ -1,2 +1,2 @@
    -this file has\^M
    -crlf line endings\^M
    +this file has
    +crlf line endings
    
    $ echo '* -text' > .gitattributes
    $ git diff
    $ git status
    On branch master
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
    
            .gitattributes
    
    nothing added to commit but untracked files present (use "git add" to track)