【问题标题】:Preserve git --assume-unchanged files between branch checkouts在分支结帐之间保留 git --assume-unchanged 文件
【发布时间】:2012-03-22 01:54:08
【问题描述】:

我一直在使用 git --assume-unchanged yacs/settings/development.py 来忽略我的 dev 分支中的本地数据库配置文件。但是当我想切换分支(用于部署)时,我得到一个错误,我仍然有未决的更改:

% git checkout production
error: Your local changes to the following files would be overwritten by checkout:
    yacs/settings/development.py
Please, commit your changes or stash them before you can switch branches.
Aborting

这很烦人。我知道如何解决这个问题的唯一方法就是把它藏起来:

% git stash
% git checkout production
% git merge dev
% ./deploy.sh
% git checkout dev
% git stash pop
# On branch dev
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   yacs/settings/development.py
#

但现在它又回到了索引中(呃)!这个工作流程有更好的替代方案吗?

[我并不特别关心本地更改是否保留在本地(也就是说,如果它是生产分支就可以了),我只是不希望它被推送到远程存储库。]

【问题讨论】:

  • 这对我不起作用。我用 --skip-worktree 添加文件,但 git status 没有显示。但是,我仍然无法切换到另一个分支。我错过了什么?

标签: git


【解决方案1】:

你可以试试(git update-index man page):

git update-index --skip-worktree -- path

Skip-worktree 位可以用一句话(长)来定义:当读取一个条目时,如果它被标记为 skip-worktree,那么 Git 会假装它的工作目录版本是最新的,而是读取索引版本。

但是,如“git assume unchanged vs skip worktree”中所述:

这两个选项都有问题。 --assume-unchanged 会在索引被丢弃时自行重置(例如 git reset),所以这可能迟早会让你绊倒。 --skip-worktree 也是如此。


另外,请务必使用 Git 2.24(2014 年第四季度)。
自 2012 年以来(OP 的问题),git stash 已被移植到 C(它不再是 shell 脚本),但它(在其新实现中)(重新)学习将刷新的索引写回磁盘。

参见Thomas Gummerer (tgummerer)commit 34933d0(2019 年 9 月 11 日)。
(由 Thomas Gummerer -- tgummerer -- 合并于 commit 34933d0,2019 年 9 月 20 日)

stash: 确保写入刷新缓存

将 stash 转换为 C 时,调用 'git update-index --refresh' 已替换为“refresh_cache()”函数。
只要索引只在内核中需要,而不是从磁盘重新读取,就可以了。

但是在许多情况下,我们确实需要将刷新的索引写入磁盘,例如“merge_recursive_generic()”在从磁盘重新读取之前丢弃内核索引,而在“apply --quiet”的情况下',如果不将索引写入磁盘,我们目前拥有的 'refresh_cache()' 是毫无意义的。

始终在刷新索引后写入索引,以确保与脚本存储相比没有回归。
将来我们可以考虑在确保后续调用实际上都不需要刷新缓存后尽可能避免写入,并且它是 stash 退出后预计不会刷新,或者它已经写在其他地方。


警告,当 git stash 与 --quiet 一起使用时,该索引可能不会被正确重写:使用 Git 2.25(2020 年第一季度),最近对“git stashpop”的更新使命令 清空使用“--quiet”选项运行时的索引,已更正。

参见Thomas Gummerer (tgummerer)commit df53c80(2019 年 11 月 13 日)。
(由 Junio C Hamano -- gitster -- 合并到 commit 3c3e5d0,2019 年 12 月 1 日)

stash:在写之前确保我们有一个有效的索引

报告人:Grzegorz Rajchman
签字人:Thomas Gummerer

在 'do_apply_stash()' 我们最后刷新索引。

