在分支结帐之间保留 git --assume-unchanged 文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9815416/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 06:39:34  来源:igfitidea点击:

Preserve git --assume-unchanged files between branch checkouts

git

提问by Jeff

I've been using git --assume-unchanged yacs/settings/development.pyto ignore my local database configuration file in my dev branch. But when I want to switch branches (for deployments), I get an error that I still have changes pending:

我一直在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

Which is annoying. The only way I know how to get around this would be to stash it:

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

% 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
#

But now it's back in the index again (ugh)! Is there a better alternative to this workflow?

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

[I don't particularly care if the local changes stay locally (aka, it's ok if it's the production branch), I just don't want it pushed to a remote repository.]

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

采纳答案by VonC

You can try (git update-index man page):

您可以尝试(git update-index 手册页):

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

Skip-worktree bit can be defined in one (long) sentence: When reading an entry, if it is marked as skip-worktree, then Git pretends its working directory version is up to date and read the index version instead.

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

However, as mentioned in "git assume unchanged vs skip worktree":

但是,如“ git 假设未更改 vs 跳过工作树” 中所述:

Both options have problems. --assume-unchangedresets itself whenever the index gets discarded (e.g. git reset), so that will probably trip you up sooner or later. Same goes for --skip-worktree.

这两种选择都有问题。--assume-unchanged每当索引被丢弃(例如git reset)时都会重置自身,因此这可能迟早会绊倒您。也一样--skip-worktree



Plus, make sure to use Git 2.24 (Q4 2014).
Since 2012 (the OP's question), git stashhas been ported to C (it is no longer a shell script) but it had (in its new implementation) to (re-)learn to write refreshed index back to disk.

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

See commit 34933d0(11 Sep 2019) by Thomas Gummerer (tgummerer).
(Merged by Thomas Gummerer -- tgummerer--in commit 34933d0, 20 Sep 2019)

请参阅Thomas Gummerer ( ) 的提交 34933d0(2019 年 9 月 11 日(由Thomas Gummerer合并-- --提交 34933d0 中,2019 年 9 月 20 日)tgummerer
tgummerer

stash: make sure to write refreshed cache

When converting stash into C, calls to 'git update-index --refresh' were replaced with the 'refresh_cache()' function.
That is fine as long as the index is only needed in-core, and not re-read from disk.

However in many cases we do actually need the refreshed index to be written to disk, for example 'merge_recursive_generic()' discards the in-core index before re-reading it from disk, and in the case of 'apply --quiet', the 'refresh_cache()' we currently have is pointless without writing the index to disk.

Always write the index after refreshing it to ensure there are no regressions in this compared to the scripted stash.
In the future we can consider avoiding the write where possible after making sure none of the subsequent calls actually need the refreshed cache, and it is not expected to be refreshed after stash exits or it is written somewhere else already.

stash: 确保写入刷新的缓存

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

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

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



Warning, that index might notbe correctly rewritten when git stash is used with --quiet: With Git 2.25 (Q1 2020), Recent update to "git stashpop" made the command emptythe index when run with the "--quiet" option, which has been corrected.

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

See commit df53c80(13 Nov 2019) by Thomas Gummerer (tgummerer).
(Merged by Junio C Hamano -- gitster--in commit 3c3e5d0, 01 Dec 2019)

请参阅Thomas Gummerer ( )提交的 df53c80(2019 年 11 月 13 日(由Junio C Hamano合并-- --提交 3c3e5d0 中,2019 年 12 月 1 日)tgummerer
gitster

stash: make sure we have a valid index before writing it

Reported-by: Grzegorz Rajchman
Signed-off-by: Thomas Gummerer

In 'do_apply_stash()' we refresh the index in the end.

Since 34933d0eff("stash: make sure to write refreshed cache", 2019-09-11, Git v2.24.0-rc0 -- mergelisted in batch #6), we also write that refreshed index when --quietis given to 'git stash apply'.

However if '--index' is not given to 'git stash apply', we also discard the index in the elseclause just before.

We need to do so because we use an external 'git update-index --add --stdin', which leads to an out of date in-core index.

Later we call 'refresh_and_write_cache', which now leads to writing the discarded index, which means we essentially write an empty index file.

This is obviously not correct, or the behaviour the user wanted.

We should not modify the users index without being asked to do so.

Make sure to re-read the index after discarding the current in-core index, to avoid dealing with outdated information.

Instead we could also drop the 'discard_cache()' + 'read_cache()', however that would make it easy to fall into the same trap as 34933d0effdid, so it's better to avoid that.

We can also drop the 'refresh_and_write_cache' completely in the quiet case.

Previously in legacy stash we relied on 'git status' to refresh the index after calling 'git read-tree' when '--index' was passed to 'git apply'.

However the 'reset_tree()' call that replaced 'git read-tree' always passes options that are equivalent to '-m', making the refresh of the index unnecessary.

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

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

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

34933d0eff(“ stash:确保写入刷新的缓存”,2019 年 9 月 11 日,Git v2.24.0-rc0 --合并列在第 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在安静的情况下完全删除 ' '。

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

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

回答by Eric Woodruff

What I've started doing is creating a branch off master called private that has my local changes; think of it as a proxy branch between my work branch and master. I can rebase my current work branch against private when I need my local-only changes and I have a couple of aliases in my .gitconfig that automate keeping private up-to-date with master. When I need to merge to master, my aliases make sure to rebase --onto master private my work branch first.

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

I posted a blog entry about this in more detail here http://blog.ericwoodruff.me/2013/02/git-private-branch-pattern.html

我在这里更详细地发布了一篇关于此的博客条目http://blog.ericwoodruff.me/2013/02/git-private-branch-pattern.html

回答by mlehmeher

The solution that worked for me was to use --skip-worktree. However, like some above, I struggled with being able to switch between a ticketed branch and the main branch without git complaining even after I had set the --skip-worktree flag on the file whose changes I wanted to remain local.

对我有用的解决方案是使用 --skip-worktree。但是,就像上面的一些人一样,即使在我希望将其更改保留在本地的文件上设置了 --skip-worktree 标志之后,我也很难在有票的分支和主分支之间切换而不会出现 git 抱怨。

It seems like you'll run into this issue if you make changes to the local-only file before running --skip-worktree, which is what happened to me.

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

One suggested workaround, above, is to add the file to your_repo/.git/info/exclude. But I didn't want to add the file to the exclude list, so I did the following from within my working tree directory:

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

  1. cp <local-only_file> ~/
    • copy file that has your local-only changes to somewhere safe on the filesystem
  2. git checkout <local-only_file>
    • in working tree, checkout file so that it matches master branch file
  3. git update-index --skip-worktree -- <local-only_file>
  4. cp ~/<local-only_file> .
    • copy file in question from safe location back into working tree
  5. git diff
    • no changes should be shown; if you push to the main repo, no changes in <local-only_file>are included in the push
  1. cp <local-only_file> ~/
    • 将只有本地更改的文件复制到文件系统上的某个安全位置
  2. git checkout <local-only_file>
    • 在工作树中,检出文件,使其与主分支文件匹配
  3. git update-index --skip-worktree -- <local-only_file>
  4. cp ~/<local-only_file> .
    • 将有问题的文件从安全位置复制回工作树
  5. git diff
    • 不应显示任何更改;如果您推送到主存储库,<local-only_file>则推送中不包含任何更改

回答by Bruce Zu

this issue happens when the skipped file is not same as the one in the branch you are trying to checkout or the one you are trying to pull.

当跳过的文件与您尝试检出或尝试拉取的分支中的文件不同时,会发生此问题。