I need to run git fetch after any cd command in the background and only if I'm in a git directory.
-
hi and welcome to Stack Exchange! I'm answering your question since it's easy, but in the future, please demonstrate to us that you've already made an attempt at solving your problem before coming here. thanks!– strugeeNov 2, 2016 at 22:15
3 Answers
There are three parts to this:
- Run some code on changing the current directory. In zsh, you put this code in the
chpwd
function, or a function with a different name in thechpwd_functions
array (example). See Execute bash scripts on entering a directory for a bash implementation. - Detect git working copies. Since you're only interested in git, you can run
git rev-parse --show-toplevel
. There are more advanced frameworks to detect version control if you're interested in other version control systems. - Run
git fetch
.
Here's a chpwd
implementation that runs git fetch
when changing into a git repository.
chpwd () {
set -- "$(git rev-parse --show-toplevel 2>/dev/null)"
# If cd'ing into a git working copy and not within the same working copy
if [ -n "$1" ] && [ "$1" != "$vc_root" ]; then
vc_root="$1"
git fetch
fi
}
chpwd
This code goes in your shell startup script: .zshrc
for zsh, .bashrc
for bash (in bash you also need the wrappers to call chpwd
on a directory change).
-
To avoid show of fatal error inside no git foldeers I changed this
set -- "$(git rev-parse --show-toplevel)" 2>/dev/null
intoset -- "$(git rev-parse --show-toplevel 2>/dev/null)"
– MauroMay 23 at 7:49
You can use a function:
function cd() {
builtin cd "$@"
if [[ -d .git ]]; then
git fetch &
fi
}
Add this to your shell's startup file.
There are a couple things that are going on here:
- First we use
function cd() {
to override the builtincd
behavior with our own custom code. - Obviously we still want to change the directory, so we do that first - we prefix it with
builtin
* so that the shell uses the builtincd
instead of recursively calling our customcd()
function, and we provide it with$@
as the arguments, which gets expanded by the shell to all arguments provided to the function. - We test if we're in a git repository^ by testing if the
.git
directory exists, and if it does we rungit fetch
, telling the shell to put it in the background by appending&
.
Note that the output of git fetch
will still be sent to the terminal. If you wish to discard it you can use this instead:
git fetch & 2>&1 >/dev/null
This redirects stderr into stdout, then sends stdout to /dev/null
.
[*]: Note that builtin
isn't in POSIX and therefore this solution isn't portable across all shells
[^]: This fails if the git repository is bare, but you almost certainly aren't going to have a bare repository on your drive, so who cares
-
That doesn't deal with pushd, with the multi-argument form of
cd
, etc. See unix.stackexchange.com/questions/21363/… for a more robust implementation. Nov 2, 2016 at 22:25 -
My shell doesn't support
command
so I renamed the function and just directly callcd "$@"
which appears to be working correctly however, catching stderr and stdout doesn't capture the command done output from the shell like :[3] + done git fetch 2>&1 > /dev/null
any suggestions on capturing that? Nov 2, 2016 at 22:35 -
@Gilles OP didn't ask about
pushd
and I thought $@ would expand to all arguments, hence handling the multi-argument form ofcd
. no?– strugeeNov 2, 2016 at 22:36 -
@north.mister you didn't specify your shell. since you mentioned bash and zsh I assumed it was one of the two - if you need code for a different shell, you should have said so.– strugeeNov 2, 2016 at 22:37
-
edited the answer to use
builtin
as that's probably more appropriate (and what I was thinking of in the first place)– strugeeNov 2, 2016 at 22:39
make a function in your .bashrc or .zshrc file that is in your home directory.
Add the following to the bottom of the file:
cd_fetch() {
command cd "$@"
if [ -d .git ]; then
git fetch &
fi
}
alias cdg=cd_fetch
Now close and re-open your terminal or run source ~/.zshrc
and now you can change directory with the command cdg
that you just aliased.
Also if you don't want to use cdg
and want to use just cd
change the alias definition to alias cd=cd_fetch
.
This approach will still output all that git fetch normally do, to silence it replace the git fetch &
line for git fetch 2>&1 >/dev/null &
.
-
2This doesn't deal with pushd or with failure of
cd
; see unix.stackexchange.com/questions/21363/… for a more robust implementation. This doesn't handle changing to a subdirectory of the git repository. Nov 2, 2016 at 23:43