End goal: I want to have files that are tracked by Git, but have those files be the same version for all branches. If you gitignore files, those are the same for all branches, but unfortunately aren't tracked. When I run git push
or the like, I need these files to passed between repos, etc.
For example, the data that is in .git folder is typically git-ignored. 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? So for example, if the .git
dir looks like:
.git/
branches/
hooks/
objects/
config
HEAD
index
I was thinking of adding a folder:
.git/
.oresoftware/
and putting my data in there, where that data is independent of all branches.
I don't think this will work, because the data in the .git repo isn't really tracked. I am looking for something that's tracked by git, but is the same for all branches...
Update: After reading the answers and thinking about this for awhile, I thought maybe if I amend the initial commit with new files, then it could magically work, but of course that's not how Git works, each commit is a total snapshot, so changing historical commits after the fact won't change newer ones.
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 precedinggit 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.
来源:https://stackoverflow.com/questions/51794791/git-metadata-is-there-a-way-to-add-git-metadata-that-is-independent-of-each-br