可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Is it possible to add a sub folder with a .git folder to a repo, without Git treating it like a submodule? I've tried different methods to ignore that .git folder, but nothing this far has worked.
I have tried in /.gitignore:
/vendor/**/.git/
..and in /vendor/.gitignore:
.git/
The .git folder I want to ignore is in /vendor/foo/bar/.
回答1:
You can do this by directly adding some (any) internal content first. Git detects submodules by encountering the .git
entry when searching a newly-encountered directory, but if you give it an actual path to look for inside that directory it doesn't search.
So
git add path/to/some/submodule/file # bypass initial search that detects .git
git add path/to/some/submodule # now git's index has it as ordinary dir
回答2:
You can use git hooks to achieve what you want. Thinking out of the box, you could create a pre-commit hook that renames the .git directory of your included project, eg. to ".git2", add all files in the latter project except the ".git2" directory, commit all, push it and finally use post-commit hook to rename ".git2" folder back to ".git" in your module.
1) Create pre-commit file under .git/hooks/ of your root repo with contents:
#!/bin/sh
mv "vendor/foo/bar/.git" "vendor/foo/bar/.git2"
git rm --cached vendor/foo/bar
git add vendor/foo/bar/*
git reset vendor/foo/bar/.git2
2) Create post-commit file under .git/hooks/ also with contents:
#!/bin/sh
mv "vendor/foo/bar/.git2" "vendor/foo/bar/.git"
3) Change a file in your repo and finally:
git commit -a -m "Commit msg"
git push
My Original answer
回答3:
Your question intrigued me so I tried it:
$ cd /tmp
$ git init foo
Initialized empty Git repository in /private/tmp/foo/.git/
$ cd foo
$ git init bar
Initialized empty Git repository in /private/tmp/foo/bar/.git/
$ cd bar
$ echo "this is bar" > bar.txt
$ git add bar.txt
$ git commit -m "initial commit"
[master (root-commit) c9d6507] initial commit
1 file changed, 1 insertion(+)
create mode 100644 bar.txt
$ cd ..
$ pwd
/tmp/foo
$ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
bar/
nothing added to commit but untracked files present (use "git add" to track)
$ git add bar
$ git commit -m "parent initial commit"
[master (root-commit) b23e106] parent initial commit
1 file changed, 1 insertion(+)
create mode 100644 bar/bar.txt
$ echo "baz" > bar/.git/baz.txt
$ git status
On branch master
nothing to commit, working tree clean
As per your question, /tmp/foo
is a Git repository. And with respect to /tmp/foo
, /tmp/foo/bar
is a subdirectory which itself has a .git
directory.
As you can see, the parent foo
repository totally ignored the bar/.git
subdirectory and I didn't even need a .gitignore
file.
And there's no way Git treats a path containing a .git
folder as a submodule without having it registered in the .gitmodules
file.
回答4:
While it is true .git
is automatically ignored, the main repo will treat /vendor/foo/bar
as a gitlink (special entry in the main repo index), and not as regular files.
A trick would simply to move bar/.git
outside the main repo:
vendor/foo/bar
would be treated as a regular sub-folder, to be added to the main repo if need be.
- the bar repo can at any time detect changes and make commit if you preceded your
git
command with GIT_DIR=/path/to/bar/.git git ...
For instance:
cd /path/to/main/repo/vendor/foo/bar
GIT_DIR=/path/to/bar/.git git status
GIT_DIR=/path/to/bar/.git git add .
GIT_DIR=/path/to/bar/.git git commit -m "changes to bar"
GIT_DIR=/path/to/bar/.git git push
回答5:
As in jthill answer, you can add any item from subdirectory with .git
and it will be treated as subdirectory instead of sub-module.
But if you already registered this subdirectory as sub-module that has .git
you have to first remove that sub-module but leave it in your working tree - git rm --cached a/submodule
.
More info on: How do I remove a submodule?
Then you can repeat steps from jthill answer.
From my research there is no way to stop treating .git
folder as sub-module. So the best solution that I can think of right now is to have bash
or any similar script that you can run in any folder in console. It should find any subfolders that have .git
and attempt to add any file from that folder to the main .git
, so it would stop treating them as sub-modules.
Source of code below: Bash script to automatically convert git submodules to regular files
#!/bin/bash
# Get a list of all the submodules
submodules=($(git config --file .gitmodules --get-regexp path | awk '{ print $2 }'))
# Loop over submodules and convert to regular files
for submodule in "${submodules[@]}"
do
echo "Removing $submodule"
git rm --cached $submodule # Delete references to submodule HEAD
rm -rf $submodule/.git* # Remove submodule .git references to prevent confusion from main repo
git add $submodule # Add the left over files from the submodule to the main repo
git commit -m "Converting submodule $submodule to regular files" # Commit the new regular files!
done
# Finally remove the submodule mapping
git rm.gitmodules
Remember to always commit/backup changes before trying new scripts to prevent any work/data loss.
回答6:
You can use Git excludes for this.
First, create a .gitexclude file:
$ echo "vendor/*/.git" >> .gitexclude
Then add this file to your Git config as a source of exclusions:
$ git config core.excludesFile .gitexclude
Now you can add files and Git doesn't offer to add them as submodules:
$ git add vendor
$
You can verify that a file is indeed "invisible" to Git with git check-ignore
:
$ git check-ignore vendor/foo/.git
vendor/foo/.git
$ git check-ignore vendor/foo/bar.txt
$
Reference:
man git-add(1)
man git-check-ignore(1)
回答7:
Have you tried wildcards?
**/vendor/.git/