1

I have around 50 local folders that I intend to initialize as individual git repositories, to be hosted on GitHub.

I was wondering if there was an easier way to initialize multiple Git repositories other than individually running git init in each of the 50 folders.

I've been running git init individually for 2 repositories of the 50 already, but it seems so tedious, and I feel that there must be an easier way.

Update:

As referenced by this post, would I run the following the bash shell?

cd folder-with-all-folders-to-git-init
for D in `find . -type d`
do
    git init && git add . && git commit -m "Initial commit"
done
Riyaad Azad
  • 149
  • 1
  • 10
  • 2
    use [bash loop](https://stackoverflow.com/a/4000707/4648586)? – Bagus Tesa Dec 24 '18 at 01:26
  • Would I just copy/paste this in the bash shell? I'm not sure. – Riyaad Azad Dec 24 '18 at 01:34
  • @SergioTulentsev I edited my question to include what I intend to run in the bash shell. I'm a little nervous, but do you think that would really work? – Riyaad Azad Dec 24 '18 at 01:46
  • You'd need `(cd "$D"; git init && git add . && git commit -m "Initial commit")` to change into the directory before running `git init`. The `(…)` notation runs the command in sub-shell, which means you don't have to worry about how to get back after doing the `cd` command. – Jonathan Leffler Dec 24 '18 at 01:47
  • And by "$D", do you mean the folder with all the folders that I would like to "git init"? – Riyaad Azad Dec 24 '18 at 01:48
  • The `$D` is the variable set in the `for D in $(find . -type d)` loop. You might also think of using a glob and a 'test for directory': `for D in *; do if [ -d "$D" ]; then (cd "$D" && git init && …) fi; done`. That's more reliable if there are names with spaces around. – Jonathan Leffler Dec 24 '18 at 01:50
  • So I cd'ed to the folder with the 50 folders (that I want to turn into repos), then ran `for D in *; do if [ -d "$D" ];` I hit enter which took me to the angle-bracket thing (`>`) then I typed in `cd "$D" && git init && git add .` However, I cd'ed into one of the 50 folders and ran `git status` but it still says "Not a git repository" – Riyaad Azad Dec 24 '18 at 01:57
  • See my answer — I'm not sure what level of chaos you've created for yourself. You are testing in a directory with copies of just 3 folders, so that you aren't hurting yourself, aren't you? At this stage the `.git` repositories are very expendable. They soon won't be, but immediately after the first commit, they are. – Jonathan Leffler Dec 24 '18 at 02:00
  • @JonathanLeffler Luckily the first times I ran it I don't think anything bad happened (git status still showed no git repo). But once I ran your answer (the "robust" option) it worked. I only needed to do the initial commit all at one time. Thanks. – Riyaad Azad Dec 24 '18 at 02:09
  • You might want to check whether you have a folder `folder-with-all-folders-to-git-init/.git` and decide whether it is a repository you want — and if not, delete it. – Jonathan Leffler Dec 24 '18 at 02:16
  • @JonathanLeffler Luckily that parent folder was not init'ed as a Git repo. – Riyaad Azad Dec 25 '18 at 14:30

2 Answers2

2

You can use the -C option with Git, which tells Git to switch its working directory to another. This is safe with directory names with special characters.

cd folder-with-all-folders-to-git-init
while read -r D; do
  if [ -d "$D/.git" ]; then
    continue # a git repo exists
  fi

  git -C "$D" init &&
  git -C "$D" add -A &&
  git -C "$D" commit -m "Initial commit"
done < <(find . -type d)
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
iBug
  • 35,554
  • 7
  • 89
  • 134
  • One minor disadvantage of what you've got is that you don't abandon the processing if something goes wrong in the sequence of 3 commands. You can fix that by adding `&&` after each of the first two, so it is hardly a major problem. – Jonathan Leffler Dec 24 '18 at 01:58
  • And the directory names with newlines cause grief now … reading the output from commands like `find` is dodgy unless you're reasonably sure that the names never contain special characters. See the [Bash Guide](http://mywiki.wooledge.org/BashGuide/TestsAndConditionals) for 'tests and conditionals' and the [Bash FAQ](http://mywiki.wooledge.org/BashFAQ) — though I admit I didn't find exactly which FAQ question(s) covers the issues. – Jonathan Leffler Dec 24 '18 at 02:13
2

The outline command is partly correct and mostly not, but can be made correct enough.

You have:

cd folder-with-all-folders-to-git-init
for D in `find . -type d`
do
    git init && git add . && git commit -m "Initial commit"
done

At minimum, you need to cd into each directory before running git init. That should be done like:

cd folder-with-all-folders-to-git-init
for D in `find . -type d`
do
    (cd "$D" && git init && git add . && git commit -m "Initial commit")
done

This launches a subshell which avoids problems with symlinks and getting back to where you started.

Using back-quotes is not recommended; use the $( … ) notation instead. But reading names from that result is also not a good idea if there could be spaces in the names. You'd do best with a 'glob'. It might also be worth testing for the absence of a .git subdirectory before trying to do git init, especially if you have to run the script multiple times. Also, the find will find sub-directories, such as existing .git sub-directories.

That leads to:

cd folder-with-all-folders-to-git-init
for D in *
do
    if [ -d "$D" ] && [ ! -d "$D/.git" ]
    then (cd "$D" && git init && git add . && git commit -m "Initial commit")
    fi
done

This is a reasonably robust solution to the problem. If there really are nested directories that you want to make into independent Git repositories, you'll need to work a bit harder, but that probably isn't what you want.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • You can omit the check for `$D` being a directory by globbing `*/`. Also, `.git` may be a file. – o11c Dec 24 '18 at 03:11
  • @o11c: yes, that's a possible glob alternative. Bash is like Perl; there's more than one way to do it (TMTOWTDI). Yes, `.git` could be a file, or a character device, socket, block device, FIFO or … but then the `git init` will fail with an appropriate error (or what it deems an appropriate error), so the rest of the commands in the subshell won't be executed, and no damage will be done. There's also no guarantee that even if `.git` is a directory, it is actually a valid Git repository. It's just heading off the most probable problems (this directory got initialized; some others didn't). – Jonathan Leffler Dec 24 '18 at 03:15
  • `.git` can't *meaningfully* be a socket, etc. It's perfectly well-defined for it to be a text file, though, containing configuration pointing to a directory elsewhere. – o11c Dec 24 '18 at 07:55