有没有办法让我把阶段性的变化藏起来?我遇到问题的情况是,我在给定的时间内处理了几个bug,并且有几个未分阶段的更改。我希望能够单独运行这些文件,创建我的.patch文件,并将它们保存起来,直到代码被批准。这样,当它被批准时,我可以隐藏我的整个(当前)会话,弹出错误并推送代码。

我做错了吗?我是否误解了git如何以其他方式简化我的过程?


当前回答

更新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.

对于相反的问题,只存储非分期的更改(别名存储工作),请参阅以下答案。

其他回答

为什么不提交对某个错误的更改,并根据该提交及其前身创建一个补丁呢?

# 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 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 ----------------------------------------------------------------

是否绝对有必要同时处理多个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

所以,是的,压扁是有点痛苦,但我仍然建议它比大量使用存储。

您可以使用——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

在这个场景中,我更喜欢为每个问题创建新的分支。我使用了一个前缀temp/,所以我知道我可以稍后删除这些分支。

git checkout -b temp/bug1

准备修复bug1的文件并提交它们。

git checkout -b temp/bug2

然后,您可以根据需要从相应的分支中选择提交,并提交一个拉取请求。