27

我正在使用我在开发环境中克隆的 5 个存储库。当我想更新 git repo 时,我进入文件夹 /home/adrian/repo1/ 并执行以下操作:

git checkout master git pull origin master

但是,每天早上我都必须为其他 4 个回购做同样的事情。这是相当麻烦的。

我可以把它放在一个shell脚本中吗?我的意思是,如果我在 shell 脚本中编写这些 git 命令并运行它,我能更新所有的 repos 吗?

本来想写这样的...

cd repo1
git checkout master 
git pull origin master
cd ..
cd repo2
git checkout master 
git pull origin master
cd ..

(我在linux上)

编辑:也许这比我想象的更具挑战性。大多数情况下,当我执行“git pull origin master”时,我会收到诸如“您对 .... 的本地更改将被合并覆盖”之类的错误。所以我必须进入各自的分支并把东西藏起来..

编辑2:

我正在考虑做的是,如果发生冲突,请忽略它并转到下一个 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 ..

但我不知道如何写括号中的内容。

4

4 回答 4

30

首先,我建议不要使用git pull. 相反,创建一个更安全的git up别名:

git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'

有关的解释,请参阅此答案git up

然后你可以安全地编写它:

#!/bin/sh
for repo in repo1 repo2 repo3 repo4; do
    (cd "${repo}" && git checkout master && git up)
done
于 2013-06-14T04:32:57.247 回答
6

由于我在本地检查了许多 git repo 以进行工作,因此我决定编写一个更详细的脚本来更新所有 repo(bash 脚本将搜索 git repos 最多 3 个文件夹深度进行更新。然后它将执行 git stash,获取, rebase, and stash pop the local changes back. 脚本在 Windows 上的 git bash shell 中运行。

#!/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!"
于 2016-04-22T18:15:16.460 回答
0

我知道我在这个问题上真的迟到了,但这是我为此目的编写的一个小 shell 脚本。

它可能看起来很业余,但那是因为它可能是!我写这篇文章主要是为了帮助自己学习 bash,但我希望它对你(或者现在可能正在阅读这篇文章的任何人)有所帮助。

您可以删除许多不必要的绒毛(例如更改文本的颜色,并列出具有未提交更改的存储库),您可以删除它们。

回购链接在这里


#!/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"
于 2019-04-11T05:02:05.203 回答
0

我建议使用 cron 脚本管理所有 repos 的更新。
这是一个自动更新其上游基础的示例脚本。

#!/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
于 2019-08-15T15:14:47.637 回答