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

标签 git git-merge githooks git-stash

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

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

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

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

  1. 我从 local/master fork 了一个分支作为 local/feature1。
  2. 我对 local/feature1 进行了多次提交。
  3. 一项功能已 merge 到 origin/master 中,该功能将一些 .pem 文件(公钥/私钥)从一个目录移动到另一个目录。
  4. 向 origin(私有(private) Gitlab 实例)添加了一个钩子(Hook),阻止 checkin 任何后续 .pem 文件。
  5. 我从 origin/master pull 入 local/master。
  6. 我从 local/master merge 到 local/feature1。
  7. 我对 local/feature1 又做了几次提交。
  8. 我尝试将代码从 local/feature1 推送到 origin 作为 origin/feature1。
  9. origin 提示我不被允许 checkin .pem 文件。

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

此时,我想从 local/feature1 的提交历史记录中删除 .pem 文件,而不实际删除这些文件。此时重新定位和压缩提交并不能解决问题,因为 .pem 文件已经存在。删除 .pem 文件不会有帮助,因为它们实际上需要位于项目中(不相关的故事)。将我的分支恢复到未 merge 状态也不是一个选项,因为上传的 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

最佳答案

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

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 中的任何文件提交。与较长的变体一样,这不会影响未跟踪的文件。

关于git - 有没有办法对项目中的每个文件进行 `git stash` (不仅仅是更改)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56501190/

相关文章:

git - `rebase' 导致的冲突数量是否真的少于 `merge' ?

git - 择优 merge 在此方案中是否合适?

git - 在 git post-receive 后更改所有权

git - git merge 后,这个分支落后1次提交

git - 如何在 Github 中 pull 请求后快速跟踪分支

git - 无法将我的代码推送到 Heroku : Permission denied <public key> fatal: Could not read from remote repository

跳过 Python 预提交单元测试

git - 错误 `remote: fatal: bad object 0000000000000000000000000000000000000000` 是什么意思?

git - 使用 git 的高效项目架构

git - 无法安装 Gerrit 的 commit-msg 钩子(Hook);身份验证似乎很好