Execute a command from another directory in bash
Say that I'm doing this:
cd subdir
git init
cd ../
Is there a way to do this with a single command, or perhaps two, rather than having to move in and out of a directory in order to run a command there?
(Not looking for a git-specific solution; that's just an example.)
This is often the best way:
( cd dir ; git init )
or
( cd dir && git init )
It's pretty short and easy to type. It does start a sub-shell, so you can't modify your environment from that, but that doesn't seem to be an issue here.
I was looking for a way to execute the git command from a path, and make changes to the repository in a different path. So I ended up in this question here.
But for my specific needs neither the accepted answer nor any of the other ones helped.
I needed to run git commands using sudo -u USER /usr/bin/git
(another user running it). And as you may know, sudo doesn't allow me to run the cd
command, so I can't be in the repository directory.
So, I went to git's man page. And among the options, I saw the --git-dir=<path>
:
--git-dir=
Set the path to the repository. This can also be controlled by setting the GIT_DIR environment variable. It can be an absolute path or relative path to current working directory.
So, if it help someone, you can still use git from a path and make changes to a repository "far from you". Just use:
git --git-dir=/path/to/repository GIT_COMMAND
or, to run it as another user, do something like:
echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir=/path/to/repository GIT_COMMAND
Also from git-init's man page:
If the $GIT_DIR environment variable is set then it specifies a path to use instead of ./.git for the base of the repository.
So, if you want to init the repository under the usual .git folder, you will need to specify it together with the --git-dir
option. e.g.:
echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir=/path/to/repository/.git init
After initializing the repository on /path/to/repo/.git
, all further commands should have the option --work-tree=<path>
, as described on git's man page:
--work-tree=
Set the path to the working tree. It can be an absolute path or a path relative to the current working directory. This can also be controlled by setting the GIT_WORK_TREE environment variable and the core.worktree configuration variable (see core.worktree in git-config(1) for a more detailed discussion).
So, the right command to run git as another user, and initialize a new repository is:
echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir=/path/to/repository/.git init
echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir='/path/to/repository/.git' --work-tree='/path/to/repository' add /path/to/repository/*
echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir='/path/to/repository/.git' --work-tree='/path/to/repository' commit -m 'MESSAGE'
echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir='/path/to/repository/.git' --work-tree='/path/to/repository' remote add origin [email protected]:path
echo USER_PASSWORD | sudo -u USER_LOGIN -S /usr/bin/git --git-dir='/path/to/repository/.git' --work-tree='/path/to/repository' push -u origin master
Not exactly what you're asking (you have real answers above with the subshell) but look at pushd
and popd
You have a few options. You can either group the commands with &&
or ;
. Like this:
cd subdir && git init && cd ..
or
cd subdir; git init; cd ..
The difference between these is that in the first example, if one of the commands fails, it will not execute the rest of them. In the second example, all of the commands will run no matter what.
Another option would be to define a function and use it, for instance:
function cdinit() {
cd $1
git init
cd ..
}
Then you can run the command:
cdinit subdir
And it will automatically git init
in that directory and move out of it.
You could also do a more complex solution using a function if you have a bunch of directories and want to git init
them with one command.
function cdinit() {
for arg in $@
do
cd $arg
git init
cd ..
done
}
You can then run this with:
cdinit subdir1 subdir2 subdir3
And it will do git init
in subdir1
, subdir2
, and subdir3
.
In case of git
(at least in version 2.7.0), you can leverage the -C
option which makes git behave as if it was started in the given directory. So your solution may look like:
> git -C subdir init
Initialized empty Git repository in /some/path/subdir/.git/
Quoting the documentation:
Run as if git was started in <path> instead of the current working directory. When multiple -C options are given, each subsequent non-absolute -C
<path> is interpreted relative to the preceding -C <path>.
This option affects options that expect path name like --git-dir and --work-tree in that their interpretations of the path names would be made
relative to the working directory caused by the -C option.