由于34933d0eff(“stash:确保写入刷新的缓存”,2019-09-11,Git v2.24.0-rc0 -- merge列在batch #6中),我们也写了刷新将--quiet 赋予“git stash apply”时的索引。

但是,如果 '--index' 没有赋予 'git stash apply',我们也会丢弃之前 else 子句中的索引。

我们需要这样做,因为我们使用了外部 'git update-index --add --stdin',这会导致内核索引过时。

稍后我们调用'refresh_and_write_cache',这会导致写入丢弃的索引,这意味着我们本质上是写入一个空索引文件。

这显然是不正确的,或者用户想要的行为。

我们不应该在没有被要求的情况下修改用户索引。

请务必在丢弃当前的内核索引后重新读取索引,以避免处理过时的信息。

相反,我们也可以删除 'discard_cache()' + 'read_cache()',但这很容易陷入与34933d0eff 相同的陷阱,因此最好避免这种情况。

我们也可以在安静的情况下完全删除“refresh_and_write_cache”。

以前在旧存储中,当“--index”传递给“git apply”时,我们在调用“git read-tree”后依靠“git status”刷新索引。

但是,替换“git read-tree”的“reset_tree()”调用始终传递与“-m”等效的选项,从而无需刷新索引。

【讨论】:

  • 在尝试了--assume-unchanged--skip-worktree 之后,当我在设置此属性后尝试切换本地分支时,都继续抱怨未提交的文件更改。
  • @amoe 并且那个文件已经被版本化了对吧?如果您将该文件添加到your_repo\.git\info\exclude 会怎样?
  • @VonC ,script.js 文件有--assume-unchanged--skip-worktree 但仍然得到同样的错误。有什么想法吗?
  • @Eray 不只是在我的头上。最好提出一个新问题,并附上指向该问题的链接。
  • @VonC 在这里提问:stackoverflow.com/questions/29549318/… 谢谢。
【解决方案2】:

我开始做的是创建一个名为 private 的 master 分支,其中包含我的本地更改;将其视为我的工作分支和 master 之间的代理分支。当我需要我的本地更改时,我可以将我当前的工作分支重新定位为私有,并且我的 .gitconfig 中有几个别名可以自动使私有与 master 保持最新。当我需要合并到 master 时,我的别名确保首先 rebase --onto master private 我的工作分支。

我在此处http://blog.ericwoodruff.me/2013/02/git-private-branch-pattern.html 发布了一篇关于此的更详细的博客文章

【讨论】:

  • 您评论中的链接无效,但我喜欢您回答中描述的想法。
  • 感谢反馈,我把更正后的博客链接放在原答案中
【解决方案3】:

对我有用的解决方案是使用 --skip-worktree。然而,就像上面的一些一样,即使我在我想保留本地更改的文件上设置了 --skip-worktree 标志,我也很难在没有 git 抱怨的情况下在出票分支和主分支之间切换。

如果您在运行 --skip-worktree 之前对仅本地文件进行更改,您似乎会遇到这个问题,这就是发生在我身上的事情。

上面建议的一种解决方法是将文件添加到your_repo/.git/info/exclude。但我不想将该文件添加到排除列表中,因此我在工作树目录中执行了以下操作:

  1. cp &lt;local-only_file&gt; ~/
    • 将仅包含本地更改的文件复制到文件系统上的安全位置
  2. git checkout &lt;local-only_file&gt;
    • 在工作树中,签出文件以匹配主分支文件
  3. git update-index --skip-worktree -- &lt;local-only_file&gt;
  4. cp ~/&lt;local-only_file&gt; .
    • 将有问题的文件从安全位置复制回工作树中
  5. git diff
    • 不应显示任何更改;如果你推送到主仓库,&lt;local-only_file&gt; 中的任何更改都不会包含在推送中

【讨论】:

    【解决方案4】:

    当跳过的文件与您尝试签出的分支中的文件或您尝试提取的文件不同时,就会出现此问题。

    【讨论】:

      猜你喜欢
      • 2013-06-16
      • 2016-01-30
      • 2011-08-31
      • 2018-03-03
      • 2013-04-27
      • 2013-12-26
      • 2012-08-30
      • 1970-01-01
      相关资源
      最近更新 更多