【问题标题】:Is there a way to `git stash` every file in the project (not just changes)?有没有办法`git stash`项目中的每个文件(不仅仅是更改)?
【发布时间】:2019-06-07 21:03:48
【问题描述】:

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

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

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

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

  1. 我从 local/master 分叉了一个分支作为 local/feature1。
  2. 我对 local/feature1 做了几次提交。
  3. 一项功能已合并到 origin/master,它将一些 .pem 文件(公钥/私钥)从一个目录移动到另一个目录。
  4. 向源(私有 Gitlab 实例)添加了一个钩子,该钩子阻止了任何后续的 .pem 文件被签入。
  5. 我从 origin/master 拉到 local/master。
  6. 我从 local/master 合并到 local/feature1。
  7. 我对 local/feature1 进行了多次提交。
  8. 我尝试将我的代码从 local/feature1 推送到 origin 作为 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

【问题讨论】:

  • 你试过git stash --include-untracked 来存储未跟踪的更改和跟踪的文件吗?此外,充分利用这些钩子脚本将凭据保留在存储库之外。
  • 这不起作用,因为我要存储的文件已经被跟踪和提交(在合并提交之前、期间和之后)。我只知道如何让 git stash 从分支的 HEAD 抓取更改。

标签: git git-merge githooks git-stash


【解决方案1】:

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

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 提示中未跟踪,反之亦然。)

还有一个更短的版本:

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

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

【讨论】:

  • 这只是推进了kluge。问题的根本原因是合并,需要解决。
  • @stellarhopper 是的,但有时这就是一个人的全部时间:-)
【解决方案2】:

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

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

【讨论】:

  • 如果在包含 .pem 文件的本地/master 的原始合并提交期间存在冲突(在不相关的文件中),这仍然有效吗?我似乎记得上次我尝试这样的事情时必须在重播期间重新解决合并冲突。
  • 哪个原始合并提交?第 6 步?您必须撤消该合并,并且您可能会在 rebase 期间看到相同的冲突,但 rebase 会给您一个修复它的机会。
  • 是的,从第 6 步开始。我想这会奏效,但仍然需要付出很多努力。
  • 这是“正确”的方式,IMO。如果您启用了 git rerere,它可能会保存解决方案,但如果您在第一次解决冲突时没有这样做,您只需要再次执行此工作。您可以尝试从该合并提交中保存一个补丁来帮助指导您。一般来说,启用 rerere 总是一个好主意。
猜你喜欢
  • 1970-01-01
  • 2017-08-05
  • 2012-06-27
  • 1970-01-01
  • 1970-01-01
  • 2017-09-03
  • 2017-10-18
  • 2021-03-16
  • 1970-01-01
相关资源
最近更新 更多