I am working with 5 repos that I have cloned in my development environment.
When I want to update a git repo, I enter the folder /home/adrian/repo1/ and do:
git checkout master
git pull origin master
But then, every morning I have to do the same thing for the other 4 repos. This is quite troublesome.
Can I put this in a shell script? I mean, if I write these git commands in the shell script, and run it, will I be able to update all the repos?
I was thinking of writing something like this...
cd repo1
git checkout master
git pull origin master
cd ..
cd repo2
git checkout master
git pull origin master
cd ..
(i'm on linux)
Edit: Maybe this is more challenging than what I thought. Most times when I do "git pull origin master", i get erorrs like "Your local changes to .... would be overwritten by merge." So i have to enter into the respective branch and stash the stuff..
Edit 2:
What I'm thinking of doing is, if a conflict happens, ignore it and go to the next repo
cd repo1
git checkout master
git pull origin master
(if there is conflict, ignore and go to the next line but dont stop here)
cd ..
cd repo2
git checkout master
git pull origin master
cd ..
but i dont know how to write the thing in parenthesis.
First, I recommend against using git pull
. Instead, create a safer git up
alias:
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
See this answer for an explanation of git up
.
Then you can safely script it:
#!/bin/sh
for repo in repo1 repo2 repo3 repo4; do
(cd "${repo}" && git checkout master && git up)
done
As I have many git repo's checked out locally for work, i decided to write a more detailed script to update all the repo's (bash script will search for git repos up to 3 folders deep to update. It will then do a git stash, fetch, rebase, and stash pop the local changes back. Script for me runs in git bash shell on windows.
#!/bin/bash
# Usage:
# ./update_git_repos.sh [parent_directory]
# example usage:
# ./update_git_repos.sh C:/GitProjects/ [MAKE SURE YOU USE / SLASHES]
updateRepo() {
local dir="$1"
local original_dir="$2"
cd $dir # switch to the git repo
repo_url=$(git config --get remote.origin.url)
echo "****************************************************************************"
echo "Updating Repo: $dir with url: $repo_url"
echo "Starting update in $PWD"
main_branch="master"
if [ "$repo_url" == "git@someserver:repo/repo.git" ]; then # if you have a repo where the primary branch isnt master
$main_branch="trunk"
fi
# update the repo, then stash any local changes
echo -e "\ncalling: git fetch --all && git stash"
(git fetch --all && git stash)
current_branch=$(git rev-parse --abbrev-ref HEAD)
# switch to master/trunk branch and rebase it, then switch back to original branch
if [ $current_branch != $main_branch ]; then
echo -e "\ncalling: git checkout $main_branch && git rebase && git checkout $current_branch"
(git checkout $main_branch && git rebase && git checkout $current_branch)
fi
# rebase the original branch and then stash pop back to original state
echo -e "\ncalling: git rebase && git stash pop on branch: $current_branch"
(git rebase && git stash pop )
#switch back to the starting directory
cd $original_dir
echo ""
}
directory_to_update=${1}
if [ -z "$directory_to_update" ] ; then
echo "no directory passed in, using current directory"
directory_to_update=$PWD
fi
echo "Updating git repo's in directory: $directory_to_update"
count=0
for dir in $(find $directory_to_update -maxdepth 4 -type d -name .git | xargs -n 1 dirname); do
updateRepo $dir $directory_to_update #& #uncomment to make it run in multiple threads, meh
((count+=1))
done
echo "$count local git repos have been updated!"
I know I'm really late to the party on this question, but here's a little shell script I wrote for this exact purpose.
It probably seems very amateurish, but that's because it probably is! I mainly wrote this to help myself learn bash, but I hope it helps you (or whoever may be reading this right now).
There's a lot of unnecessary fluff on this that you can remove (like changing the color of the text, and listing the repositories with uncommitted changes) that you can remove.
The link to the repo is here
#!/bin/bash
declare -a my_array
for f in *; do
if [ -d "$f" ] ; then
cd "$f"
echo -e "\n ------------------ NEW REPOSITORY ------------------\n"
echo "Now checking $f"
if [ -d .git ] ; then
git add .
git diff-index --quiet HEAD --
if [ "$?" -ne 0 ] ; then
echo "THE REPO NEEDS TO BE COMMITTED"
my_array=( "${my_array[@]}" "${PWD##*/}" )
fi
git status
git push
git pull
fi
cd ..
fi
done
RED=`tput setaf 1`
reset=`tput sgr0`
green=`tput setaf 2`
if [ ${#my_array[@]} -ne 0 ]; then
var=$(IFS=' '; echo "${my_array[*]}")
var="${RED}$var${reset}"
if [ ${#my_array[@]} -eq 1 ]; then
var="The repository $var"
var="$var has uncomitted changes."
else
var="The repositories $var"
var="$var have uncomitted changes."
fi
echo "$var"
I would suggest to manage the update of all the repos with a cron script.
Here is an example script for auto update base to their upstream.
#!/bin/bash
repo_update() {
echo -e "\nUpdating $1" && cd $1
if [[ `git rev-parse --abbrev-ref HEAD` != master ]]; then git checkout master; fi
GIT_URL=$(git config --get remote.origin.url) && REMOTE=${GIT_URL##*:}
REMOTE=https://api.github.com/repos/${REMOTE%.*}
UPSTREAM=$(curl -s $REMOTE | jq -r '.parent.ssh_url')
if [[ $UPSTREAM == null ]]; then return 1; fi
if grep -q $UPSTREAM << EOF
`git remote -v`
EOF
then
git remote set-url upstream $UPSTREAM
else
git remote add upstream $UPSTREAM
fi
git fetch --prune upstream
if [[ `git rev-list HEAD...upstream/master --count` == 0 ]]
then
echo -e "all the same, do nothing"
else
echo -e "update exist, let's checking!"
git pull --rebase upstream master
git reset --hard upstream/master
push $GIT_URL
fi
}
# Check connection
ssh-add -l &>/dev/null
if [[ "$?" == 2 ]]; then eval `ssh-agent` > /dev/null; fi
# Check identity
ssh-add -l &>/dev/null
if [[ "$?" == 1 ]]; then expect $HOME/.ssh/agent > /dev/null && ssh-add -l; fi
# Update repositories
find ~/.gits -maxdepth 1 -mindepth 1 -type d | while read repo; do repo_update $repo; done