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



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

以下是我的 git 工作流程的概述:

  • 在我的机器上保留了我们的源/主分支的本地副本,我将其称为本地/主分支。
  • 在调试我自己的本地/功能分支中的更改时,我使用本地/主进行比较。 例如,如果我注意到我的本地/功能分支中存在错误,我可能会切换回本地/主分支以查看它是否在那里重现。 这让我知道该错误是预先存在的还是由我自己的更改引起的。
  • 在源/主分支
  • 和我的本地/特征分支之间执行合并时,我还使用本地/主作为中间暂存分支。 这可以防止源分支(master)成为移动目标,以防我需要放弃合并并重新开始。
  • 我只通过从源/主中提取来更新本地/主。 每当其他开发人员将自己的更改合并到源/主节点时,就会执行此操作。
  • 我通过从本地/功能推送到源/功能并将合并请求从源/功能提交到源/主来提交我的代码。

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

我将本地/
  1. 主分支分叉为本地/功能1。
  2. 我对本地/功能1进行了几次提交。
  3. 一个功能被合并到origin/master中,它将一些.pem文件(公钥/私钥)从一个目录移动到另一个目录。
  4. 将钩子添加到源(私有 Gitlab 实例),阻止签入任何后续 .pem 文件。
  5. 我从原点/主站拉到本地/主站。
  6. 我从本地/主合并到本地/功能1。
  7. 我又对 local/feature1 进行了几次提交。
  8. 我试图将我的代码从本地/功能1推送到原点/特征1。
  9. origin抱怨我不允许签入.pem文件。

我相信这种情况正在发生,因为 local/feature1 中的提交历史记录现在包含一个包含 .pem 文件更改的合并提交。 此文件是在实现钩子之前添加到 origin/master 的,因此它不受钩子限制的约束。 但是,合并提交到我的分支之后会与我的代码更改一起提交,因此它被钩子标记。

此时,我想从本地/feature1 的提交历史记录中删除 .pem 文件,而无需实际删除这些文件。 此时变基和压缩提交并不能解决问题,因为 .pem 文件已经存在。 删除 .pem 文件无济于事,因为它们实际上需要在项目中(不相关的故事)。 将我的分支恢复到未合并的状态也不是一种选择,因为上传的源/要素与原点/主节点相差太远,以至于审查没有意义。

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

# 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

这里不需要git stashgit stash已经保存了完整的快照,但所有提交也是如此。 没有提交是差异。 Git通过将提交与另一个完整快照进行比较来将其转换为差异:无论两个快照中有什么不同,这就是差异。 许多命令(包括git stash)通过将提交与其父级进行比较来执行此操作。 例如,git cherry-pick将要选取的提交与其父级进行比较,以查看更改的内容,然后将这些更改应用于您现在所在的位置(也执行第二个差异并使用合并引擎)。

git commit索引的内容而不是从工作树中的内容创建快照。 因此,如果您希望在某个现有分支上进行与任何现有提交完全匹配的新提交,您所要做的就是删除索引中的所有内容并将其全部替换为其他提交中的所有内容。 (工作树随行而来,这样你就可以看到发生了什么。 有一个明显、简单的方法可以做到这一点:

$ 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

这导致工作树中的改动较少(有时对于例如make很重要):read-tree 将提交读取到索引中,-u使 Git 更新工作树以匹配。 由于这里只有一个参数要git read-tree,这会抛出当前的索引内容,删除其中(和工作树中)中不在br2提交中的任何文件。 与较长的变体一样,这不会影响未跟踪的文件。

我不明白为什么在本地/主(在步骤 6 中)之上重新定位本地/功能1是不够的。它将从上游引入 pem 更改,在其上重放您的提交,因此当您推送时,pem 内容不会被触及。

如果您之前已推送到原点/功能1,则必须按--force,但强制推送功能豆通常应该没问题。

相关内容

最新更新