Make a shell script to update 3 git repos

2020-05-15 15:07发布

问题:

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.

回答1:

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


回答2:

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!"


回答3:

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"


回答4:

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


标签: git shell