【问题标题】:Can I use git diff on untracked files?我可以在未跟踪的文件上使用 git diff 吗?
【发布时间】:2010-10-25 17:47:00
【问题描述】:

是否可以要求git diff 在其差异输出中包含未跟踪的文件,或者我最好在新创建的文件和我编辑的现有文件上使用git add,然后使用:

git diff --cached

?

【问题讨论】:

    标签: git diff


    【解决方案1】:

    使用最新的 git 版本,您可以 git add -N 文件(或 --intent-to-add),这会在该位置的索引中添加一个长度为零的 blob。结果是您的“未跟踪”文件现在变成了将所有内容添加到这个零长度文件的修改,并显示在“git diff”输出中。

    git diff
    
    echo "this is a new file" > new.txt
    git diff
    
    git add -N new.txt
    git diff
    diff --git a/new.txt b/new.txt
    index e69de29..3b2aed8 100644
    --- a/new.txt
    +++ b/new.txt
    @@ -0,0 +1 @@
    +this is a new file
    

    遗憾的是,正如所指出的,当您有一个像这样的 --intent-to-add 文件挂起时,您不能 git stash。虽然如果您需要存储,您只需添加新文件然后存储它们。或者您可以使用仿真解决方法:

    git update-index --add --cacheinfo \
    100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txt
    

    (在这里设置别名是你的朋友)。

    【讨论】:

    • 事实证明,我的 Git 副本不够新,无法添加 -N,但这回答了我的问题。
    • 你可以用“git update-index --add --cacheinfo 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txt”来模拟“git add -N new.txt”(我是怎么把这个放在错误的答案上的?)
    • 如果您有很多新文件怎么办,有没有一种简单的方法可以将它们全部添加然后进行比较?
    • @Vic git add -N .
    【解决方案2】:

    我相信您可以通过简单地提供两个文件的路径来区分索引中的文件和未跟踪的文件。

    git diff --no-index tracked_file untracked_file
    

    【讨论】:

    • 如果自上次提交以来创建了多个未跟踪文件,这是否有效?
    • 是的,完美的答案!然后我可以使用git diff --no-index untracked_file_1 untracked_file_2 在差异上获得git diff 语法着色等...漂亮。
    • 我不明白您为什么要将跟踪文件与 不相关的未跟踪文件进行比较。 如果您只是想获得差异输出未跟踪的文件,您可以使用 /dev/null 代替:git diff --no-index -- /dev/null <untracked_file>
    • 或者只是cat untracked_file_1,或者printf '\e[1;32m%s\e[0m\n' "$(cat untracked_file_1)",如果你真的需要绿色输出的话。 :) (虽然更严肃一点,请注意命令替换将从文件中删除尾随的换行符。)
    • 这应该是公认的答案——它不需要更改 git 的索引;正如原作者所说,有它的缺点
    【解决方案3】:

    对于我的交互式日常 gitting(我一直将工作树与 HEAD 进行比较,并希望将未跟踪的文件包含在 diff 中),add -N/--intent-to-add 不可用,因为它breaks git stash.

    这是我的git diff 替代品。这不是一个特别干净的解决方案,但由于我真的只以交互方式使用它,我可以接受黑客攻击:

    d() {
        if test "$#" = 0; then
            (
                git diff --color
                git ls-files --others --exclude-standard |
                    while read -r i; do git diff --color -- /dev/null "$i"; done
            ) | `git config --get core.pager`
        else
            git diff "$@"
        fi
    }
    

    仅输入 d 将在 diff 中包含未跟踪的文件(这是我在工作流程中关心的),d args... 的行为将与常规 git diff 一样。

    注意事项:

    • 我们在这里使用git diff实际上只是连接单个差异的事实,因此不可能从“真正的差异”中分辨出d的输出——除了所有未跟踪的文件都被排序的事实最后。
    • 这个函数的唯一问题是即使重定向输出也是彩色的;但我懒得为此添加逻辑。
    • 我找不到任何方法来获取包含未跟踪文件的方法,只需为git diff 组装一个光滑的参数列表。如果有人知道如何做到这一点,或者将来某个时候可能会将某个功能添加到 git,请在此处留言!

    【讨论】:

    • 具有讽刺意味的是,我为旧 git 建议的我的git update-index --add --cacheinfo 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txt 解决方法确实git stash 一起工作,假设您的数据库中已经有了 e69de29bb,例如通过尝试以前使用add -N。所以显然它在某种程度上并不完全等同于git add -N:tbh 我不确定如何。
    • 顺便说一句,您正在使用test 命令执行字符串比较而不是数字相等性检查。不应该影响任何事情,但test "$#" -eq 0 更准确地说是预期的。
    • 是的,看起来您仍然需要成对进行...但可以将其伪造为一个 less,因此您不必为每个文件按 q,感觉就像git diff,通过删除每个文件的分页(-P),之后将其添加回来(| less),保留颜色(--color=always)并将其解释为颜色(less -rless -R)。所以总共是:do git -P diff --color=always -- /dev/null "$i"; done | less -r
    • 如果您希望将来被打扰,test -t 1(例如if [ -t 1 ]; then color_arg=--color; fi 或其他东西)是外壳检查其输出是否为终端的一种方式,这是一个有用的决定颜色的方法。而xargs 可能会提供一种摆脱 while 循环的方法。你仍然需要-n 1,所以它仍然会启动git很多次,并且仍然需要成对的方式,但是......它摆脱了whileread,所以也许这样更好?!?我把它留给读者。
    【解决方案4】:

    不是 100%,但如果由于某种原因您不想按照接受的答案的建议将文件添加到索引中,这里是另一种选择:

    如果文件未被跟踪,显然差异是整个文件,所以你可以用 less 查看它们:

    less $(git ls-files --others --exclude-standard)
    

    使用:n:p 在它们之间导航以获取下一个和上一个..

    来自 cmets 的更新:如果您需要补丁格式,您也可以将其与 git diff 结合使用:

    git ls-files --others --exclude-standard -z | xargs -0 -n 1 git --no-pager diff /dev/null | less
    

    在这种情况下,您还可以将输出重定向到文件或使用其他 diff 命令。

    【讨论】:

    • 您也可以运行git diff /dev/null <untracked_tile> 并以补丁格式获取补丁,而不是“只是”一个文件
    • 这个答案结合 git diff 是完美的解决方案。
    • 这里的第二个命令行运行良好。我也喜欢保留颜色,所以我把--color=always放在了diff之后,用更少的-R。所以大家一起:git ls-files --others --exclude-standard | xargs -n 1 git --no-pager diff --color=always /dev/null | diff-so-fancy | less -R.
    • @TylerCollier 需要在 git 命令中添加 -z-0xargs。尽可能使用空终止符,以避免出现错误(和安全漏洞!),例如包含回车符或其他奇怪字符的文件名。
    【解决方案5】:
    git add -A
    git diff HEAD
    

    根据需要生成补丁,然后:

    git reset HEAD
    

    【讨论】:

    • 这有可能通过添加所有内容而丢失之前的(预)工作。尤其是如果一个人经常使用git add -p(顺便说一句,我通常推荐)......这确实提供了一种做基本事情的方法,它只是......应该注意它有潜力避免不必要的副作用。
    【解决方案6】:

    对于一个文件:

    git diff --no-index /dev/null new_file
    

    对于所有新文件:

    for next in $( git ls-files --others --exclude-standard ) ; do git --no-pager diff --no-index /dev/null $next; done;
    

    别名:

    alias gdnew="for next in \$( git ls-files --others --exclude-standard ) ; do git --no-pager diff --no-index /dev/null \$next; done;"
    

    对于合并为一个命令的所有修改和新文件:

    { git --no-pager diff; gdnew }
    

    【讨论】:

    • 这是一个了不起的答案!比公认的要好得多!
    • 我还为最后一个命令添加了这个别名:alias gdall="git --no-pager diff; gdnew"
    【解决方案7】:

    这对我有用:

    git add my_file.txt
    git diff --cached my_file.txt
    git reset my_file.txt
    

    最后一步是可选的,它将使文件保持之前的状态(未跟踪)

    如果您也在创建补丁,这很有用:

      git diff --cached my_file.txt > my_file-patch.patch
    

    【讨论】:

    【解决方案8】:

    更新:我的答案是分阶段和非分阶段的变化。未跟踪和未跟踪。有关已跟踪/未跟踪的信息,请参阅已接受的答案。留给子孙后代。

    以下内容只会为您提供未分阶段的更改:

    $ git diff
    

    如果您想要分阶段和非分阶段的更改,请将HEAD 添加到命令中:

    $ git diff HEAD
    

    【讨论】:

    • HEADdefault value,所以这与git diff 相同,但不能解决问题。
    • 这需要每个未跟踪文件中的git add
    • 如果您编辑此答案以包含git add,这是最简单的如果您的用例是检查您刚刚添加/想要添加的内容
    • @lulian 不正确,git diff 将仅显示未暂存的更改,git diff HEAD 将显示未暂存和暂存的更改。
    • 这没有回答关于“未跟踪”而不是“未暂存”的问题
    【解决方案9】:

    通常当我与远程位置团队合作时,在我遵循 git 阶段 untrack-->staged-->commit 之前,我必须先了解其他团队在同一文件中所做的更改,这对我来说很重要 为此,我编写了一个 bash 脚本,帮助我避免与远程团队不必要的解决合并冲突或创建新的本地分支并在主分支上进行比较和合并

    #set -x 
    branchname=`git branch | grep -F '*' |  awk '{print $2}'`
    echo $branchname
    git fetch origin ${branchname}
    for file in `git status | grep "modified" | awk "{print $2}" `
    do
    echo "PLEASE CHECK OUT GIT DIFF FOR "$file 
    git difftool FETCH_HEAD $file ;
    done
    

    在上面的脚本中,我获取远程主分支(不需要它的主分支)到 FETCH_HEAD 他们只列出我修改过的文件并进行比较 修改文件到 git difftool

    这里有许多 git 支持的 difftool,我配置了 'Meld Diff Viewer' 以获得良好的 GUI 比较。

    【讨论】:

      【解决方案10】:

      使用您可以暂存新文件并且可以对暂存文件进行比较的想法,您可以将这两者结合起来查看差异。我觉得使用起来很简单。

      1. 添加您想要查看差异的文件。在您的情况下,add only untracked files。您可以选择仅添加您希望查看差异的那些文件。

        git stash && git add . && git stash pop 
        
      2. 区分分期

        git diff --staged
        
      3. 如果需要,重置暂存文件

        git reset
        

      综合以上几点,

         git stash && git add . && git stash pop && git diff --staged && git reset 
      

      【讨论】:

        【解决方案11】:

        如果您碰巧在使用 git stash(即预提交 git 挂钩)的脚本上下文中需要此功能,那么这对我来说在 macOS Big Sur 上使用 git v2.34.1 效果很好:

        # Stash unstaged changes
        # NOTE: we always create a stash - possibly even a totally empty one.
        git stash --keep-index --include-untracked --message="pre-commit auto-stash"
        diffTracked=$(git diff --stat --staged stash@{0})
        diffUntracked=$(git stash show --only-untracked stash@{0})
        [[ $diffTracked || $diffUntracked ]] && {
          echo "Stashed diff:"
          # Ensure diffs have standard coloring:
          git diff --stat --staged stash@{0}
          git stash show --only-untracked stash@{0}
        }
        

        【讨论】:

          【解决方案12】:

          假设您没有本地提交,

          git diff origin/master
          

          【讨论】:

          • 该问题要求包含未跟踪文件的git diff 命令。此命令不包括它们。此外,是否存在本地提交与问题完全无关。
          • JFTR、我 git merge --squash mybranchgit diff master 向我展示了未跟踪文件中的更改。
          • 那是不可能的。您似乎对“未跟踪”的含义感到困惑。未跟踪并不意味着文件在一个分支而不是另一个分支中被跟踪,这意味着它不在任何地方的“Git”中以任何方式。不管你是不是壁球都没有区别。 git diff 不显示未跟踪文件的差异:因为它们未跟踪,根据定义,永远不会显示任何差异。这就是 Git 的工作方式。 :)
          猜你喜欢
          • 1970-01-01
          • 2018-09-06
          • 1970-01-01
          • 2016-01-20
          • 2018-02-22
          • 2010-10-05
          • 1970-01-01
          • 2013-10-06
          相关资源
          最近更新 更多