有没有办法让我把阶段性的变化藏起来?我遇到问题的情况是,我在给定的时间内处理了几个bug,并且有几个未分阶段的更改。我希望能够单独运行这些文件,创建我的.patch文件,并将它们保存起来,直到代码被批准。这样,当它被批准时,我可以隐藏我的整个(当前)会话,弹出错误并推送代码。
我做错了吗?我是否误解了git如何以其他方式简化我的过程?
有没有办法让我把阶段性的变化藏起来?我遇到问题的情况是,我在给定的时间内处理了几个bug,并且有几个未分阶段的更改。我希望能够单独运行这些文件,创建我的.patch文件,并将它们保存起来,直到代码被批准。这样,当它被批准时,我可以隐藏我的整个(当前)会话,弹出错误并推送代码。
我做错了吗?我是否误解了git如何以其他方式简化我的过程?
当前回答
我制作了一个脚本,只存储当前正在上演的内容,并保留其他所有内容。当我开始做太多不相关的改变时,这是非常棒的。简单地暂存与所需的提交和存储无关的内容。
(感谢bartjoomiej提供的起点)
#!/bin/bash
#Stash everything temporarily. Keep staged files, discard everything else after stashing.
git stash --keep-index
#Stash everything that remains (only the staged files should remain) This is the stash we want to keep, so give it a name.
git stash save "$1"
#Apply the original stash to get us back to where we started.
git stash apply stash@{1}
#Create a temporary patch to reverse the originally staged changes and apply it
git stash show -p | git apply -R
#Delete the temporary stash
git stash drop stash@{1}
其他回答
我还没有见过这种不需要使用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)
在这个场景中,我更喜欢为每个问题创建新的分支。我使用了一个前缀temp/,所以我知道我可以稍后删除这些分支。
git checkout -b temp/bug1
准备修复bug1的文件并提交它们。
git checkout -b temp/bug2
然后,您可以根据需要从相应的分支中选择提交,并提交一个拉取请求。
我制作了一个脚本,只存储当前正在上演的内容,并保留其他所有内容。当我开始做太多不相关的改变时,这是非常棒的。简单地暂存与所需的提交和存储无关的内容。
(感谢bartjoomiej提供的起点)
#!/bin/bash
#Stash everything temporarily. Keep staged files, discard everything else after stashing.
git stash --keep-index
#Stash everything that remains (only the staged files should remain) This is the stash we want to keep, so give it a name.
git stash save "$1"
#Apply the original stash to get us back to where we started.
git stash apply stash@{1}
#Create a temporary patch to reverse the originally staged changes and apply it
git stash show -p | git apply -R
#Delete the temporary stash
git stash drop stash@{1}
为了达到同样的目的…
只准备您想要处理的文件。 Git提交-m 'temp' Git添加。 git藏 git重置头~1
繁荣。你不想要的文件都被藏起来了。您要的文件都准备好了。
如果你没有一个更新的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
以前的收藏现在恢复了。