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

前端 未结 9 1785
春和景丽
春和景丽 2020-12-28 12:14

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,

  • If the fi
相关标签:
9条回答
  • 2020-12-28 12:22

    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
    
    0 讨论(0)
  • 2020-12-28 12:30

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

    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).

    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

    Note: My original suggestion was to use assume-unchanged. As explained in Git - Difference Between 'assume-unchanged' and 'skip-worktree', it is really skip-worktree that you want. In particular, assume-unchanged is 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-worktree changes.

    0 讨论(0)
  • 2020-12-28 12:35

    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.

    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.

    0 讨论(0)
  • 2020-12-28 12:38

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

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

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

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

    0 讨论(0)
  • 2020-12-28 12:42

    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.).

    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.

    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.

    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.

    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.

    0 讨论(0)
  • 2020-12-28 12:44

    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 local and git checkout local to 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 commit to commit your changes.
    4. Make the changes that you want to push upstream.
    5. Use git checkout parent to go back to the branch that you do want to push.
    6. Use git commit to commit to this branch.
    7. Use git push to push your changes.
    8. Use git checkout local to get back to your local branch.
    9. Use git rebase parent to bring the changes from parent in to local. Using rebase will 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.

    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.

    0 讨论(0)
提交回复
热议问题