Git stash uncached:如何存放所有未暂存的更改?

Posted

技术标签:

【中文标题】Git stash uncached:如何存放所有未暂存的更改?【英文标题】:Git stash uncached: how to put away all unstaged changes? 【发布时间】:2013-11-30 11:09:54 【问题描述】:

假设在一个由 git 版本控制的项目中进行了两组更改。一组已上演,另一组未上演。

我想通过在此状态下(提交前)运行我的项目来重新检查分阶段的更改。 有什么简单的方法可以存放所有未暂存的更改并只保留已暂存的更改?所以我需要未暂存的更改从我的项目中消失,但要存储在某个地方以供进一步工作。

这听起来很像git stash 命令。但是git stash 会将非分阶段和分阶段的更改从我的项目中移除。而且我找不到像git stash uncached 这样的东西。

【问题讨论】:

到今天我的 git 2.21 仍然没有一个好的答案。以下所有答案要么不正确(-k 选项)要么使用起来很麻烦。 【参考方案1】:

更新 2: 我不确定为什么人们抱怨这个答案,它似乎与我完美配合,对于未处理的文件,您可以添加 -u 标志

完整的命令变成git stash --keep-index -u

这是来自git-stash帮助的sn-p

如果使用 --keep-index 选项,则所有更改都已添加到 索引保持不变。

如果使用了 --include-untracked 选项,所有未跟踪的文件都会被 还藏起来,然后用 git clean 清理,留下工作 目录处于非常干净的状态。如果改为使用 --all 选项 然后除了 未跟踪的文件。

这是它外观的 gif:

更新:

尽管这是选择的答案,但很多人指出[下面的答案](https://***.com/a/34681302/292408) 是正确的,我建议检查一下。

我今天(2020 年 1 月 31 日)针对 git 版本 2.24.0 再次测试了我的答案,我仍然相信它是正确的,我在上面添加了一个关于未跟踪文件的小注释。 如果您认为它不起作用,请同时提及您的 git 版本。

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

git stash --keep-index

来自documentation of 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'

但是,如果您只想直观地检查阶段性更改,您可以尝试difftool

git difftool --cached

【讨论】:

另见git stash [-p|--patch],感觉就像交互式存储。来自man git stash "使用 --patch,您可以交互地从 HEAD 和工作树之间的差异中选择要隐藏的块。" 我通常add -pcheckout -preset -p,从未尝试过stash -p,感谢您的提示:D 请注意,此答案还将隐藏您已暂存的更改。 这个答案并不是很有用,因为它会导致混乱。这个答案更好***.com/a/34681302/292408。 @ElijahLynn 我已经链接到另一个答案,因为我发现很多人说这是更好的答案,感谢您的评论【参考方案2】:

正如一些人指出的那样,公认的答案还隐藏了阶段性更改。这是一种无需在存储中进行分阶段更改的方法。

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

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

# -u option so you also stash untracked files
$ git stash -u

# now un-commit your WIP commit:
$ git reset --soft HEAD^

此时,您将存储未暂存的更改,并且只会将暂存的更改存在于您的工作副本中。

【讨论】:

这确实是 IMO 的正确答案。当前接受的答案中的 --keep-index 选项仍然存储索引中的内容,它只是 将其保留在索引中。所以它被复制了,随之而来的是欢闹。 @KenWilliams hilarity 悲剧 这是迄今为止最好的答案,因为已接受答案中的 --keep-index 选项具有误导性。这应该是公认的答案。 @PengheGeng 你可以运行git commit--no-verify 来禁用这个特定提交的提交钩子【参考方案3】:

我发现标记的答案对我不起作用,因为我需要一些真正隐藏我未暂存更改的东西。标记的答案git stash --keep-index 隐藏了分阶段和非分阶段的更改。 --keep-index 部分只是在工作副本上保持索引完好无损。这适用于 OP,但这只是因为他提出的问题与他实际想要的答案略有不同。

我发现存储未暂存更改的唯一真正方法是根本不使用存储:

git diff > unstaged.diff
git apply -R unstaged.diff

git checkout -- . 也可以代替 apply -R

工作工作工作......

git apply unstaged.diff
rm unstaged.diff

【讨论】:

这里在git version 2.6.1.windows.1git stash -k 按描述工作。 这应该是公认的答案!它是多个 *** 线程中唯一一个执行它声称的操作而不依赖于临时提交的线程! @user643011:临时提交在 git 中并不是一件坏事。它们不花钱,也不会伤害任何人。 @Fritz:在某些情况下不可能进行临时提交。如果您有一个检查当前工作代码的预提交挂钩,它可能会失败。如果您的分阶段更改很好,但您的未分阶段更改不是,则此方法将无法提交分阶段更改。 这不包括未跟踪的文件。您需要使用“git ls-files”在差异补丁中查找并包含这些文件【参考方案4】:

Git:存储未暂存的更改

这将隐藏你没有 git add 的所有修改:

git stash -k

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

git stash -k -u 

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

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

【讨论】:

这相当于git stash --keep-index。暂存文件包含在存储中。【参考方案5】:

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

tl;博士

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

git diff --staged --diff-filter=d --name-only

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

git diff --diff-filter=d --name-only

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

git ls-files --modified --others --exclude-standard

仅存储暂存文件(最初来自 this *** answer,但略有调整):

git stash push --include-untracked -- $(git diff --staged --diff-filter=d --name-only)

仅存放未暂存(未跟踪)的文件:

git stash push --keep-index -- $(git diff --diff-filter=d --name-only)

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

git stash push --keep-index --include-untracked -- $(git ls-files --modified --others --exclude-standard)

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

git stash push --keep-index

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

git stash push --include-untracked --keep-index

完整说明

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

git stash push -- <pathspec>

push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message &lt;message&gt;] [--pathspec-from-file=&lt;file&gt; [--pathspec-file-nul]] [--] [&lt;pathspec&gt;…​]

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

