忽略 git 中文件的特定更改,但不忽略整个文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16598257/
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 08:32:45  来源:igfitidea点击:

Ignore specific changes to a file in git, but not the entire file

gitgitignoreignore

提问by Kevin

I have a file in a git repository that has a local change on it. I want to have git ignore the local change forever, but not the file. In particular,

我在 git 存储库中有一个文件,其中有一个本地更改。我想让 git 永远忽略本地更改,而不是文件。特别是,

  • If the file isn't touched besides this change, git add .should never stage it.
  • Likewise, git commit -ashouldn't commit it.
  • If I ever make an additional change to the file, I should be able to stage and commit that change - but the change I'm ignoring should notbe staged and committed.
  • 如果除了此更改之外未触及该文件,则不应暂存git add .它。
  • 同样,git commit -a不应该提交它。
  • 如果我对文件进行了额外的更改,我应该能够暂存并提交该更改 - 但我忽略的更改应该暂存和提交。

Is there a way to do this? Doing some research, I read about "smudge/clean cycles," where, if I read correctly,

有没有办法做到这一点?做了一些研究,我读到了“污迹/清洁周期”,如果我读对了,

  1. the file would be marked as unchanged,
  2. the change I made would be overwritten when I checkout,
  3. and then a script would automatically reapply the change and then mark the file as unchanged again.
  1. 该文件将被标记为未更改,
  2. 当我结帐时,我所做的更改将被覆盖,
  3. 然后脚本会自动重新应用更改,然后再次将文件标记为未更改。

