Git metadata - is there a way to add git metadata that is independent of each branch?

泄露秘密 提交于 2019-12-06 04:37:04

Okay, I think I understood your query now. Basically, you need to add the data in a visible folder so that git tracks it i.e. git add <data> in one of the branches and merge this branch to master and then consequently synchronize other two branches with the master (git fetch origin master && git merge origin master). In this particular case, since you added a new file/folder in git, you won't face merge conflicts. Finally, your data will be available in all the branches. EDIT (based on another user's comment): git cherry-pick <commit-hash> is another way where you can apply a specific commit to a branch.

... data that is in .git folder is typically git-ignored.

This is not just typical, it's necessary for Git's security model.

(In the past, Git had some bugs in which you could create files named .GIT/whatever and they would go into the repository, then exist in .git/whatever on checkouts on Windows and MacOS, since those systems default to ignoring case: a file named .GIT/foo is actually created as .git/foo since .git exists at that point. This bug has been corrected in modern Git.)

I want to add some data to my repo so that the data is independent of all branches, but still appears in all branches, and when you clone the repo, the data shows up.

Is this possible?

No—but there are other ways to get what you want.

Cloning a repository is equivalent to the following steps:

  • Create an empty directory (or use an existing one): mkdir path.
  • Create a new, empty Git repository there: cd path && git init.
  • Add a remote, usually named origin, for the URL: git remote add origin url.
  • Fetch everything from that remote: git fetch origin.
  • Create a branch via git checkout: git checkout branch, where branch is normally created from a remote-tracking name that was created during the preceding git fetch step.

There are a number of historical peculiarities, plus issues if something goes wrong, so the above is not quite perfect. It also omits an optional git config step. The branch chosen at the end, to be created, is the one from your -b argument. If your -b argument names a tag instead of a branch, Git just checks out a detached HEAD without creating any branch. If you don't give a -b argument, Git uses directives from the remote to figure out which branch to create. The default, and thus the usual result, is master, created to point to the same commit as origin/master.

Once there is a branch, or some branches, in a repository, those branches—more precisely, those names, like master and develop and so on—are owned by whoever owns the repository. They can do whatever they want with them; you, as the owner of the repository that they cloned, can do nothing to stop them. You cannot make them have a file show up in their branches. Of course we can say that about the entire repository, so that's a bit silly as an argument: it's true that you cannot control them; the whole repository is theirs to do with as they will.

Presumably, then, what you want is to make it easy for them to install some content into a file somewhere. The way to do that is to have the content accessible by some simple name. But what names does Git offer?

Well, at the bottom level, what Git stores are commits, which in turn store trees (path names) that store blobs (file content). The actual name of any given commit, tree, or blob is a raw hash ID, and hash IDs are unpredictable and not generally useful to, or accessible by, humans. So you could tell people, say, to:

extract hash ID 1bdc91e282c5393c527b3902a208227c19971b84 into .oresoftware/foo

but (1) the hash ID is incomprehensible, and (2) who wants to type all that in? And if you have multiple files, you'll need one blob hash ID per file. Yuck!

There is a better way to do this though. You can create a commit object that contains files named .oresoftware/foo, .oresoftware/bar, and so on. This is an ordinary commit that can be extracted into an ordinary work-tree at any time.

Now suppose that you put this commit on a branch named ORESOFTWARE. You can then tell people that they should:

run git checkout origin/ORESOFTWARE -- .oresoftware && git reset .oresoftware

which, admittedly, is not really any shorter, but at least is not full of incomprehensible hash IDs.

The git checkout will create .oresoftware in their work-tree, as long as they have the remote-tracking name, which git fetch (from git clone) will have created.1 The git reset .oresoftware will remove the .oresoftware entries that git checkout created in their index. If /.oresoftware/ is listed in .gitignore, the work-tree files will be ignored. This means you have to have a .gitignore in each tip commit of each branch, so that the directory will be conveniently automatically ignored, but that is easy to do.

Last, instead of directing people to run two apparently-magic Git commands, you can say:

run ./setup.sh

which means you can put the two Git commands into a shell script, setup.sh, that you provide in every branch-tip just like you provide the .gitignore file in every branch tip. Moreover, you can even have your software-build process automatically run ./setup.sh, and then you don't need any special action on their part.

Should you decide to change the files that go in .oresoftware, you just need to make a new commit on your own ORESOFTWARE branch. This can (and probably should) contain just the .oresoftware directory. Because the build process re-extracts the directory with each build, a git fetch will get your users an updated origin/ORESOFTWARE remote-tracking name, which will then get them updated files.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!