问题
I think this issue has already been discussed under this question :
Recursively add the entire folder to a repository
However I still can not add some folders to a git repository and I need help.
$ git status
...
# modified: folder_to_add1 (modified content, untracked content)
# modified: folder_to_add2 (modified content, untracked content)
These folders originally belonged to another git repository, so I entered the folders and deleted the .git folder inside.
I then ran:
$ git add folder_to_add1
$ git add folder_to_add2
$ git status
# On branch master
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
# (commit or discard the untracked or modified content in submodules)
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# ../filestore/
# ../../stdout
no changes added to commit (use "git add" and/or "git commit -a")
Neither folder_to_add1 and folder_to_add2 can be committed.
There is no .gitignore file in my repo.
What else can I try ? Thanks.
I will try to add further information regarding my original post which ended right before previous line. I will appreciate your comments regarding "this" being considered the right war to further clarify my original question, I am a complete newbie posting here.
Dear torek, thanks for your very detailed answer. I guess I will have to read it very carefully to understand the subtleties involved with the submodules concept. I guess submodules are very much like "svn externals" which I am more familiar with.
From a ten minutes reading of your answer, my answer is: "I do not want a submodule or subgit at all". I mean: I want these folders, originally being submodules, to be part of only one project instead of many projects (to use a figure).
I am sure your answer is somewhere telling me why this is happening, but the fact is that I need to copy my project from one PC to another one and by using git to do it, these folders are actually not included in the index with "git add " regardless of whether there is a .git subfolder in them or not.
A ".gitmodules" file does not seem to exist. After running :
$ find . -name .gitmodules -print
on the main folder of the project I get no results.
What I did to be able to add these folders to a new (different) repository was:
$ cp -r myproject /home/myusername/newproject
$ cd /home/myusername/newproject/folder_to_add1
$ rm -r .git
$ cd ../folder_to_add2
$ rm -r .git
$ cd /home/myusername/newproject
$ git init
$ git add .
$ git commit -m "Adding all existing files to the new repository"
But I think I loose all file changes history by doing it this way.
回答1:
Whenever you see:
modified: some-name (modified content)
in git status
output, this means that your Git repository thinks that the directory named some-name
is part of some other Git repository. (Note that the sub-directory / folder name here, some-name
in this example, does not end with a slash.)
One way that I find helpful to think about this issue is to pretend that there are multiple Gits involved (because there are): one is your Git, working in your repository, and the other in this case is the folder or subdirectory's Git, working in this second Git repository. And it is—or at least was—a second Git repository, at some point.
This bears repeating: this sub-directory / folder really was some other Git repository before. It may or may not still be a second repository. Moreover, your own Git repository has already recorded the presence of the other Git in some way. If your Git repository had not recorded that, you would have seen:
Untracked files:
(use "git add <file>..." to include in what will be committed)
subgit/
Instead, though, you are seeing:
Changes not staged for commit:
...
modified: subgit (modified content)
So, the fact that your Git repository's git status
output says modified content
or untracked content
means your repository is quite certain that this sub-directory is some other repository. Your repository is reporting the relative state of the other repository.
You can get another hint about this if you use git status -uall
, or git status --untracked-files=all
(these mean the same thing, -u
is short for --untracked-files=
): if your Git doesn't think the sub-directory contains another Git repository, it will look inside the sub-directory and tell you about each file in the directory. If your Git is convinced that the sub-directory is a Git repository of its own, it won't look inside it and report each file—but your Git also won't say "modified content" or "untracked content" like this.
What to do about this depends on what you want to happen in the end
First, we need to talk about submodules.
Submodules
Git has a concept called submodules. Some people call them sob-modules because they make programmers cry. 😀 A submodule essentially means: I tell my Git to record information about another Git repository.
Now, think about the way you clone a Git repository. It's with one simple command: git clone url name
, or maybe even just git clone url
with the resulting clone going into a directory/folder name based on the URL. (Giving the name
argument picks the directory/folder name instead of letting the URL dictate it.)
So, if your repository—which we'll call the superproject since it supervises some sub-Gits—is going to refer to some other repository, what your Git is going to need is:
- the URL it should clone
- the directory/folder name it should use when cloning
These two pieces of information are, in a proper submodule, stored in a file named .gitmodules
in the top level of the superproject.
This .gitmodules
file is needed to make a new clone of the superproject. It's only needed in a new clone! If you already have a clone, that's working and is managing its sub-repositories, the contents of the .gitmodules
file don't matter any more.
With or without .gitmodules
, your Git also records more about the submodule
Every Git repository has three parts:
- Git stores the
.git
repository itself. This contains a couple of databases that you don't need to poke around in yourself. - Git also stores something called, variously, the index, the staging area, or the cache. What it's called depends on who or which part of Git is doing the calling, but all three are names for the same thing.
- Git provides for you a work-tree. The files inside your Git repository are stored in a special, frozen, compressed, Git-only format. They can't be changed. They can be added-to, as in adding more versions of files, but they're all just historical records. So you need a place where you can get at those files, in ordinary non-Git format, and work on and with them. That's your work-tree.
The work-tree is often the part of Git you work with the most—well, naturally, it's right there in the name, isn't it? And yet, Git doesn't really use the work-tree, in a sense. It puts files into it, for you to use; and when you run git add
, your Git copies files out of the work-tree, into that thing in #2 above: they go into the index.
When Git makes a new commit, Git uses the files that are in the index. It's the presence of a file in the index that makes a file tracked in the first place. When you have Git fill in your work-tree, using git checkout
to extract a commit, Git first fills in your index. All of the real Git action is taking place in this index: existing commits go into it, and new commits are made from it. So it's the index, not the work-tree, that really matters, at least as far as new commits go. No matter what you do in the work-tree, Git only really pays attention to the index. This is why you have to keep using git add
all the time: it's the copy of each file in the index that matters to Git.
In short, your index holds what will go into the next commit you make. It has inside it a copy of all of your files, in the pre-Git-ified, ready-to-freeze forever format. That's what makes your index so crucial. If you change a work-tree file you must use git add
to copy (and Git-ify) the file to be ready for the next commit.
So, for Git, what matters are commits, identified by their big ugly hash IDs—which are unique: no two different commits ever have the same hash ID—and the index that it uses to make new commits. You use the work-tree to do your work, but then you update your Git's index and have your Git make a new commit from it.
This is where submodules come in again, too. If your Git is acting as a superproject, supervising some sub-Git in some folder named subgit/
for instance, then your Git will record their Git's commit hash ID, in your index!
Think about that for a while. Your Git doesn't save their Git's files. Your Git knows that if their Git—the Git in your subgit/
folder—has saved some files in a commit, that commit hash ID is good forever. That one simple hash ID, big and ugly as it may be, uniquely identifies all those files, in their saved-forever form. So your Git does not need to save the files. All it has to do is save their commit's hash ID.
That's exactly what your superproject Git does. Instead of saving files—their files—your Git just saved their commit hash ID, in your index. And then, since it's in your index, it goes into your commits, too. From this point forward, every new commit you make contains their hash ID. If you want to record a different hash ID, you tell them—the other Git, the one in control of the subgit/
folder—to switch to a different commit hash ID, or to make a whole new commit; and then you have your Git record that hash ID in your index, so that your next commit has the right subproject hash ID.
Note that all of this works even without a .gitmodules
file. But if you don't have a .gitmodules
file, this superproject that supervises some other Git repository works here, but you won't be able to clone it easily later.
Now you must decide: do you want a submodule, or not?
If you want submodules, well, you're already there—or at least halfway there. If you have a .gitmodules
file that lists the subproject repository, your superproject already records the correct URL and name for future clones. If not, you should probably create a .gitmodules
file, using git submodule add
. See also How to `git submodule add` Existing sub Repository? (This answers the question of how to fix up a subproject repository that wasn't added properly originally, but that you do want to use as a proper submodule.)
So you want a submodule, and already have it in .gitmodules
Given that you have decided that you do want to use a submodule, and that it's all correctly recorded, what you need to do now is not git add subgit
. As you already saw, that doesn't do anything!
Instead, what you need to do is to start a new session—by cd
-ing into the submodule, or opening a new window in which you start working in the submodule, or whatever. Now you're in a new and different repository! But, uh oh, you're probably in detached HEAD mode.
That's OK: you can choose to work in this mode. Or, you can run git checkout somebranch
to get on some branch, or git checkout -b newbranch
to create a new branch at the current commit. You should do whatever makes sense for this Git repository.
Now that you are in this new and different repository, you can work as usual, with your work-tree. Once you have all the files arranged the way you want, on the branch you want, you will git add
modified files and/or git add
untracked files to copy them into the index. You then git commit
the result. And now you have a new commit, and you can git push
it or whatever it is that you do with these commits in this repository.
Now that you're done making the new commit that holds the updated and/or new files in the subproject, now you can go back to the superproject. You cd
back to the superoject, or close this window, or whatever, and resume work in the superproject.
Now all you have to do in the superproject is run git add subproject
. If the subproject is named subgit
, just git add subgit
. That copies the sub-repository's commit hash ID into your index, so now it's ready to commit. Add anything else you like, and run git commit
to make a new commit that freezes all your index contents forever. That saves your files, and your subproject's commit hash ID, all of which were ready to go in your index.
So you don't want a submodule or subgit at all
This one is a little harder, especially in very old versions of Git. Modern Git makes it much easier. So here I'm going to outsource the entire answer to How do I remove a submodule? Note that most of the answers, including this short one for modern Git, have the idea that you're also going to remove the entire work-tree of the sub-repository. If you want to keep the work-tree, the simplest method is just to move or copy it somewhere else. Be sure to save the files that are modified and/or untracked, since they're probably not in any commit in the sub-repository!
来源:https://stackoverflow.com/questions/54907159/unable-to-add-folder-to-git-repo