Unverified Commit 05e2956d authored by Marc Cornellà's avatar Marc Cornellà Committed by GitHub
Browse files

fix(git-auto-fetch): background `git-fetch-all` and other fixes (#9468)

parent d8888719
# Git auto-fetch
Automatically fetches all changes from all remotes while you are working in git-initialized directory.
Automatically fetches all changes from all remotes while you are working in a git-initialized directory.
#### Usage
Add `git-auto-fetch` to the plugins array in your zshrc file:
To use it, add `git-auto-fetch` to the plugins array in your zshrc file:
```shell
plugins=(... git-auto-fetch)
```
Every time you launch a command in your shell all remotes will be fetched in background.
By default autofetch will be triggered only if last fetch was done at least 60 seconds ago.
You can change fetch interval in your .zshrc:
```
GIT_AUTO_FETCH_INTERVAL=1200 #in seconds
## Usage
Every time the command prompt is shown all remotes will be fetched in the background. By default,
`git-auto-fetch` will be triggered only if the last auto-fetch was done at least 60 seconds ago.
You can change the fetch interval in your .zshrc:
```sh
GIT_AUTO_FETCH_INTERVAL=1200 # in seconds
```
Log of `git fetch --all` will be saved into `.git/FETCH_LOG`
A log of `git fetch --all` will be saved in `.git/FETCH_LOG`.
## Toggle auto-fetch per folder
#### Toggle auto fetch per folder
If you are using mobile connection or for any other reason you can disable git-auto-fetch for any folder:
If you are using a mobile connection or for any other reason you can disable git-auto-fetch
for any folder:
```shell
$ cd to/your/project
......@@ -29,3 +32,19 @@ disabled
$ git-auto-fetch
enabled
```
## Caveats
Automatically fetching all changes defeats the purpose of `git push --force-with-lease`,
and makes it behave like `git push --force` in some cases. For example:
Consider that you made some changes and possibly rebased some stuff, which means you'll
need to use `--force-with-lease` to overwrite the remote history of a branch. Between the
time when you make the changes (maybe do a `git log`) and the time when you `git push`,
it's possible that someone else updates the branch you're working on.
If `git-auto-fetch` triggers then, you'll have fetched the remote changes without knowing
it, and even though you're running the push with `--force-with-lease`, git will overwrite
the recent changes because you already have them in your local repository. The
[`git push --force-with-lease` docs](https://git-scm.com/docs/git-push) talk about possible
solutions to this problem.
GIT_AUTO_FETCH_INTERVAL=${GIT_AUTO_FETCH_INTERVAL:=60}
# Default auto-fetch interval: 60 seconds
: ${GIT_AUTO_FETCH_INTERVAL:=60}
# Necessary for the git-fetch-all function
zmodload zsh/datetime zsh/stat
function git-fetch-all {
(`command git rev-parse --is-inside-work-tree 2>/dev/null` &&
dir=`command git rev-parse --git-dir` &&
[[ ! -f $dir/NO_AUTO_FETCH ]] &&
(( `date +%s` - `date -r $dir/FETCH_LOG +%s 2>/dev/null || echo 0` > $GIT_AUTO_FETCH_INTERVAL )) &&
(
# Get git root directory
if ! gitdir="$(command git rev-parse --git-dir 2>/dev/null)"; then
return 0
fi
# Do nothing if auto-fetch disabled
if [[ -z "$gitdir" || -f "$gitdir/NO_AUTO_FETCH" ]]; then
return 0
fi
# Get time (seconds) when auto-fetch was last run
lastrun="$(zstat +mtime "$gitdir/FETCH_LOG" 2>/dev/null || echo 0)"
# Do nothing if not enough time has passed since last auto-fetch
if (( EPOCHSECONDS - lastrun < $GIT_AUTO_FETCH_INTERVAL )); then
return 0
fi
# Fetch all remotes (avoid ssh passphrase prompt)
GIT_SSH_COMMAND="command ssh -o BatchMode=yes" \
command git fetch --all 2>/dev/null &>! $dir/FETCH_LOG &)
command git fetch --all 2>/dev/null &>! "$gitdir/FETCH_LOG"
) &|
}
function git-auto-fetch {
`command git rev-parse --is-inside-work-tree 2>/dev/null` || return
guard="`command git rev-parse --git-dir`/NO_AUTO_FETCH"
# Do nothing if not in a git repository
command git rev-parse --is-inside-work-tree &>/dev/null || return 0
(rm $guard 2>/dev/null &&
echo "${fg_bold[green]}enabled${reset_color}") ||
(touch $guard &&
echo "${fg_bold[red]}disabled${reset_color}")
# Remove or create guard file depending on its existence
local guard="$(command git rev-parse --git-dir)/NO_AUTO_FETCH"
if [[ -f "$guard" ]]; then
command rm "$guard" && echo "${fg_bold[green]}enabled${reset_color}"
else
command touch "$guard" && echo "${fg_bold[red]}disabled${reset_color}"
fi
}
# Override zle-line-init if it exists
if (( $+functions[zle-line-init] )); then
eval "override-git-auto-fetch-$(declare -f zle-line-init)"
# zle-line-init widget (don't redefine if already defined)
(( ! ${+functions[_git-auto-fetch_zle-line-init]} )) || return 0
function zle-line-init () {
case "$widgets[zle-line-init]" in
# Simply define the function if zle-line-init doesn't yet exist
builtin|"") function _git-auto-fetch_zle-line-init() {
git-fetch-all
override-git-auto-fetch-zle-line-init
}
else
function zle-line-init () {
} ;;
# Override the current zle-line-init widget, calling the old one
user:*) zle -N _git-auto-fetch_orig_zle-line-init "${widgets[zle-line-init]#user:}"
function _git-auto-fetch_zle-line-init() {
git-fetch-all
}
fi
zle _git-auto-fetch_orig_zle-line-init -- "$@"
} ;;
esac
zle -N zle-line-init
zle -N zle-line-init _git-auto-fetch_zle-line-init
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment