简体   繁体   中英

git how to keep a config file different in different branches?

Allow me phrase my attempt first. Let say I have two branch, Alice1 and Alice2. Alice1 has it's own server and Alice2 has his own too. I want to be able to checkout to Alice1, writing my code, then test it on its own server by pushing the code directly using the URL that is saved in the URL config file so it has to stay in local. Alice2 has its own server also, if the code is tested fine on Alice1, I will checkout to Alice2, and sync with Alice1, then push it on Alice2's server. Sometimes I want Alice1 and Alice2 have independent testing environment so they can be seperate until I want to merge them.

I have been researching this for a long time but still not finding a reliable answer. The most popular solution is using .gitattribute and do merge=ours but it has cons that git will sometimes ignore them in forwarding. I also tried checkout file while merging, but this only works in one merge instead of every merging. Gitignore doesn't work obiviously as they don't track this file so all changes in this file will be lost.

Currently, I have two branch, master and dev. There is a file call .clasp.json. I want this file be different in these branches on every checkout, and merge should not touch those files.

I'm thinking if I can write a script that everytime when checkout to a branch, generate the file based on the branch name, I don't know if there is a way of doing it? I found I can use content filter driver, but there isn't a straight forward document out there, any recommandations please?

What I have tried: This method works in one merge, but the file will still get merged in the next merge. https://stackoverflow.com/a/4516022

Whats the Proper usage of .gitattributes with merge=ours This method will only work if there is a merge conflict, which in my case, I won't edit the file after the first edit, I just want it stay different in each branch.

The reason you can't do this in Git is that Git isn't about branches. 1

OK, can't is too strong: as you've shown in your question, you can do it manually. You're correct, though, that using a merge driver in .gitattributes won't work. The reason is that when you do run git merge , Git:

  • computes the merge base;
  • compares the config file in the base against the one each branch-tip; and
  • if the file is different in only one branch-tip commit, uses that branch-tip-commit version of the file.

If you could pick the merge base version of the file manually, you could avoid situations in which two out of the three input files match, but you can't do that.

So, what can you do? There are several classes of options:

  • post-checkout scripts;
  • filter drivers;
  • something outside Git itself.

The filter driver idea is attractive, but it has a terrible flaw: it runs before Git tells you which branch name was supplied to the git checkout or git switch command.

The post-checkout script method can work. However, it really leads to the third method: don't do it in Git at all. The reason is that you don't want to modify a tracked file (one that is in Git's index / staging-area), which produces all kinds of operational headaches later.

The third method is the one that really works. Use a file that is untracked and ignored, or is entirely outside the Git repository, or a startup directive, to hold the configuration. Allow this file or startup directive to include other files that are in Git, if you like, and/or build this file from files that are in Git. Have your software read defaults from files that are maintained in Git, if that's useful. But keep the actual configuration elsewhere.

Now that the configuration is outside the Git repository, you can have Git manage the files that are in the repository, without having Git damage the configuration.


1 More precisely, Git is about commits. Commits hold files, but Git isn't about the files; branch names hold commit hash IDs, but Git isn't about the branch names either. The Git operations we care about here—checkout and merge, that is—work on a commit basis, and the "true name" of a commit is its hash ID. Many commits are on many branches all at once, and some commits are sometimes on no branch at all. With commits existing without branch names, a branch name cannot be the basis for the existence of a commit. With some commits being the tip of multiple branches, and the stored files inside a commit being read-only, the files literally cannot depend on the branch name. Branch names can be changed, and the names can be moved around. The commits, once made, are fixed in place forever.

In the end, there's just a fundamental mismatch here. If you think about Git as being about commits —rather than branches or files—with commits holding files, everything all works. If you think about Git as being about branches , some parts just don't fit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM