有什么办法可以隐瞒我分阶段进行的更改?我遇到的情况是我在给定的时间处理了多个错误,并进行了一些未分级的更改。我希望能够分别暂存这些文件,创建我的.patch文件,并将其存放起来,直到代码获得批准为止。这样,当批准时,我可以隐藏整个(当前)会话,弹出该错误并推送代码。
我会以错误的方式处理吗?我是否误解了git如何以其他方式简化我的流程?
有什么办法可以隐瞒我分阶段进行的更改?我遇到的情况是我在给定的时间处理了多个错误,并进行了一些未分级的更改。我希望能够分别暂存这些文件,创建我的.patch文件,并将其存放起来,直到代码获得批准为止。这样,当批准时,我可以隐藏整个(当前)会话,弹出该错误并推送代码。
我会以错误的方式处理吗?我是否误解了git如何以其他方式简化我的流程?
Answers:
是的,DOUBLE STASH有可能
git stash --keep-index
。此命令将创建包含所有更改(暂存和未暂存)的存储,但是会将暂存的更改保留在工作目录中(仍处于暂存状态)。git stash push -m "good stash"
"good stash"
已经ONLY上演文件。现在,如果您需要在存储之前未暂存的文件,只需应用第一个存储(用创建的--keep-index
存储),现在就可以删除存储到的文件"good stash"
。
请享用
-u
开关。
git stash apply --index
选项感兴趣。这将尝试保持您的(暂存)状态。现在可以更轻松地从工作树中删除不需要的更改。
在最新的git中,您可以使用--patch
option
git stash push --patch
git stash save --patch # for older git versions
git会要求您对文件中的每个更改进行添加或不添加到存储中。
您只要回答y
或n
UPD
别名的双重存储:
git config --global alias.stash-staged '!bash -c "git stash --keep-index; git stash push -m "staged" --keep-index; git stash pop stash@{1}"'
现在您可以暂存文件,然后运行git stash-staged
。
结果,您暂存的文件将被保存到stash中。
如果您不希望保留暂存的文件并将其移到存储中。然后,您可以添加另一个别名并运行git move-staged
:
git config --global alias.move-staged '!bash -c "git stash-staged;git commit -m "temp"; git stash; git reset --hard HEAD^; git stash pop"'
-u|--include-untracked
git-stash
我编写了一个脚本,该脚本仅存储当前正在上演的内容,并保留其他所有内容。当我开始进行太多无关的更改时,这真棒。只需暂存与所需提交无关的内容,然后隐藏即可。
(感谢Bartłomiej为起点)
#!/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}
TL; DR只需
-- $(git diff --staged --name-only)
为您的git<pathspec>
参数添加
git stash -- $(git diff --staged --name-only)
并简单地添加一条消息:
git stash push -m "My work in progress" -- $(git diff --staged --name-only)
在v2.17.1和v2.21.0.windows.1上测试
局限性:
- 请注意,如果您没有暂存文件,则这将隐藏每件事。
- 同样,如果您的文件只是部分暂存(即,仅某些更改的行已暂存,而其他某些更改的行未暂存),则整个文件将被保存(包括未暂存的行)。
在这种情况下,我更愿意为每个问题创建新的分支。我使用前缀temp /,所以我知道以后可以删除这些分支。
git checkout -b temp/bug1
暂存修复bug1的文件并提交。
git checkout -b temp/bug2
然后,您可以根据需要从各个分支中挑选提交并提交拉取请求。
您为什么不提交针对某个错误的更改,并根据该提交及其前身创建补丁?
# 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.patch
和0002-fix-bug-321.patch
或者,您可以为每个错误创建单独的分支,以便可以单独合并或调整错误修复的基础,如果无法解决,则可以删除它们。
git stash --keep-index
是一个很好的解决方案...除了在已删除的路径上无法正常工作外,该路径已在Git 2.23(2019年第三季度)中修复
参见Thomas Gummerer()的commit b932f6a(2019年7月16日)。(由Junio C Hamano合并--在commit f8aee85中,2019年7月25日)tgummerer
gitster
stash
:修复处理带有--keep-index
git stash push --keep-index
应该保留所有已添加到索引的更改,无论是在索引中还是在磁盘上。当前,当从索引中删除文件时,这不能正常工作。
**-keep-index当前会还原文件,而不是将其保留在磁盘上。**通过
git checkout
在无覆盖模式下使用' ' 来修复该问题,该模式可以忠实地还原索引和工作树。
这也简化了代码。请注意,如果未跟踪的文件与在索引中已删除的文件具有相同的名称,则这将覆盖未跟踪的文件。
仅在Git中存储索引(分阶段的更改)比应有的困难。我发现@Joe的答案可以正常工作,并将它的一个很小的变化变成了这个别名:
stash-index = "!f() { \
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"
它会将已分阶段和未分阶段的更改都推入临时存储区,仅保留已分阶段的更改。然后,它将分段的更改推入存储区,这是我们要保留的存储区。传递给别名的参数,例如--message "whatever"
将添加到此存储命令。最后,它弹出临时存储库以恢复原始状态并删除临时存储库,然后最后通过反向修补程序从工作目录中“删除”隐藏的更改。
对于仅存储未分段的更改(别名stash-working
)的相反问题,请参见此答案。
绝对需要一次处理多个错误吗?“一次”是指“同时编辑多个错误的文件”。因为除非您绝对需要,否则我一次只能在您的环境中处理一个错误。这样,您可以使用本地分支和重新设置基准,这比管理复杂的存储/阶段要容易得多。
假设master在提交B处。现在处理错误#1。
git checkout -b bug1
现在,您正在使用分支bug1。进行一些更改,提交,等待代码审查。这是本地的,因此您不会影响其他任何人,并且应该很容易从git diffs制作补丁。
A-B < master
\
C < bug1
现在,您正在研究bug2。去背到主用git checkout master
。新建一个分支git checkout -b bug2
。进行更改,提交,等待代码审查。
D < bug2
/
A-B < master
\
C < bug1
假设您在等待审查时,其他人在master上提交了E&F。
D < bug2
/
A-B-E-F < master
\
C < bug1
批准代码后,可以通过以下步骤将其重新建立为掌握代码的基础:
git checkout bug1
git rebase master
git checkout master
git merge bug1
这将导致以下结果:
D < bug2
/
A-B-E-F-C' < master, bug1
然后,您可以推送,删除本地bug1分支,然后退出。您的工作空间中一次只能出现一个错误,但是通过使用本地分支,您的存储库可以处理多个错误。并且这避免了复杂的舞台/隐藏舞蹈。
在评论中回答ctote的问题:
好了,您可以针对每个错误返回存储,并且一次只能处理一个错误。Atleast为您节省了分期问题。但是尝试过此之后,我个人觉得很麻烦。git日志图中的散乱有点混乱。更重要的是,如果您搞砸了,您将无法还原。如果您的工作目录很脏并且弹出存储,则无法“撤消”该弹出窗口。搞砸已经存在的提交要困难得多。
这样git rebase -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 checkout master; git checkout -b bug2
可以缩短为git checkout -b bug2 master
。同样适用于git checkout bug1; git rebase master; git checkout master; git merge bug1
,它等同于git rebase master bug1; git push . bug1:master
(授予,push
技巧并不明显)
在对Mike Monkiewicz回答的评论中,我建议使用一个更简单的模型:使用常规开发分支,但使用merge的squash选项在您的master分支中获得单个提交:
git checkout -b bug1 # create the development branch
* hack hack hack * # do some work
git commit
* hack hack hack *
git commit
* hack hack hack *
git commit
* hack hack hack *
git commit
git checkout master # go back to the master branch
git merge --squash bug1 # merge the work back
git commit # commit the merge (don't forget
# to change the default commit message)
git branch -D bug1 # remove the development branch
此过程的优点是您可以使用正常的git工作流程。
TL; DR ;
git stash-staged
创建别名后:
git config --global alias.stash-staged '!bash -c "git stash -- \$(git diff --staged --name-only)"'
这里git diff
返回--staged
文件列表,--name-only
然后我们将此列表传递pathspec
给git stash
逗号。
来自man git stash
:
git stash [--] [<pathspec>...]
<pathspec>...
The new stash entry records the modified states only for the files
that match the pathspec. The index entries and working tree
files are then rolled back to the state in HEAD only for these
files, too, leaving files that do not match the pathspec intact.