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

时间:2019-06-07 21:03:48

标签: git git-merge githooks git-stash

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

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

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

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

  1. 我从本地/主服务器分支为本地/功能1。
  2. 我对local / feature1做了几次提交。
  3. 一项功能被合并到origin / master中,该功能将一些.pem文件(公用/专用密钥)从一个目录移动到另一个目录。
  4. 已将钩子添加到原始位置(一个私有的Gitlab实例),阻止了随后的.pem文件的签入。
  5. 我从起源/母带拉到了本地/母带。
  6. 我从本地/母版合并到本地/ feature1。
  7. 我又对local / feature1进行了几次提交。
  8. 我试图将我的代码从local / feature1推送到起源,作为origin / feature1。
  9. origin抱怨我不允许检入.pem文件。

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

这时,我想从local / 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

2 个答案:

答案 0 :(得分:3)

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

git commit index 的内容而不是工作树中的内容制作快照。因此,如果您希望某个现有分支上的某个新提交与任何现有提交完全匹配,那么您要做的就是删除索引中的所有内容,并将其替换为其他某个提交中的所有内容。 (随即出现了工作树,因此您可以看到发生了什么。)有一种显而易见的简单方法:

$ 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技巧中未跟踪,反之亦然。)< / p>

有一个简短的版本:

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

会减少工作树的搅动(有时对于make来说很重要):read-tree将提交读入索引,而-u使Git更新工作-树匹配。由于此处git read-tree仅具有一个参数,因此它将抛出当前索引内容,并删除其中(以及工作树中)不在br2提交中的任何文件。与较长的变体一样,这不会影响未跟踪的文件。

答案 1 :(得分:2)

我不理解为何仅在本地/主控上重新建立本地/功能1(在步骤6)是不够的。它将从上游引入pem更改,并在其上重播提交,因此当您推送时,pem的内容将不会被触及。

如果您先前已将--force推到origin / feature1,则必须推--force,但是通常应使用推力功能部件。