51

我有一系列文件到存储区(stash{0})中,我git apply 只想这些文件的一些部分/大块(通常称为交互模式)。

可能吗?

我已经看到可以执行

git stash save -p 'Stash name'

但似乎不可能

git stash apply -p 'Stash name'

你知道实现它的方法吗?

4

4 回答 4

81

可能吗?

是的!

git checkout -p stash@{0}

您可以在其中将0in替换为stash@{0}您要应用的存储的索引。

如果不确定要应用哪个存储,请使用git stash listgit show -p stash@{n}n

git stash drop stash@{n}当您知道不再需要该存储时,请不要忘记,因为git checkout显然不会为您丢弃存储。

为什么它有效?

关键是要意识到 stash 本质上是对提交的引用,就像标签和分支一样。

实际上,它们存储在.git/refs/stash,每个存储散列一行。

注意事项

正如下面评论中提到的@mgaddagit checkout -p ,尝试应用提交和当前工作空间之间的全部差异。

在 git stash 的情况下,如果您尝试应用的 stash 是针对不同的提交完成的,那么将尝试以交互方式应用提交和当前工作空间的提交git checkout -p stash@{n}之间的所有差异,包括它们的所有父提交是不同的stash@{n}

例如,如果您尝试将“多次提交前”保存的存储应用到当前工作区,git checkout -p stash@{n}则不仅会尝试应用存储中的更改,还会尝试恢复在存储所基于的提交和当前提交。

相反,如果您尝试“从未来”应用存储,即应用到一个分支,该分支是在存储所基于的提交之前的多次提交,那么git checkout -p stash@{n}将尝试也应用所有其他发生的更改在当前提交和未来提交之间,除了存储本身的更改。

(如果您想知道,git checkout -p stash@{n}来自并行分支的存储将尝试还原当前提交和原始分支点之间的所有更改,应用分支点和另一个分支之间的所有更改,除了存储中的更改) .

解决方法

有一些解决方法,它们都不适合所有情况:

    1. 当你接受的补丁时要非常小心git checkout -p stash@{n}
    1. 做一个git stash pop,然后git stash再做之前git checkout -p ...。但是,如果您想部分应用您的存储以避免冲突,这将无济于事。在这种情况下,请参阅下面的解决方案 4。
    1. 如果您有 git 支持的图形差异工具(例如meld),您可以git difftool只使用并“向左应用”您感兴趣的更改:
    • git difftool -d stash@{n}比较整个存储及其所有文件

    • git difftool stash@{n} -- path/to/file比较单个文件

    1. (基于@andrew 的回答)在一个分离的头上,返回到您感兴趣的存储的“父”提交,应用存储,仅以交互方式重新存储您感兴趣的部分,返回并重新应用较小的藏匿处。

一步步:

git checkout stash@{n}^  # notice the "^". 

# Now you're in a detached head in the parent commit of the stash.
# It can be applied cleanly:
git stash apply stash@{n}

# Now save only the diffs you're interested in:
git stash -p

# remove the rest of the old stash
git checkout -- .  # be careful or you could remove unrelated changes

# go back to the branch where you want to apply the smaller stash
git checkout <my previous branch>

# apply the smaller stash
git stash pop
于 2017-04-28T19:47:47.760 回答
10

我经常做的(在 git bash 中)是

git stash show -p 'stash@{0}' >tmp.patch

然后我编辑文件并删除我不想要的部分。最后我说

<tmp.patch git apply

或者

<tmp.patch patch -p1

但是,它不适用于二进制文件,但接受的答案(使用 checkout -p)也不适用于它们。

于 2019-12-18T08:18:58.310 回答
4

一种可能的方法是重置索引,然后使用交互式添加

# 0. ensure there are no uncommitted changes
git status

# 1. apply a changeset as is
git stash apply stash@{n}
# ... fix or discard conflicts if any

# 2. reset the index 
git reset

# 3. interactively add the required chunks (except new files)
git add -p

# 4. stash all other changes
git stash save --keep-index "comment"
# 4. or just discards all other changes in the working tree
git checkout-index -f -a

# 5. commit
git commit -m "comment"

另一种方法是使用交互式重置代替交互式添加。

# 0. ensure the working tree does not have unstaged changes
git status

# 1. apply a changeset as is
git stash apply stash@{n}
# ... fix or discard conflicts if any

# 2. interactively exclude the unneeded chunks from the index 
git reset -p

# 3. stash all other changes
git stash save --keep-index "comment"
# 3. or just discards all other changes in the working tree
git checkout-index -f -a

# 4. commit
git commit -m "comment"
于 2018-09-05T13:16:57.467 回答
3

我认为没有办法通过大块(甚至通过文件)应用更改。您必须应用存储,然后以交互方式存储您不想要的更改(使用git stash save -p)。如果您担心冲突,您可以先存储任何未提交的更改,应用您的存储,存储任何冲突的块,然后应用其他存储。

于 2015-01-28T15:27:16.060 回答