I am very new to git and scripting, though (I'm an intern with C# and Java experience), so if that's what I need to do, can you please post detailed directions or a link to a tutorial on how to set a smudge/clean cycle up?

不过,我对 git 和脚本编写非常陌生(我是 C# 和 Java 经验的实习生),所以如果这就是我需要做的,请您发布详细说明或链接到如何设置污迹的教程/清理循环?

Background:I want my working branch to be out of sync with the trunk. There is a low priority bug that only affects development machines, so rather than fix it, we're just commenting out the offending code. Obviously, we don't want this code to be removed from production, where it works just fine.

背景:我希望我的工作分支与主干不同步。有一个低优先级的错误只影响开发机器,所以我们不是修复它,而是注释掉有问题的代码。显然,我们不希望从生产中删除此代码,因为它可以正常工作。

采纳答案by Steven Penny

As I see it, the situation you are describing is this: you want to maintain a working directory that is different from the local repository.

在我看来,您所描述的情况是这样的:您想要维护一个与本地存储库不同的工作目录。

This is not advisable; because these changes are not committed you will have little recourse if a file is accidentally deleted or changed in a way you do not want.

这是不可取的;因为这些更改没有提交,如果文件被意外删除或以您不想要的方式更改,您将几乎没有追索权。

Therefore it is recommended that you in fact commit all your changes. If you would like to separate these changes you can easily do that using a branch. Example

因此,建议您实际上提交所有更改。如果您想分离这些更改,您可以使用分支轻松实现。例子

git checkout -b new-branch
# now you can change the file without affecting master
echo bar >> foo
git add
git commit
# and back to master
git checkout master

回答by Mark Lodato

You can use the skip-worktreebit. Turn it on with:

您可以使用该skip-worktree位。打开它:

git update-index --skip-worktree <file>

After that, git will never stage local changes for <file>and will fail (loudly) if git itself has to write to <file>(say, in a merge or a checkout).

在那之后,<file>如果 git 本身必须写入<file>(例如,在合并或结帐中),git 将永远不会为本地更改暂存并且将失败(大声)。

If you ever want to stage a future change, you can turn it off, stage the new change, and then turn it back on:

如果您想暂存未来的更改,可以将其关闭,暂存新的更改,然后重新打开:

git update-index --no-skip-worktree <file>
git add -p <file>
git update-index --skip-worktree <file>

While not perfect, this might be good enough. It will be up to you to notice that <file>has unstaged changes, since git will no longer tell you that

虽然不完美,但这可能已经足够了。由您决定是否<file>有未暂存的更改,因为 git 将不再告诉您

Note:My original suggestion was to use assume-unchanged. As explained in Git - Difference Between 'assume-unchanged' and 'skip-worktree', it is really skip-worktreethat you want. In particular, assume-unchangedis a promise to Git that you won't change the file, and if you violate that promise Git is allowed to erase your changes or commit them!In contrast, Git will not erase or commit your skip-worktreechanges.

注意:我最初的建议是使用assume-unchanged. 正如Git - 'assume-unchanged' 和 'skip-worktree' 之间的差异所解释,这确实skip-worktree是您想要的。特别assume-unchanged是向 Git 承诺你不会更改文件,如果你违反了这个承诺,Git 将被允许删除你的更改或提交它们!相比之下,Git 不会删除或提交您的skip-worktree更改。

回答by Tyler Perkins

These answers are good, but may not best solve @Kevin's problem. I had a similar concern, often editing a config file so the app I was working on would access my own private development database instead of the production one. It's only a matter of time before I accidentally check in and push those config changes! I just needed a light weightway to ignore a file. Here's what I learned:

这些答案很好,但可能无法最好地解决 @Kevin 的问题。我也有类似的担忧,经常编辑配置文件,这样我正在开发的应用程序将访问我自己的私有开发数据库而不是生产数据库。我不小心签入并推送这些配置更改只是时间问题!我只需要一种轻量级的方式来忽略文件。这是我学到的:

  • First, make your needed change to your file. I'll call it my_config.

  • Make a patch file of that change with git diff >../somewhere-else/my_config.patch

  • Now tell git to ignore that file (without having to change the checked-in .gitignore): git update-index --assume-unchanged my_config

  • 首先,对文件进行所需的更改。我会打电话给它my_config

  • 制作该更改的补丁文件 git diff >../somewhere-else/my_config.patch

  • 现在告诉 git 忽略该文件(无需更改签入的 .gitignore): git update-index --assume-unchanged my_config

Now, as long as you don't make changes to my_configthat you dowant to check in, you can work freely. To stop ignoring my_config, do git update-index --no-assume-unchanged my_config. After pulling in somebody else's changes to my_config, you can easily restore your private change with git apply ../somewhere-else/my_config.patch, then ...assume-unchanged again, as above, and get back to work!

现在,只要你不更改my_config,你需要检查中,你可以自由地工作。停止无视my_config,做git update-index --no-assume-unchanged my_config。在将其他人的更改拉入 之后my_config,您可以轻松地使用 恢复您的私人更改git apply ../somewhere-else/my_config.patch,然后...再次假设未更改,如上所述,然后重新开始工作!

Here are some helpful aliases you can put in your ~/.gitconfig:

这里有一些有用的别名,你可以放在你的~/.gitconfig:

[alias]
    unchanged = update-index --assume-unchanged
    changed = update-index --no-assume-unchanged
    show-unchanged = !"git ls-files -v | sed -e 's/^[a-z] //p; d'"

回答by Riking

Git's "patch mode" is perfect for adding only certain changes from a file to your commit.

Git 的“补丁模式”非常适合仅将文件中的某些更改添加到您的提交中。

To start it, type git add -p, git commit -p(straight to commit message when done), or git add --interactive(more prompts).

要启动它,请键入git add -p, git commit -p(完成后直接提交消息)或git add --interactive(更多提示)。

It essentially takes you through each section of code shown in git diffand asks you whether you want to stage it or not.

它基本上会带您浏览 中显示的每个代码部分,git diff并询问您是否要暂存它。

When you reach the change, either answer no, or eto open the patch in your $EDITOR.

当您到达更改时,请回答no 或e以在您的 $EDITOR 中打开补丁。

回答by Tanner Swett

Note: other people have said that keeping around persistent local changes is a bad idea, and I don't have any reason to disagree. Consider other options.

注意:其他人说保持持续的本地更改是一个坏主意,我没有任何理由不同意。考虑其他选择。

Here's the method that I like:

这是我喜欢的方法:

  1. Make some changes that you want to keep on your local machine.
  2. Use git branch localand git checkout localto make a new branch for your local changes. (If I'm not mistaken, these commands won't set up a remote branch automatically, so the new branch won't get pushed.)
  3. Use git committo commit your changes.
  4. Make the changes that you want to push upstream.
  5. Use git checkout parentto go back to the branch that you do want to push.
  6. Use git committo commit to this branch.
  7. Use git pushto push your changes.
  8. Use git checkout localto get back to your local branch.
  9. Use git rebase parentto bring the changes from parentin to local. Using rebasewill make it so that your local changes remain on top of the changes in parent.
  10. Go back to step 4 and repeat ad nauseam.
  1. 进行一些要保留在本地计算机上的更改。
  2. 使用git branch localgit checkout local为您的本地更改创建一个新分支。(如果我没记错的话,这些命令不会自动设置远程分支,因此不会推送新分支。)
  3. 使用git commit提交更改。
  4. 进行您想要向上游推送的更改。
  5. 用于git checkout parent返回您想要推送的分支。
  6. 使用git commit承诺这个分支。
  7. 使用git push推更改。
  8. 用于git checkout local返回您当地的分支机构。
  9. 使用git rebase parent从带来的变化parentlocal。使用rebase将使您的本地更改保持在parent.
  10. 返回第 4 步,重复令人作呕的事情。

With this, you don't have to manually tell git which changes are local and which ones aren't every time you want to make a non-local change.

有了这个,您不必每次想要进行非本地更改时都手动告诉 git 哪些更改是本地的,哪些不是。

回答by sleske

Yes, this could probably be done using smudge/clean filters. However, I'd strongly advise against doing this, because it would be rather complex and error-prone (e.g. it would confuse many tools building on git, it would make problems hard to debug etc.).

是的,这可能可以使用污迹/清洁过滤器来完成。但是,我强烈建议不要这样做,因为它会相当复杂且容易出错(例如,它会混淆许多在 git 上构建的工具,它会使问题难以调试等)。

Also, it is generally not a good idea to have permanent local changes. One important point of using a SCM is that you can checkout a version and have it work immediately. That means that everything that you need should be checked in.

此外,进行永久性本地更改通常不是一个好主意。使用 SCM 的一个重要点是您可以检出一个版本并使其立即运行。这意味着你需要的一切都应该被签入。

I don't think there is any "nice" way to do this, neither with git nor probably with most other SCMs. I would recommend you reconsider your requirements.

我认为没有任何“好”的方法可以做到这一点,无论是使用 git 还是大多数其他 SCM。我建议您重新考虑您的要求。

The problem seems to be that you have a file with "mixed content": Some content that is always the same, and some that needs to be changed locally (machine-specific options?). The recommended way to handle this is not to check in the problematic file, but instead check in a "template" file, then generate the real file at build time. Try investigating this. It will be more work now (possibly), but will make things easier, especially if you need to support more variation or if other people want to work on the same project.

问题似乎在于您有一个包含“混合内容”的文件:有些内容始终相同,有些内容需要在本地更改(特定于机器的选项?)。处理此问题的推荐方法不是签入有问题的文件,而是签入“模板”文件,然后在构建时生成真实文件。试着调查一下。现在(可能)会有更多的工作,但会让事情变得更容易,特别是如果你需要支持更多的变化或者其他人想要在同一个项目上工作。

Edit (based on info in comment)

编辑(基于评论中的信息)

You write that you want to ignore a local code change that is only necessary for the development machines, but not in production.

您写道,您想忽略仅对开发机器是必需的本地代码更改,而不是在生产中。

In that case, instead of commenting out, wrap the code in a condition of some sort, so that it only runs on the dev machines (e.g. using conditional compilation, or reading a config file or some environment property, or ...(1)). Then you can check in the code normally.

在这种情况下,不要注释掉,而是将代码包装在某种条件中,以便它仅在开发机器上运行(例如,使用条件编译,或读取配置文件或某些环境属性,或...(1 ))。然后就可以正常签入代码了。

Even better, just fix the bug. If a bug makes development difficult, then IMHO it is high-priority.

更好的是,只需修复错误。如果错误使开发变得困难,那么恕我直言,它是高优先级的。

Just commenting out code is not a good idea. It is error-prone and must be done each time you check out. Above all, running different code in development and in production is asking for trouble and should be avoided whenever possible.

仅仅注释掉代码并不是一个好主意。这很容易出错,每次结账时都必须这样做。最重要的是,在开发和生产中运行不同的代码会带来麻烦,应尽可能避免。

(1) As an example: In our company, we have an environment variable specifically for cases like this. It indicates whether the code is running in development, in beta test, or in production, and is set by our build and deployment scripts. However, it is usually only used for simple things like choosing different file paths. Changing program logic based on the environment is discouraged, as explained above.

(1) 举个例子:在我们公司,我们有一个专门针对这种情况的环境变量。它指示代码是在开发、beta 测试还是生产中运行,并由我们的构建和部署脚本设置。然而,它通常只用于简单的事情,比如选择不同的文件路径。如上所述,不鼓励根据环境更改程序逻辑。

回答by sleske

As of Git 2.5 (July 2015), you can use git worktree:

从 Git 2.5(2015 年 7 月)开始,您可以使用git worktree

git worktree add -b patch-1 ../patch-1

This is essentially just creating a branch, but it puts the new branch into a new folder alongside the parent repo. This is nice because you can do work on this branch, even without committing, then switch back to master with a clean working directory.

这本质上只是创建一个分支,但它将新分支放入父存储库旁边的新文件夹中。这很好,因为你可以在这个分支上工作,即使没有提交,然后切换回 master 并使用干净的工作目录。

回答by LOAS

If you happen to be using intellij as your IDE, then it has a neat feature (changelists) that I believe does exactly what OP is requesting.

如果您碰巧使用 intellij 作为您的 IDE,那么它有一个简洁的功能(更改列表),我相信它完全符合 OP 的要求。

You can mark and name a specific part of your local diff. If memory serves, this will keep those changes separate from all other local modifications and will only be staged for commit if you actively choose to do so - so long as you do your committing from intellij.

您可以标记和命名本地差异的特定部分。如果没记错的话,这将使这些更改与所有其他本地修改分开,并且只有在您主动选择时才会提交提交 - 只要您从 intellij 提交。

回答by Bijendra

If you can't use .gitignore as you need to make parallel changes in the same file(as found in your comments) then one option is git add -p Using this you can add or skip accordingly.

如果您不能使用 .gitignore ,因为您需要在同一个文件中进行并行更改(如您的评论中所示),那么一个选项是 git add -p 使用它,您可以相应地添加或跳过。

The problem using the above git command here is, it will be more of a manual process. I guess you may not find any other automated approach for you problem.

这里使用上面的 git 命令的问题是,这将更多是一个手动过程。我想您可能找不到任何其他自动化方法来解决您的问题。