有没有办法让我把阶段性的变化藏起来?我遇到问题的情况是,我在给定的时间内处理了几个bug,并且有几个未分阶段的更改。我希望能够单独运行这些文件,创建我的.patch文件,并将它们保存起来,直到代码被批准。这样,当它被批准时,我可以隐藏我的整个(当前)会话,弹出错误并推送代码。
我做错了吗?我是否误解了git如何以其他方式简化我的过程?
有没有办法让我把阶段性的变化藏起来?我遇到问题的情况是,我在给定的时间内处理了几个bug,并且有几个未分阶段的更改。我希望能够单独运行这些文件,创建我的.patch文件,并将它们保存起来,直到代码被批准。这样,当它被批准时,我可以隐藏我的整个(当前)会话,弹出错误并推送代码。
我做错了吗?我是否误解了git如何以其他方式简化我的过程?
当前回答
我还没有见过这种不需要使用git stash的解决方案:
你甚至不需要使用git隐藏在所有。你可以使用一个专用的分支来解决这个问题(分支很便宜)。
实际上,你可以用几个连续的命令分别隔离非变化和阶段性变化,你可以把它们捆绑在一个git别名中:
创建并切换到一个新的分支,在那里你将分别提交阶段性和非阶段性的更改:参见这里
在任何时候,你都可以从创建的分支中选择-e一个提交,并将其应用到你想要的地方(-e更改其提交消息)。
当你不再需要它时,你可以删除这个“收藏分支”。你可能不得不使用-D选项来强制删除(而不是-D普通选项),因为该分支没有合并,git可能会认为如果你删除它会有丢失数据的风险。如果你没有选择删除前的提交,这是正确的:
git branch -D separated-stashes
您还可以为~/添加别名。Gitconfig,以便自动化此行为:
git config --global alias.bratisla '!git switch -c separated-stashes; git commit -m "staged changes"; git add -u; git commit -m "unstaged changes"; git switch -' # why this name ? : youtu.be/LpE1bJp8-4w
在“藏” 在“藏”
当然,您也可以使用两个连续的存储来实现相同的结果
正如在其他答案中所述,您可以使用git stash (-k|——keep-index)与其他命令组合使用一些方法来仅保存非阶段性或仅阶段性的更改。
我个人认为-k选项非常令人困惑,因为它存储了所有内容,但将阶段性更改保持在阶段性状态(这解释了为什么使用“——keep-index”)。而储存东西通常会把它移动到一个储存入口。使用-k,非暂存的更改通常会被存储,但暂存的更改只是复制到相同的暂存条目。
第0步:你的git状态中有两个东西:一个包含阶段性变化的文件,另一个包含非阶段性变化的文件。
第一步:保存非阶段性+阶段性变化,但将阶段性变化保留在索引中:
git stash -k -m "all changes"
-m "…"部分是可选的,git stash -k实际上是git stash push -k的别名(它不会远程推送任何东西,顺便说一句,不用担心),它接受一个-m选项来标记你的stash条目,以使其清晰(就像一个提交消息或标签,但对于一个stash条目)。它是已弃用的git存储保存的新版本。
步骤1bis(可选):
git stash
隐藏阶段性更改(仍在索引中)。 这一步对于下面的内容不是必需的,但是它表明,如果您愿意,您可以只将阶段性的更改放在存储条目中。 如果你使用这一行,你必须在继续第二步之前git stash (pop|apply) && git add -u。
第二步:
git commit -m "staged changes"
提交只包含从步骤0开始的阶段性更改,它包含与步骤1bis开始的隐藏条目相同的内容。
第三步:
git stash (pop|apply)
恢复第1步的存储。 注意,这个隐藏条目包含了所有内容,但是由于您已经提交了阶段性更改,所以这个隐藏只会添加从第0步开始的非阶段性更改。
注意:这里的“restore”并不是指“git restore”,这是一个不同的命令。
第四步:
git add -u
将弹出的存储的内容添加到索引中
第五步:
git commit -m "unstaged changes"
这里的“未分期”,与步骤2和步骤3注释中的“分期”一样,指的是步骤0。实际上,您正在登台并提交从步骤0开始的“登台更改”。
完成了! 您现在有两个独立的提交,其中包含从第0步开始的(un)阶段性更改。 您可能希望修改/重新设置它们以进行其他更改或重命名/删除/压缩它们。 取决于你对你的stash的堆栈做了什么(弹出或应用),你可能还想要git stash (drop|clear)它。你可以看到你用git stash (list|show)
其他回答
为了达到同样的目的…
只准备您想要处理的文件。 Git提交-m 'temp' Git添加。 git藏 git重置头~1
繁荣。你不想要的文件都被藏起来了。您要的文件都准备好了。
在Git 2.35 (Q1 2022)中,“Git stash”(man)学会了——staging选项来隐藏添加到索引中的内容(而不是其他内容)。
所以现在这是官方支持的(8年后)。
参见Sergey Organov (sorganov)的commit a8a6e06(2021年10月28日)和commit 41a28eb(2021年10月18日)。 (由Junio C Hamano—gitster—在commit 44ac8fd中合并,2021年11月29日)
Stash:为“推送”和“保存”执行“——staging”选项 署名:Sergey Organov
只保存已上演的更改。 这种模式允许轻松地隐藏一些与当前正在进行的工作无关的更改,以便以后重用。 与'stash push -patch'不同,- staging支持使用任何工具来选择要存储的更改,包括但不限于'git add -interactive'(man)。
Git stash现在包括在它的手册页:
“git藏”[推动[p |——补丁][s |——上演][- k |——[不——]keep-index] [q |——安静)
Git stash现在包括在它的手册页:
保存[- p |——补丁][s |——上演][- k |——[不——]keep-index] [- u |——include-untracked][——|——所有][q |——安静][<消息>]
Git stash现在包括在它的手册页:
- s ——上演了 此选项仅对推送和保存命令有效。 只保存当前暂存的更改。这类似于 基本的git提交,除了状态被提交到stash 当前分支的。 ——patch选项优先于此选项。
Git stash现在包括在它的手册页:
Saving unrelated changes for future use When you are in the middle of massive changes and you find some unrelated issue that you don't want to forget to fix, you can do the change(s), stage them, and use git stash push --staged to stash them out for future use. This is similar to committing the staged changes, only the commit ends-up being in the stash and not on the current branch. ---------------------------------------------------------------- # ... hack hack hack ... $ git add --patch foo # add unrelated changes to the index $ git stash push --staged # save these changes to the stash # ... hack hack hack, finish curent changes ... $ git commit -m 'Massive' # commit fully tested changes $ git switch fixup-branch # switch to another branch $ git stash pop # to finish work on the saved changes ----------------------------------------------------------------
如果你没有一个更新的git,它有——staging选项,下面是如何直接做到这一点。
git stash命令只是一个复杂的shell脚本,用于操作树对象和提交等。我们可以手动完成它所做的事情。
概述
隐藏堆栈记录特殊的提交。我们将从阶段性更改中创建一个提交,然后手动将其转移到存储中。然后,取消提交。
设置
我有一个项目,其中Makefile有两个更改。一个是有舞台的,一个是没有舞台的:
$ git diff --cached
diff --git a/Makefile b/Makefile
index 4ca6058f..c8c7480a 100644
--- a/Makefile
+++ b/Makefile
@@ -605,7 +605,7 @@ conftest2: conftest1.c conftest2.c
$(V)if echo | $(CC) -dM -E - | grep -s __ANDROID__ > /dev/null 2>&1 ; then \
echo yes ; \
fi
-
+# FOO
.PHONY: conftest.clean
conftest.clean:
$(V)rm -f conftest$(EXE) conftest.[co] \
$ git diff
diff --git a/Makefile b/Makefile
index c8c7480a..270c313d 100644
--- a/Makefile
+++ b/Makefile
@@ -611,3 +611,4 @@ conftest2: conftest1.c conftest2.c
$(V)rm -f conftest$(EXE) conftest.[co] \
conftest2$(EXE) conftest[12].[oc] \
conftest.err
+# BAR
添加# FOO行是阶段性的;# BAR的添加是无阶段的。
步骤1:创建树对象。
首先,我们从当前索引(包含分段项)创建一个树对象。
$ git write-tree
0d9651ad74328e747a053a9434d9867c8cd79d41 <-- output
步骤2:创建两次提交。
首先,从树中创建一个提交,它有一个父结点,即当前分支HEAD:
$ git commit-tree -p HEAD -m 'add # FOO' 0d9651ad74328e747a053a9434d9867c8cd79d41
baa34222e781078d82cefed519ff105715c7f665 <-- output
然后,从树中创建另一个提交,它有两个父节点:HEAD和baa34222…我们刚刚做出的承诺:
$ git commit-tree -p HEAD -p baa34222e781078d82cefed519ff105715c7f665 -m 'add # FOO' 0d9651ad74328e747a053a9434d9867c8cd79d41
2c96b028e475a05d84f472da7f2a70ac53d0ac90 <-- output
这个双亲2c96b02…将是我们安装到隐藏的提交。
注意,git commit-tree不是git commit。这是一个低级别的命令。这些提交不会对当前分支做任何事情;我们只是在Git的存储中分配对象,并没有对我们所在的分支做任何事情,也没有改变索引或工作树。
步骤3。
接下来,我们将这个提交写到.git/refs/stash中。你可能需要备份这个文件。
$ echo 2c96b028e475a05d84f472da7f2a70ac53d0ac90 > .git/refs/stash
步骤4。
我们将同样的提交钩子到.git/logs/refs/stash文件中。在编辑之前,文件中的最后一行看起来是这样的:
b1819d98ab24720796315b9497236172d1fb1f5f 3b2ecc6604d77c9df4fe72efd1fbd384b2c43f76 Au Thor <author@example.com> 1654892876 -0700 On master: elim-aliases
我们手动添加这条伪行:
3b2ecc6604d77c9df4fe72efd1fbd384b2c43f76 2c96b028e475a05d84f472da7f2a70ac53d0ac90 Au Thor <author@example.com> 1654892876 -0700 On master: add # FOO
您可能还想备份此文件。然而,如果出了问题,事情很容易恢复。
注意左边哈希3b2ecc…在这个新行中与前一行中的右哈希相同。这是之前的存储提交,与我们在这里所做的无关,必须重复将这一行链接到存储堆栈中。在它的右边,我们有我们的散列2c96b028e4....然后剩下的人都假装离开了。在时区-0700后面有一个硬选项卡,而不是空格。我只是复制粘贴了一下。
第5步。
我们验证我们已经将commit添加到存储堆栈:
$ git stash list | head -3
stash@{0}: On master: add # FOO
stash@{1}: On master: elim-aliases
stash@{2}: On master: compiler-safe-eval
and:
$ git stash show -p
diff --git a/Makefile b/Makefile
index 4ca6058f..c8c7480a 100644
--- a/Makefile
+++ b/Makefile
@@ -605,7 +605,7 @@ conftest2: conftest1.c conftest2.c
$(V)if echo | $(CC) -dM -E - | grep -s __ANDROID__ > /dev/null 2>&1 ; then \
echo yes ; \
fi
-
+# FOO
.PHONY: conftest.clean
conftest.clean:
$(V)rm -f conftest$(EXE) conftest.[co] \
它在那里;Git stash认为我们的提交是一个“类仓库”的提交,并接受它。
总结
我们手动获取一个分阶段更改的索引,并生成一个树对象。 然后,我们将树对象转换为常规提交对象,然后再进行一个双亲提交。双父对象作为类存储提交是可以接受的。 最后,我们通过编辑一对文件手动将这个提交修补到存储堆栈中。
附录
我们没有执行任何操作索引或工作树的不安全命令。但是,我们已经不安全地操作了git存储堆栈。如果出现问题,以下是如何修复它(而不是从备份文件恢复):
删除我们添加到.git/logs/refs/stash的伪行,这样这仍然是最后一行: b1819d98ab24720796315b9497236172d1fb1f5f 3b2ecc6604d77c9df4fe72efd1fbd384b2c43f76 Au Thor <author@example.com> 1654892876 -0700 On master: elime -aliases 取右边的散列3b2ecc6604d77c9df4fe72efd1fbd384b2c43f76并将其植入到.git/refs/stash文件中: $ echo 3b2ecc6604d77c9df4fe72efd1fbd384b2c43f76 > .git/refs/stash
以前的收藏现在恢复了。
这个回答被接受了,但太老了。现在你可以把它藏起来-S见https://stackoverflow.com/a/70231955/683157
最初的回答: 是的,这是可能的DOUBLE STASH
准备好你需要藏匿的所有文件。 运行git stash——keep-index。这个命令将创建一个包含所有更改(阶段性和非阶段性)的存储,但是将阶段性更改保留在工作目录中(仍然处于阶段性状态)。 运行git stash push -m "good stash"(添加-u标志以在stash中包含新文件) 现在你的“好收藏”只有阶段性文件。
现在,如果你需要非暂存文件在stash之前,只需应用第一个stash(一个创建的——keep-index),现在你可以删除文件,你储存到“良好的stash”。
享受
更新2022年1月:Git 2.35已经发布,stash现在支持——staging参数。因此,这个答案在Git 2.35+中已经过时了。参见vonc的回答:https://stackoverflow.com/a/70231955/430128。
旧的回答:
在Git中仅存储索引(分阶段更改)比想象中要困难得多。我发现@Joe的答案工作得很好,并把它的一个小变化变成了这个别名:
stash-index = "!f() { \
! git diff --cached --exit-code --quiet && \
git stash push --quiet --keep-index -m \"temp for stash-index\" && \
git stash push \"$@\" && \
git stash pop --quiet stash@{1} && \
git stash show -p | git apply -R; }; f"
It:
Validates that there are actually staged changes (git diff --cached --exit-code returns a non-zero status if there are). HT: @nandilugio It pushes both the staged and unstaged changes into a temporary stash, leaving the staged changes alone. It then pushes the staged changes into the stash, which is the stash we want to keep. Arguments passed to the alias, such as --message "whatever" will be added to this stash command. It pops the temporary stash to restore the original state and remove the temporary stash, and then Finally "removes" the stashed changes from the working directory via a reverse patch application.
对于相反的问题,只存储非分期的更改(别名存储工作),请参阅以下答案。