0

认为

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

git cherry-pick -n <commit>

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

git reset HEAD

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


目的

如果一个人进行了存储,则无法将存储推送到遥控器。当前的 WIP 无法从另一个系统上的远程拉出以进行处理。所以我编写了 shell 函数来模拟 git-stash,除了我为每个存储使用分支。

apply或通常会将隐藏的pop更改应用于 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.

4

1 回答 1

1

眼前的问题

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

例如,考虑一下如果通过以下方式计算的 delta 会发生什么:

git diff $commit^ $commit

表示git cherry-pick $commit应该在 中添加一行README,从 中删除一行f1.txt,并在其中更改一行f2.txt(“更改”实际上是由 remove-old-add-new 暗示的)。

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

更普遍的问题

如果一个人进行了存储,则无法将存储推送到遥控器。

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

提交的安排使得工作树提交是最后一个提交,并且其他两个(加上当前提交)作为其父提交。然后最终提交的哈希 ID 使用git update-ref.

因为这些是提交,所以它们可以被git push-ed。但是,您必须在遥控器上为它们命名,遥控器将允许您设置。这个refs/stash名字一般是不可写的。例如:

git push fred stash:refs/heads/sneaky

将使用sneaky在远程创建分支名称。fredrefs/stash

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

fred$ git stash apply sneaky

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

fred$ git branch -D sneaky

另一项技术说明

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

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

应用这样的存储会调用内部 Git 合并机制,但通常您可以通过使用git apply -3. (请注意,这与实际的cherry-pick或merge或stash调用之间存在细微差别。)

于 2018-01-25T22:50:02.493 回答