有没有办法 `git stash` 项目中的每个文件(不仅仅是更改)?

Is there a way to `git stash` every file in the project (not just changes)?

我 运行 遇到一个问题,我认为最好的解决方案是捕获项目的当前状态并将其应用于新分支中的新提交。

这是我的 git 工作流程的概述:

以下是导致这种情况的时间顺序:

  1. 我从 local/master 分支了一个分支作为 local/feature1.
  2. 我对 local/feature1 做出了几次承诺。
  3. 一项功能已合并到 origin/master 中,将一些 .pem 文件(public/private 键)从一个目录移动到另一个目录。
  4. 向 origin(私有 Gitlab 实例)添加了一个挂钩,以防止签入任何后续的 .pem 文件。
  5. 我从 origin/master 拉到 local/master。
  6. 我从 local/master 合并到 local/feature1.
  7. 我对 local/feature1 做出了更多承诺。
  8. 我试图将我的代码从 local/feature1 推送到原始 origin/feature1.
  9. origin 抱怨不允许我签入 .pem 文件。

我相信这是因为 local/feature1 中的提交历史现在包含一个包含 .pem 文件更改的合并提交。该文件是在实现挂钩之前添加到 origin/master 的,因此不受挂钩限制。但是,合并提交到我的分支之后会随着我的代码更改一起提交,所以它被钩子标记了。

此时我想从 local/feature1 的提交历史记录中删除 .pem 文件,而不实际删除这些文件。此时重新设置和压缩提交不会解决问题,因为 .pem 文件已经存在。删除 .pem 文件无济于事,因为它们实际上需要在项目中(不相关的故事)。将我的分支恢复到未合并状态也不是一种选择,因为上传的 origin/feature 与 origin/master 相比太过时了,以至于审查没有意义。

显而易见的解决方案似乎是:

# Copy current state of the project to a backup directory
cp -r . ../backup
rm -rf ../backup/.git

# Reset project to latest official state
git checkout local/master
git pull

# Regenerate local branch so the merged changes aren't included as local commits
git branch -D local/feature1
git checkout -b local/feature2

# Copy the desired project state back in and commit it
cp -rf ../backup/. .
git add --all
git commit -m "Regenerating feature branch"
rm -rf ../backup

# Upload without being restricted by hook
git push --set-upstream origin feature2

我觉得应该有一种方法可以使用 git 在本地执行此操作,而无需直接扰乱文件系统。这样做有什么魔术吗?也许通过 git stash?

我不明白为什么在 local/master 之上重新设置 local/feature1 基数(在第 6 步)是不够的。它将从上游引入 pem 更改,在其之上重播您的提交,因此当您推送时,pem 内容不会被触及。

如果您之前已推送到 origin/feature1,则必须推送 --force,但强制推送功能 beanches 通常应该没问题。

这里不需要git stashgit stash 已经保存了完整的快照,但所有提交也是如此。没有提交是差异。 Git 将一个提交变成一个差异,方法是将它与另一个完整的快照进行比较:两个快照中的不同之处就是差异.许多命令,包括 git stash,通过将提交与其父项进行比较来执行很多操作。例如,git cherry-pick 将 to-be-picked 提交与其父提交进行比较,以查看更改的内容,然后将这些更改应用到您现在所在的位置(同时进行第二次差异并使用合并引擎)。

A git commit 根据 index 的内容创建快照,而不是 work-tree 中的内容。因此,如果您想要在某个现有分支上进行新提交,该分支与任何现有提交完全匹配,您所要做的就是删除索引中的所有内容,并将其全部替换为来自其他提交的所有内容。 (work-tree 随行,以便您可以看到会发生什么。)有一个明显、简单的方法可以做到这一点:

$ git checkout br1
$ git rm -r .             # from the top level: remove everything
$ git checkout br2 -- .   # extract everything from commit at tip of br2
$ git commit

这将创建一个新提交,添加到 br1 的提示,其内容来自 br2。 (没有未跟踪的文件随行,因为未跟踪的文件根据定义不在索引中,但请注意提取的提交中跟踪的文件,这些文件在旧 br1 提示中未跟踪,反之亦然。)

同样有一个更短的版本:

$ git read-tree -m -u br2
$ git commit

这会减少 work-tree 中的流失(有时对 make 很重要):read-tree 将提交读入索引,而 -u Git 更新 work-tree 以匹配。由于此处 git read-tree 只有一个参数,因此会抛出当前索引内容,删除其中(以及 work-tree)中不在 br2 提交中的所有文件。与较长的变体一样,这不会影响未跟踪的文件。