Git stash未缓存:如何收起所有未分级的变化?

klm*_*123 72 git git-stash

假设在由git版本化的项目中进行了两组更改.一套是上演的,另一套则没有.

我想通过在此状态下运行我的项目(在提交之前)来重新检查暂存的更改.什么是简单的方法来收起所有未分阶段的变化并且只留下上演?所以我需要从我的项目中消失的非分段更改,但是要存储在某个地方以便进一步工作.

这听起来非常像git stash命令.但是git stash会将未分阶段和分阶段的更改从我的项目中移除.我找不到类似的东西git stash uncached.

Moh*_*ady 78

更新:
即使这是选定的答案,很多人都指出下面答案是正确答案,我建议检查出来.

旧答案:
如果使用该--keep-index选项,则已添加到索引的所有更改都保持不变:

git stash --keep-index
Run Code Online (Sandbox Code Playgroud)

来自以下文件git-stash:

测试部分提交

git stash save --keep-index当您想要在工作树中的更改中进行两次或更多次提交时,您可以使用,并且您希望在提交之前测试每个更改:

# ... hack hack hack ...
$ git add --patch foo            # add just first part to the index
$ git stash save --keep-index    # save all other changes to the stash
$ edit/build/test first part
$ git commit -m 'First part'     # commit fully tested change
$ git stash pop                  # prepare to work on all other changes
# ... repeat above five steps until one commit remains ...
$ edit/build/test remaining parts
$ git commit foo -m 'Remaining parts'
Run Code Online (Sandbox Code Playgroud)

但是,如果您只想视觉检查分阶段的更改,您可以尝试difftool:

git difftool --cached
Run Code Online (Sandbox Code Playgroud)

  • 请注意,此答案还会隐藏您上演的更改. (13认同)
  • 这个答案有效。问题是关于暂存与未暂存的问题,没有提及任何有关未跟踪文件的内容。 (6认同)
  • 另见`git stash [-p | --patch]`,感觉就像交互式存储.从`man git stash`"使用--patch,你可以交互式地从HEAD和工作树之间的差异中选择难以存储的东西." (4认同)
  • 这个答案对我来说“效果很好”:结果存储中唯一的东西是未暂存的更改。‍♂️ (4认同)
  • 这个答案并不是很有用,因为它会导致混淆。这个答案更好 /sf/answers/2427691171/。 (2认同)
  • 对我来说,它将暂存和未暂存的文件都放入存储中。 (2认同)
  • 以下是此答案的问题演示:https://gist.github.com/bobpaul/bded251b8637061e6a7094e6141ef38f (2认同)
  • 这个答案混淆了“untracked”和“unstaged”。未跟踪的文件是尚未在 Git 中的新文件。未暂存的文件是已更改的文件,但尚未选择这些更改进行提交。因此,新文件既可以是未跟踪的,也可以是未暂存的。但是,如果您对 Git 中已有的现有文件进行更改,该文件将不会被取消跟踪,但会被取消暂存。OP 想要的是一种仅存储那些未选择提交(未暂存)的更改的方法,这与未跟踪完全分开。 (2认同)

ste*_*son 72

接受的答案还隐藏了一些已经指出的阶段性更改,并且它不会存储未跟踪的文件.这是一种方法,无需在存储中进行暂存更改,同时还可以删除和存储未跟踪的文件.

我们的想法是暂时提交您的暂存更改,然后存储未暂存的更改,然后取消提交临时提交:

# temp commit of your staged changes:
$ git commit --message "WIP"

# stage your previously unstaged files before stashing (so you get untracked files):
$ git add .

$ git stash

# now un-commit your WIP commit:
$ git reset --soft HEAD^
Run Code Online (Sandbox Code Playgroud)

此时,您将收到未暂存更改的隐藏信息,并且只会在您的工作副本中显示您的暂存更改.

  • 这真的是IMO的正确答案.当前接受的答案中的`--keep-index`选项仍然存储在索引中的内容,它只是**将它保留在索引中.那么它就是重复的,随之而来的是欢闹. (16认同)
  • @PengheGeng,您可以使用“--no-verify”运行“git commit”来禁用此特定提交的提交挂钩 (6认同)
  • @KenWilliams <del> hilarity </ del> <ins> tragedy </ ins> (3认同)
  • 这是迄今为止最好的答案,因为接受的答案中的 --keep-index 选项具有误导性。这应该是公认的答案。 (3认同)
  • `git add .`步骤可能希望通过`git add --all`进行改进,因为它应该抓取当前工作目录上方的目录中的文件. (2认同)
  • -1 这种方法并不适用于所有场景。它提交分阶段的更改,但如果您有一个检查当前工作代码的预提交挂钩,则提交可能会失败。如果您的分阶段更改很好,但未分阶段的更改不好,则此方法将无法提交分阶段更改。 (2认同)

