GIT 从当前 HEAD 中删除特定提交的更改



假设

我最近在索引中添加或未添加更改。现在我正在挑选一个特定的提交,而无需在我的 HEAD 上创建新的提交......

git cherry-pick -n <commit>

如何从索引中删除精选更改?我可以做一个

git reset HEAD

但我必须重做之前添加的所有更改。


目的

如果一个人进行藏匿,则藏匿不能推送到遥控器。无法从另一个系统上的远程设备中提取当前 WIP。所以我写了 shell 函数来模拟 git-stash,除了我为每个存储使用分支。

applypop通常会将隐藏的更改应用于 WIP,而不是当前索引。当我使用樱桃选择来应用来自存储分支的更改时,所有这些更改都将添加到索引中,之后我需要将它们从索引中删除。


编辑 (2018-01-29)

我读了@torek的安斯瓦并理解了它。尽管如此,我喜欢分享我以前已经使用过的 bash 功能。

function git-stash {
local gitbranch="$( git branch | grep * )"
local currentbranch="$( [ "${gitbranch}" == "* (HEAD"* ] && echo "${gitbranch}" | cut -d ' ' -f5 | cut -d ')' -f1 || echo "${gitbranch}" | cut -d ' ' -f2- )"
local stashname="stash/$( date +%s )"
git stash save -u ${stashname}
git checkout -b ${stashname}
git stash pop
git add .
[ ${1} ] && git commit -m "WIP: "$1 || git commit -m "WIP"
git checkout ${currentbranch}
}
function git-stash-apply {
local stashbranches="$( git branch | grep stash/ | cut -d ' ' -f3- | sort -r )"
local stashbranches=(${stashbranches[@]})
local lateststashbranch="${stashbranches[0]}"
git cherry-pick -n "${lateststashbranch}"
}
function git-stash-pop {
local stashbranches="$( git branch | grep stash/ | cut -d ' ' -f3- | sort -r )"
local stashbranches=(${stashbranches[@]})
local lateststashbranch="${stashbranches[0]}"
git cherry-pick -n "${lateststashbranch}"
git branch -D "${lateststashbranch}"
git push origin :"${lateststashbranch}"
}

这还不是一个合适的解决方案,更不用说stash pop中缺少的错误处理了。

眼前的问题

在这种特殊情况下,您可以尝试git revert -n <commit>,这与反向应用这些更改基本相同。 不过,一般来说,这不是一个可逆的操作,首先完成git cherry-pick -n是不明智的。

例如,考虑如果增量计算者

git diff $commit^ $commit

git cherry-pick $commit应该在README中添加一行,从f1.txt中删除一行,并在f2.txt中更改一行("更改"暗示为删除旧添加新,真的)。

但是,如果您已经将该行添加到README并对f2.txt进行了更改,则实际运行樱桃选择只会修改f1.txt。 (发生这种情况是因为 Git 使用其合并机制,该机制会发现您的更改及其更改重叠,从而减少重叠。 如果你现在决定撤消樱桃采摘并运行git revert -n $commit,Git 将通过从README中删除该行、将行添加回f1.txt并在f2.txt中恢复原始行来撤消它。 Git不会知道合并操作将这三个更改中的两个删除为"已经到位",并且会撤消所有三个更改。

更普遍的问题

如果一个人进行藏匿,则藏匿不能推送到遥控器。

这并不完全正确(但也不完全错误)。git stash所做的是进行两次或有时三次提交,其中没有一个在分支上:一个存储当前索引,一个存储当前工作树(但仅适用于当前索引中的文件)。 如果第三次提交存在,它将存储未跟踪的文件减去忽略的文件,或未跟踪的文件,包括忽略的文件。

提交被安排为工作树提交是最后一个提交,并将其他两个(加上当前提交)作为其父级。 然后,最终提交的哈希 ID 使用git update-ref"推送到"存储堆栈中。

因为这些是提交,所以可以git push编辑。 但是,您必须在遥控器上为它们发明一个名称,遥控器将允许您设置该名称。refs/stash名称通常不可写。 例如:

git push fred stash:refs/heads/sneaky

将使用refs/stash在远程fred上创建分支名称sneaky

可以如上所述以其他名称发送提交,然后 - 通过登录到另一个系统 - 如果您想这样做,将它们偷运到refs/stash名称中。 不过,您甚至不必这样做,因为git stash apply等将采用解析为"类似存储"提交的任何标识符(特别是工作树提交,如果存储是两个提交实体,则有两个父项,如果存储是三个提交实体,则有三个父项):

fred$ git stash apply sneaky

如果一切顺利并且您不再想要这个,那么您可以强制删除分支:

fred$ git branch -D sneaky

另一个技术说明

applypop通常会将隐藏的更改应用于 WIP,但不会应用于当前索引。

这也是正确的,除非您使用--index选项。 在这种情况下,存储代码尝试使用git show <index-commit-hash> | git apply --index恢复索引。

应用这样的存储会调用内部 Git 合并机制,尽管通常您可以通过使用git apply -3获得非常相似的效果。 (请注意,这与实际的挑选或合并或存储调用之间存在细微差别。

相关内容

  • 没有找到相关文章

最新更新