I got tens of repos, my script should update them if any difference happened, new commits, new tag, new branch. Fetch is kind of slow for tens of repos in my case, I'd like to know if there is any quick command could meet my requirement.
You can use the git ls-remote
plumbing command to obtain the state of the remotes without fetch.
Here, let’s use git itself as a lightweight database, to keep track of the state of the remote.
Put the following in a script; you can enable it later as a git alias shell function for convenience. Run inside your repo.
REMOTE_SUM=$(git ls-remote --tags --heads 2>/dev/null | git hash-object --stdin)
if git cat-file -e $REMOTE_SUM
then
echo Remote check-summed up-to-date.
else
echo Remote changed, fetching...
git ls-remote --tags --heads 2>/dev/null | \
git hash-object -w --stdin &>/dev/null
git fetch
fi
Some of the necessary error checking was omitted, and code was duplicated for sake of clarity.
Explanation
Listing all the remote tips with git ls-remote --tags --heads
generates output such as:
From /home/user/tmp/repo2 777201715768a4d82f374f7224e68164a916ac1f refs/heads/bar 78981922613b2afb6025042ff6bd878ac1994e85 refs/heads/master ...
In turn we hash the above picture of the remote repo as a single hash via git hash-object --stdin
and check if we've previously seen it by querying for the hash in git with git cat-file -e
. If we haven't seen it, the remote picture must have changed, and we record it first in git with git hash-object -w
, to accommodate races between pulling and committing on the remote, and then proceed to fetch the remote.
One can integrate this with a git pre-fetch functionality: pre-fetch hook functionality in git, but that's out of the scope of this answer.
Addendum
Note that the above will generate loose objects in git that occasionally will need to be garbage collected with git gc
, and possibly --prune
explicitly.
Further, the above should work as long as commits are not rearranged on purpose in such a way that branch tips remain the same. This would be /quite uncommon/ and goes against git guidelines of changing pushed state, but hey, the worst thing that can happen is that you skip a fetch.
Also note that ls-remote
works on a single remote. To work with multiple remotes, you'll have to extend the script by generating a list of remotes with git remote show
and work with each one in turn.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With