'git stash apply' 使用交互模式

'git stash apply' with Interactive Mode

我有一系列文件存储在 (stash{0}) 中,我想 git apply 只是 其中一些 parts/hunks文件(通常称为 交互模式)。

可能吗?

我看到可以执行

git stash save -p 'Stash name'

但好像做不到

git stash apply -p 'Stash name'

你知道实现它的方法吗?

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

Is it possible?

是的!

git checkout -p stash@{0}

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

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

不要忘记 git stash drop stash@{n} 当你知道你不再需要那个藏品时,因为 git checkout 显然不会为你放弃藏品。

为什么有效?

关键是要认识到存储在本质上 references to commits 就像标签和分支一样。

确实,它们存储在 .git/refs/stash 中,每个存储哈希一行。

注意事项

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

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

例如,如果您尝试将“多次提交前”保存的存储应用到当前工作区,git checkout -p stash@{n} 不仅会尝试应用存储本身的更改,还会还尝试还原 存储所基于的提交与当前提交之间发生的所有更改。

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

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

解决方法

有一些变通方法,none 适合所有情况:

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

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

    1. 在分离的头上,返回到您感兴趣的存储的“父”提交,应用存储,仅以交互方式重新存储您感兴趣的部分,去返回并重新应用较小的存储空间。

一步一步:

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

一种可能的方法是重置索引,然后使用 interactive add

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

我经常做的(在gitbash)是

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

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

<tmp.patch git apply

<tmp.patch patch -p1

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