Evi*_*lta 18

Git 2.35(2022 年第一季度)开始,您现在可以通过git stash --staged.

因此,要隐藏未暂存 (且未跟踪)的更改:

git stash --staged          # stashes staged, leaving unstaged
git stash -u                # stashes unstaged & untracked
git stash pop "stash@{1}"   # pops staged back (but they're now unstaged)
git add -A                  # restages the previously staged changes
Run Code Online (Sandbox Code Playgroud)

然而,如果分阶段和未分阶段的更改影响相同的行,则这将失败git stash --staged,因为在这种情况下,通过隐藏分阶段的更改会“部分”失败,但会留下分阶段和未分阶段的更改。
在这种情况下,下面的方法(使用git commit可能会更好。


如果您想为其添加 git别名.gitconfig,请将其添加到您的:

[alias]
    stash-unstaged = "!cd "${GIT_PREFIX:-.}"; f() { \
        git stash --quiet --staged;                 \
        git stash -u \"$@\";                        \
        git stash pop --quiet \"stash@{1}\";        \
        git add -A;                                 \
    }; f"
Run Code Online (Sandbox Code Playgroud)

用法:

git stash-unstaged -m "Stash Message"
Run Code Online (Sandbox Code Playgroud)

对于Git 版本 <2.35

您可以通过利用分离暂存和未暂存的更改来隐藏未暂存 (和未跟踪)的更改:git commit

git commit -m "TEMP"        # commits staged, leaving unstaged
git stash -u                # stashes unstaged & untracked
git reset --soft HEAD^      # undo commit, bringing staged back
Run Code Online (Sandbox Code Playgroud)

与之前的方法(使用git stash --staged不同,即使暂存和未暂存的更改影响相同的行,该方法仍然有效。
不过,当您弹出存储时,您可能需要解决合并冲突。


仅供参考,要存储分阶段的更改,只需先存储未分阶段的更改:

# Stash unstaged as shown previously
git commit -m "TEMP"
git stash -u
git reset --soft HEAD^

git stash -u                # stashes remaining staged
git stash pop "stash@{1}"   # pops unstaged back
Run Code Online (Sandbox Code Playgroud)

这 2 个的别名:

[alias]
    stash-unstaged = "!cd "${GIT_PREFIX:-.}"; f() { \
        git commit --quiet -m \"TEMP\";             \
        git stash -u \"$@\";                        \
        git reset --quiet --soft HEAD^              \
    }; f"
    
    stash-staged = "!cd "${GIT_PREFIX:-.}"; f() {   \
        git stash-unstaged --quiet;                 \
        git stash -u \"$@\";                        \
        git stash pop --quiet \"stash@{1}\";        \
    }; f"
Run Code Online (Sandbox Code Playgroud)


Bin*_*ile 17

我发现明确的答案对我来说不起作用,因为我需要的东西真的只能隐藏我未经修改的变化.标记的答案,git stash --keep-index隐藏了分阶段和非分阶段的变化.该--keep-index部分仅仅将索引保留在工作副本上.这适用于OP,但仅仅是因为他提出的问题与他实际想要的答案略有不同.

我发现存储未分级更改的唯一真实方法是不使用存储:

git diff > unstaged.diff
git apply -R unstaged.diff
Run Code Online (Sandbox Code Playgroud)

git checkout -- .也会工作而不是apply -R.

工作工作工作...

git apply unstaged.diff
rm unstaged.diff
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案!它是多个 stackoverflow 线程中唯一一个执行其声明的操作且不依赖于进行临时提交的线程! (3认同)
  • @user643011:临时提交在 git 中并不是一件坏事。它们不需要任何成本,也不会伤害任何人。 (2认同)
  • @Fritz:在某些情况下不可能没有临时提交。如果您有一个检查当前工作代码的预提交钩子,它可能会失败。如果您的分阶段更改很好但您的非分阶段更改不好,则此方法将无法提交分阶段更改。 (2认同)
  • 这不包括未跟踪的文件。您需要使用“git ls-files”来查找并包含差异补丁中的文件 (2认同)
  • 这绝对应该是公认的答案,比编写预提交挂钩时的临时提交更好。 (2认同)
  • **唯一真正用正确且充分的解决方案回答问题的答案。谢谢。** (2认同)

Gle*_*as' 12

由于到目前为止,这里的各种答案似乎都有自己的复杂性/局限性,因此我想提供更多替代方案,涵盖我个人需要的所有特定边缘情况。

\n

太长了;博士

\n

列出暂存(未删除)文件:

\n
git diff --staged --diff-filter=d --name-only\n
Run Code Online (Sandbox Code Playgroud)\n

列出未暂存(未删除)的文件:

\n
git diff --diff-filter=d --name-only\n
Run Code Online (Sandbox Code Playgroud)\n

列出未暂存/未跟踪的文件:

\n
git ls-files --modified --others --exclude-standard\n
Run Code Online (Sandbox Code Playgroud)\n

仅存储暂存文件(最初来自StackOverflow 答案,但略有调整):

\n
git diff --staged --diff-filter=d --name-only\n
Run Code Online (Sandbox Code Playgroud)\n

仅存储未暂存(而非未跟踪)的文件:

\n
git stash push --keep-index -- $(git diff --diff-filter=d --name-only)\n
Run Code Online (Sandbox Code Playgroud)\n

存储未暂存和未跟踪的文件:

\n
git stash push --keep-index --include-untracked -- $(git ls-files --modified --others --exclude-standard)\n
Run Code Online (Sandbox Code Playgroud)\n

存储暂存/未暂存文件,同时还将暂存文件保留在索引中:

\n
git stash push --keep-index\n
Run Code Online (Sandbox Code Playgroud)\n

存储暂存/未暂存/未跟踪文件,同时还将暂存文件保留在索引中:

\n
git stash push --include-untracked --keep-index\n
Run Code Online (Sandbox Code Playgroud)\n

完整说明

\n

git stash push允许我们提供一个<pathspec>,并且只存储与其匹配的文件:

\n
git stash push -- <pathspec>\n
Run Code Online (Sandbox Code Playgroud)\n
\n

push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>\xe2\x80\xa6\xe2\x80\x8b]

\n

将本地修改保存到新的存储条目并将其回滚到 HEAD(在工作树和索引中)。该部分是可选的,并给出描述以及隐藏状态。

\n
\n
\n

<pathspec>\xe2\x80\xa6\xe2\x80\x8b

\n

该选项仅对push命令有效。

\n

新的存储条目仅记录与路径规范匹配的文件的修改状态。然后,索引条目和工作树文件也仅回滚到这些文件的 HEAD 中的状态,而使与路径规范不匹配的文件保持不变。

\n
\n
\n

-u, --include-untracked,--no-include-untracked

\n

当与pushsave命令一起使用时,所有未跟踪的文件也会被隐藏,然后用 清理git clean

\n
\n
\n

git diff允许我们列出当前未暂存的文件--name-only

\n
git diff --name-only\n
Run Code Online (Sandbox Code Playgroud)\n
\n

git diff [<options>] [--] [<path>\xe2\x80\xa6\xe2\x80\x8b]

\n

这个表单是查看你相对于索引(下一次提交的暂存区)所做的更改。

\n
\n
\n

--name-only

\n

仅显示已更改文件的名称。

\n
\n
\n

--diff-filter=\\[(A|C|D|M|R|T|U|X|B)\xe2\x80\xa6\xe2\x80\x8b\\[*\\]\\]

\n

仅选择已添加 ( A)、已复制 ( C)、已删除 ( D)、已修改 ( M)、已重命名 ( R) 且具有其类型的文件(即常规文件、符号链接、子模块、\xe2\x80\xa6\xe2\x80\x8b)已更改 ( T)、未合并 ( U)、未知 ( X) 或其配对已损坏 ( B)。可以使用过滤字符的任意组合(包括无)。

\n

此外,这些大写字母可以小写以排除。例如,--diff-filter=ad排除添加和删除的路径。

\n
\n
\n

git ls-files允许我们列出--modified文件和未跟踪的 ( --others) 文件:

\n
git ls-files --modified --others --exclude-standard\n
Run Code Online (Sandbox Code Playgroud)\n
\n

git-ls-files- 显示索引和工作树中文件的信息

\n
\n
\n

-m,--modified

\n

在输出中显示修改后的文件

\n
\n
\n

-o,--others

\n

在输出中显示其他(即未跟踪的)文件

\n
\n
\n

--exclude-standard

\n

添加标准 Git 排除:.git/info/exclude、每个目录中的 .gitignore 以及 user\xe2\x80\x99s 全局排除文件。

\n
\n

  • 完美的答案。谢谢@格伦 (2认同)

Cor*_*son 6

Git:隐藏未分级的更改

这将存储您没有git添加的所有修改:

git stash -k
Run Code Online (Sandbox Code Playgroud)

请注意,除非您也使用该-u开关,否则新创建(和未添加)的文件将保留在您的工作目录中。

git stash -k -u 
Run Code Online (Sandbox Code Playgroud)

另外,稍后您使用git stash pop时,您的工作目录必须干净(即,需要添加所有更改)。

http://makandracards.com/makandra/853-git-stash-unstaged-changes

  • 这相当于`git stash --keep-index`。暂存文件包含在隐藏文件中。 (11认同)