Search code examples
windowsgitpowershelldirectory

PowerShell script to call git init in all subdirectories


I want to init repositories in all subdirectories in a given directory. Since there are about 200 of them (legacy projects), I want to automate it with PowerShell. So far I have:

 $items = Get-ChildItem -Path "."

    foreach ($item in $items)
    {
          if ($item.Attributes -eq "Directory")
          {
              $git = "C:\Program Files (x86)\Git\cmd\git"
              & $git "init"
          }
    }

Obviously I am missing a line where I make use of each subdirectory in the loop. In its current form, I believe all this does it call git init over and over in the same directory ("."), so what is the way to call git init from inside of each of the subdirectories? Is there a way to temporarily cd into each subdirectory found?

I tried something naïve like

& $item.Name + "\git init"

But it doesn't like that, for obvious reasons.


Solution

  • The cmdlets you are looking for are Push-Location and Pop-Location. The former will change the current working directory to whatever argument you pass to it. The old location will be stored on a stack. Once you have changed the directory using Push-Location, you can execute commands locally as if you manually cd’d into them. Afterwards, call Pop-Location to clear the stack and go back to the original directory.

    Btw. note that checking Attributes equality for "Directory" will not necessarily be good enough to identify directories. While you can be sure that you will only find directories using that, there may be other directories which have other attribute flags set as well. See also the FileAttributes enumeration.

    A better way to check for directories is to check the PSIsContainer property. It will simply be true for directories, and otherwise false.

    Using PowerShell’s piping, you can also write this all in a single line:

    Get-ChildItem | ? { $_.PSIsContainer } | % { Push-Location $_.FullName; git init; Pop-Location }
    

    This will first get all items in the current directory and push them into the pipe. Then they will be filtered for directories (? is filter), and then commands will be executed for each item that is left in the pipe (% is for each). So you call Push-Location to get to the directory’s location, call git init there, and then go back using Pop-Location.

    Note: If you are using PowerShell 3, you can also use Get-ChildItem -Directory to filter for directories right away.