有没有办法让我把阶段性的变化藏起来?我遇到问题的情况是,我在给定的时间内处理了几个bug,并且有几个未分阶段的更改。我希望能够单独运行这些文件,创建我的.patch文件,并将它们保存起来,直到代码被批准。这样,当它被批准时,我可以隐藏我的整个(当前)会话,弹出错误并推送代码。
我做错了吗?我是否误解了git如何以其他方式简化我的过程?
有没有办法让我把阶段性的变化藏起来?我遇到问题的情况是,我在给定的时间内处理了几个bug,并且有几个未分阶段的更改。我希望能够单独运行这些文件,创建我的.patch文件,并将它们保存起来,直到代码被批准。这样,当它被批准时,我可以隐藏我的整个(当前)会话,弹出错误并推送代码。
我做错了吗?我是否误解了git如何以其他方式简化我的过程?
当前回答
是否绝对有必要同时处理多个bug ?这里的“立刻”指的是“同时对文件进行多个错误的编辑”。因为除非您绝对需要,否则我在您的环境中一次只处理一个错误。这样你就可以使用本地分支和重新建立基础,我发现这比管理复杂的存储/阶段要容易得多。
假设master在提交b,现在处理bug #1。
git checkout -b bug1
现在您在分支bug1上。做一些修改,提交,等待代码审查。这是本地的,所以你不会影响到其他人,而且从git差异中制作补丁应该很容易。
A-B < master
\
C < bug1
现在您正在处理bug2。用git checkout master返回master。创建一个新的分支,git checkout -b bug2。进行更改,提交,等待代码审查。
D < bug2
/
A-B < master
\
C < bug1
让我们假设在您等待审查时,其他人在master上提交了E & F。
D < bug2
/
A-B-E-F < master
\
C < bug1
当你的代码被批准后,你可以按照以下步骤将其重新设置为master:
git checkout bug1
git rebase master
git checkout master
git merge bug1
这将导致以下结果:
D < bug2
/
A-B-E-F-C' < master, bug1
然后你可以推送,删除你的本地bug1分支,然后你就可以走了。在您的工作空间中,一次只处理一个错误,但是通过使用本地分支,您的存储库可以处理多个错误。这样就避免了复杂的舞台舞蹈。
请在评论中回答ctote的问题:
那么,您可以回到为每个bug存储,并且一次只处理一个bug。至少这省去了分期问题。但尝试过之后,我个人觉得很麻烦。在git日志图中,存储有点混乱。更重要的是,如果你把事情搞砸了,你就无法挽回了。如果你有一个脏的工作目录,你弹出一个隐藏,你不能“撤消”这个弹出。搞砸已经存在的提交要困难得多。
那么,这就叫反应i。
当您将一个分支重新基于另一个分支时,您可以交互地进行(-i标志)。当您这样做时,您可以选择对每次提交做什么。Pro Git是一本很棒的书,它也是HTML格式的在线,并且有一个关于重基和压缩的不错的部分:
http://git-scm.com/book/ch6-4.html
为了方便起见,我将逐字逐句地引用他们的例子。假设你有以下提交历史记录,你想要将bug1重置并压缩到master上:
F < bug2
/
A-B-G-H < master
\
C-D-E < bug1
下面是当你输入git rebase -i master bug1时你会看到的结果
pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
#
# Commands:
# p, pick = use commit
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
要将一个分支的所有提交压缩为一次提交,请将第一次提交保留为“pick”,并将所有后续的“pick”条目替换为“squash”或简单的“s”。您还将有机会更改提交消息。
pick f7f3f6d changed my name a bit
s 310154e updated README formatting and added blame
s a5f4a0d added cat-file
#
# Commands:
# p, pick = use commit
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
所以,是的,压扁是有点痛苦,但我仍然建议它比大量使用存储。
其他回答
为什么不提交对某个错误的更改,并根据该提交及其前身创建一个补丁呢?
# hackhackhack, fix two unrelated bugs
git add -p # add hunks of first bug
git commit -m 'fix bug #123' # create commit #1
git add -p # add hunks of second bug
git commit -m 'fix bug #321' # create commit #2
然后,创建适当的补丁,使用git format-patch:
git format-patch HEAD^^
这将创建两个文件:0001-fix-bug-123。补丁和0002-fix-bug-321.patch
或者您可以为每个错误创建单独的分支,这样您就可以单独合并或重新建立错误修复,甚至在它们不起作用时删除它们。
要修剪意外的更改,特别是删除多个文件,请执行以下操作:
git add <stuff to keep> && git stash --keep-index && git stash drop
换句话说,把垃圾藏起来,把它们一起扔掉。
在git版本2.17.1中测试
您可以使用——staging来仅保存阶段性更改。
git stash --staged
文档:https://git-scm.com/docs/git-stash文档/ git-stash.txt-push-p——patch-S staged-k——no-keep-index-u include-untracked-a——all-q quiet-m——messageltmessagegt pathspec-from-fileltfilegt——pathspec-file-nul ltpathspecgt82308203
是否绝对有必要同时处理多个bug ?这里的“立刻”指的是“同时对文件进行多个错误的编辑”。因为除非您绝对需要,否则我在您的环境中一次只处理一个错误。这样你就可以使用本地分支和重新建立基础,我发现这比管理复杂的存储/阶段要容易得多。
假设master在提交b,现在处理bug #1。
git checkout -b bug1
现在您在分支bug1上。做一些修改,提交,等待代码审查。这是本地的,所以你不会影响到其他人,而且从git差异中制作补丁应该很容易。
A-B < master
\
C < bug1
现在您正在处理bug2。用git checkout master返回master。创建一个新的分支,git checkout -b bug2。进行更改,提交,等待代码审查。
D < bug2
/
A-B < master
\
C < bug1
让我们假设在您等待审查时,其他人在master上提交了E & F。
D < bug2
/
A-B-E-F < master
\
C < bug1
当你的代码被批准后,你可以按照以下步骤将其重新设置为master:
git checkout bug1
git rebase master
git checkout master
git merge bug1
这将导致以下结果:
D < bug2
/
A-B-E-F-C' < master, bug1
然后你可以推送,删除你的本地bug1分支,然后你就可以走了。在您的工作空间中,一次只处理一个错误,但是通过使用本地分支,您的存储库可以处理多个错误。这样就避免了复杂的舞台舞蹈。
请在评论中回答ctote的问题:
那么,您可以回到为每个bug存储,并且一次只处理一个bug。至少这省去了分期问题。但尝试过之后,我个人觉得很麻烦。在git日志图中,存储有点混乱。更重要的是,如果你把事情搞砸了,你就无法挽回了。如果你有一个脏的工作目录,你弹出一个隐藏,你不能“撤消”这个弹出。搞砸已经存在的提交要困难得多。
那么,这就叫反应i。
当您将一个分支重新基于另一个分支时,您可以交互地进行(-i标志)。当您这样做时,您可以选择对每次提交做什么。Pro Git是一本很棒的书,它也是HTML格式的在线,并且有一个关于重基和压缩的不错的部分:
http://git-scm.com/book/ch6-4.html
为了方便起见,我将逐字逐句地引用他们的例子。假设你有以下提交历史记录,你想要将bug1重置并压缩到master上:
F < bug2
/
A-B-G-H < master
\
C-D-E < bug1
下面是当你输入git rebase -i master bug1时你会看到的结果
pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
#
# Commands:
# p, pick = use commit
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
要将一个分支的所有提交压缩为一次提交,请将第一次提交保留为“pick”,并将所有后续的“pick”条目替换为“squash”或简单的“s”。您还将有机会更改提交消息。
pick f7f3f6d changed my name a bit
s 310154e updated README formatting and added blame
s a5f4a0d added cat-file
#
# Commands:
# p, pick = use commit
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
所以,是的,压扁是有点痛苦,但我仍然建议它比大量使用存储。
如果你没有一个更新的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
以前的收藏现在恢复了。