Let's say I've got the following directory structure.
.ProjectFolder
|-A
|-B
|-C
Where A,B and C are all github projects.
I could do
git submodule foreach git checkout <branch> && git submodule foreach git pull
to checkout and pull each one to the most recent version of . However, let's say that I have some work done on A locally, and git will tell me that it cannot check out to because of my uncommited work.
I would like to write a bash script that goes inside of each folder, checks out said branch if possible, then performs a set of actions. Say
for item in $(ls);do
cd ./$item
git checkout <branch>
git pull
cd ..
done
The issue with that is "cd". When I try doing that, it doesn't seem to go into the folder. I've browsed a bit around and I've seen that happens because "cd" runs a subshell, then exits, leaving me in the same place as before. I've tried sourcing the file rather than running it, and that didn't seem to work either.
Does anybody have any alternative? (preferably, alternatives that don't use aliases for "cd").
The reason why i'd like to do it this way is because I'd like to extend that functionality at some point I.E. checkout to a new local branch, commit the changes to that branch, then attempt to checkout the branch I was interested in.
CodePudding user response:
When I try doing that, it doesn't seem to go into the folder...
If I have the same project structure:
$ tree ProjectFolder
ProjectFolder/
├── A
├── B
└── C
And inside that folder I run your script, but I replace the git
commands with pwd
, we can see that it works exactly as intended:
$ cd ProjectFolder
$ for item in $(ls); do
> cd ./$item
> pwd
> cd ..
> done
.../ProjectFolder/A
.../ProjectFolder/B
.../ProjectFolder/C
So we know the cd
is working. If we run the git
commands instead,
it also seems to work:
$ for item in $(ls); do
> cd ./$item
> git checkout testbranch
> git pull
> cd ..
> done
branch 'testbranch' set up to track 'origin/testbranch' by rebasing.
Switched to a new branch 'testbranch'
Already up to date.
branch 'testbranch' set up to track 'origin/testbranch' by rebasing.
Switched to a new branch 'testbranch'
Already up to date.
branch 'testbranch' set up to track 'origin/testbranch' by rebasing.
Switched to a new branch 'testbranch'
Already up to date.
That also seems to work.
I would make suggest a few changes to your script:
Don't use
ls
; just use wildcard expansion:for item in *; do
Consider some defensive coding to make sure your targets are git repositories:
for item in *; do [ -d "$item/.git" ] || continue done
This prevents your script from breaking or throwing up errors if
ProjectFolder
contains files or non-git-repository directories.You don't need to use
cd
at all if you use the-C
option togit
:for item in *; do [ -d "$item/.git" ] || continue git -C "$item" git checkout testbranch git -C "$item" git pull done
CodePudding user response:
I tried your script in git bash and it worked. To avoid cd
, we have at least 2 options.
One is to export GIT_DIR and GIT_WORKTREE,
for item in $(ls);do
export GIT_DIR=${item}.git
export GIT_WORKTREE=${item}
git checkout <branch>
git pull
done
unset GIT_DIR
unset GIT_WORKTREE
The other is to use --git-dir and --work-tree,
for item in $(ls);do
git --git-dir=${item}.git --work-tree=${item} checkout <branch>
git --git-dir=${item}.git --work-tree=${item} pull
done
In order to run the script in any directory, it's better to pass the absolute paths to gitdir and worktree.