&lt;pathspec&gt;…​

此选项仅对push 命令有效。

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

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

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


git diff 允许我们使用--name-only 列出currently unstaged files:

git diff --name-only

git diff [&lt;options&gt;] [--] [&lt;path&gt;…​]

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

--name-only

仅显示更改文件的名称。

--diff-filter=\[(A|C|D|M|R|T|U|X|B)…​\[*\]\]

仅选择添加 (A)、复制 (C)、删除 (D)、修改 (M)、重命名 (R)、它们的类型(即常规文件、符号链接、子模块......可以使用过滤字符的任意组合(包括无)。

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


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

git ls-files --modified --others --exclude-standard

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

-m, --modified

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

-o, --others

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

--exclude-standard

添加标准的 Git 排除:.git/info/exclude,每个目录中的 .gitignore,以及用户的全局排除文件。

【讨论】:

【参考方案6】:

这里有一个非常简单的方法:

    将下面的别名定义添加到您的.zshrc.bashrc.bash_profile 现在,任何时候遇到这种情况,只需输入 gss,您就会有 2 个存储 - 1 个包含所有更改,另一个仅包含分阶段更改

因此,您现在可以应用分阶段的更改,看看它们是否有效,如果需要,提交它们。然后,稍后您还可以通过应用“所有 WIP”存储来引入未​​暂存的更改并进行尝试。

alias gsts='git stash save'
alias gsv="git stash save --keep-index"

# How to Git Stash preserving staged/unstaged situation.
# 1. gsv will stash all and reset (remove) the unstaged, leaving only staged in staged state.
# 2. gsts will make a stash with your "good" (staged) files
alias gss='gsv all WIP && gsts staged WIP'

【讨论】:

以上是关于Git stash uncached:如何存放所有未暂存的更改?的主要内容,如果未能解决你的问题,请参考以下文章

GitHub Desktop 的“放弃所有更改”的 Git 等效项(虽然不是 git stash)[重复]

如何查看git stash内容

git stash

未commit 执行git stash后怎么恢复

git stash pop 冲突怎么解决?

git放弃本地所有修改