-->

Git: prevent staging some files, automatically sta

2019-04-11 22:03发布

问题:

I would like to unstage everything in my current working copy, but automatically stage all files and hunks I edit in the future.

For example, I am using a different version of CocoaPods than most other people on the project I am working on. I would like to upgrade the configuration of the configuration files to be compatible with my CocoaPods without breaking theirs. The easiest way to do this is to not include the new configuration in a pull request, but that means I can't build. Stashing and popping won't work because if I stash after editing the configuration and then apply my changes, popping will fix the configuration but undo my changes.

How should I fix this?

回答1:

One way would be to modify that configuration file in a way which is visible only by you locally.
But in a way that remains invisible for the other users of that repo.

If those modifications are well defined (and not all over the place in your.config.file) then you could consider a content filter driver in order to generate the right content for that config file on checkout:

  • add a smudge script associated to your.config.file files in a .gitattributes declaration:

    your.config.file filter=filterconfig
    

(edit or create a .gitattributes file at the root folder of your local repo, and add the line above in it. You can add, commit and push that file: it won't have any impact for other users).


(image from "Customizing Git - Git Attributes", from "Pro Git book")

cd /path/to/your/local/cloned/repo
git config filter.filterconfig.smudge 'update_config'
git config filter.filterconfig.clean 'restore_config'

The update_config and restore_config scripts can anywhere on your local $PATH (they are in bash, even if you are on Windows, since they will be executed by the mingw git bash).

The update_config script would:

  • make a initial copy of the config file,
  • inject its modifications in the config file.

That way, a git pull which triggers an update of the working tree would automatically re-generate the config file content with the local modifications needed.

And the restore_config script would restore the saved copy of the file whenever it is called by git (it would be triggered by a git status or a git diff for instance):

cat saved_copy

That way, the config file appears to never change as far as git is concerned.



回答2:

A strategy I have been using, is to use two branches: One branch that is public, and a second branch that never leaves your machine and which contains your configuration changes.

When you do your development, you have your private branch checked out, but you don't commit to it. Once you are satisfied with your changes, you stash them, checkout the public branch, do a git stash pop, and commit the result. After that, you return to your private branch and merge your fresh commit. The resulting history will look something like this:

*   (HEAD->private) merge
|\
| * (public) commit 3
* | merge
|\|
| * commit 2
* | a change in your local configuration
* | merge
|\|
| * commit 1
* | some private configuration changes
 \|
  * some base commit

Now, if you graph the history of the public branch, you get this:

* (public) commit 3
* commit 2
* commit 1
* some base commit

As you see, no public commit ever depends on your local changes to the configuration, keeping the public history clean of your configuration changes. However, your configuration changes are perfectly version controlled, so you can go back to any of your merge commits and know that you will be able to build.

The price for this is, of course, the hassle of constantly changing branches. So I would avoid such a construct as much as I can, but it can be helpful in some situations.