繁体   English   中英

如何将.gitignore添加到Git存储库中的所有分支?

[英]How do i add .gitignore to all branches in repositories in Git?

我的存储库中有5个以上的分支机构。 我想将.gitignore文件添加到每个分支并将其推送到远程存储库。

克隆远程存储库后,我尝试一一运行以下命令。

我依次运行的命令:

 for branch in $(git branch --all | grep '^\s*remotes' | egrep --invert-match '(:?HEAD|master)$'); do    git branch --track "${branch##*/}" "$branch"; done

for branch in $(git branch); do    git checkout $branch && touch .gitignore; done

for branch in $(git branch); do    git checkout $branch && git status; done

for branch in $(git branch); do    git checkout $branch && echo ".classpath" >> .gitignore && echo ".project" >> .gitignore && echo ".settings/" >> .gitignore && echo "log/" >> .gitignore && echo "target/" >> .gitignore ; done

for branch in $(git branch); do    git checkout $branch && git add .gitignore; done

for branch in $(git branch); do    git checkout $branch && git commit -m 'Adding gitignore'; done

for branch in $(git branch); do    git checkout $branch && git push -u origin $branch; done

不知道,但是它没有按预期执行。

请帮忙。

首先, git branch是用户友好的,而不是编程友好的。 不要在编程时使用它:使用对编程友好的“管道”命令git for-each-ref

其次,正如Leon在评论中所说 ,编写您的脚本-一次性脚本是一个好主意,如果需要,可以在新的(新鲜,干净的)克隆上重复编写和重复使用,直到正确为止,这要容易得多,一个循环完成循环内的所有必要操作。

最后,根本不要在这里进行git push 单独进行。 Git具有内置的方式来推送“所有分支”。

您的第一个循环读取(使用我的格式):

 for branch in $(git branch --all | grep '^\s*remotes' |
         egrep --invert-match '(:?HEAD|master)$'); do 
     git branch --track "${branch##*/}" "$branch"
 done

看起来您想使用现有的远程跟踪分支origin/*或其他),并从它们创建新的本地分支,并将新的本地分支设置为将相应的远程跟踪分支作为其上游。 您出于某种原因(我想我知道原因)将master排除在外,并且还排除了显示为:

  remotes/origin/HEAD -> origin/master

您剩余的循环不会排除master循环(但也无法处理git branch打印的* ,因此它们至少会产生一些错误消息)。 因此,您似乎也想在master上执行此操作。 这意味着您可能只是在第一个循环中就已跳过它,因为它已经存在,在新克隆中通常为true 1

因此,让我们写一些我们希望在新的git clone上运行的东西,即,除了master之外没有分支的git clone (尽管,请再次参阅脚注1。)我们还将尝试在此过程中修复其他错误。

有一个小问题:在这里我们假设远程服务器的名称是origin ,因此远程跟踪分支的名称以refs/remotes/origin/开头。 这样可以更轻松地遍历所有名称并去除origin/前缀。 然后,我们将以此开始脚本:

for name in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin); do

这将遍历所有缩短的名称: origin/HEADorigin/master等。

接下来,我们要跳过那些实际上是符号引用(例如HEAD引用。 我们可以跳过文字HEAD,这要简单得多。 一种奇特的方法是使用git symbolic-ref进行测试,但没有意义,由于历史原因,我们将看到的唯一实际的是HEAD,所以我们就可以这样做:

    [ "$name" = origin/HEAD ] && continue

现在,我们需要做的是创建并签出一个本地分支,该分支将相应的远程跟踪分支设置为其上游。 我们可以使用内置的git checkout在一个简单的步骤中完成此操作。

这也让我们避免使用特殊格式的mastergit clone已经运行了git checkout master ,它创建了master并将其设置为origin/master作为其上游,但是无论如何我们都需要使用git checkout master 这将检出git clone创建的现有 master (当git clone运行git checkout master )。 因此,我们的下一步是构造正确的分支名称:

    branch=${name#origin/}
    git checkout $branch

例如,如果其中一个远程跟踪分支的名称为origin/feature/life而另一个分支的名称为origin/feature/zorg ,则我们只希望除去origin/ ,而不是“直到最后一个斜杠的所有内容”。 我们需要本地feature/life ,可以从中更新origin/feature/life

如果分支是master ,则它已经存在,并且将其检出。 如果分支为别的,它不存在,但由于这是一个新的克隆,只有一个远程跟踪分支确实存在,在一个用$name -所以我们将创建本地分支,检查出来,它将远程跟踪分支设置为其上游。

现在我们要创建一个.gitignore ,在其中放入一堆东西,添加并提交。 一个重要的问题是我们刚刚检出的提交中是否已经存在.gitignore ,如果存在,那么我们要怎么做。 我不能为你回答这个问题。 另一个是是否有我们即将加入这个文件.gitignore的承诺我们只签出的存在,如果是这样,做什么有关 再说一次, 无法回答。 我会注意,但是,该touch .gitignore其次是git status ,如果将只打印东西.gitignore是由新创建的touch 直接测试可能更明智:

    if [ -f .gitignore ]; then
        ... do whatever should be done here ...
    else
        ... create it ...
    fi

如果“无论做什么”都没有什么特别的,我们会更容易,因为我们可以简单地使用>>添加它,如果不存在它将创建它,如果存在则添加它。

除了使用五个单独的echo ... >> .gitignore ,我们还可以使用一只cat >> .gitignore和一个“ here-document”:

    cat << END >> .gitignore
.classpath
.project
.settings
log/
target/
END

现在我们像往常一样git addgit commit ,这就是循环的结尾:

    git add .gitignore
    git commit -m 'add gitignore'
done

将所有这些都写到一个shell脚本文件中( /tmp/doit.sh/tmp/t.sh是我最喜欢的此类脚本名称)。 添加#! /bin/sh -e #! /bin/sh -e行或在顶部set -e并使文件可执行-e确保在任何命令由于任何原因失败时脚本将退出。 (还添加了set -x来进行调试。)在循环之前添加一个显式的git clone行,以便克隆存储库,从而确保我们有一个全新的克隆。 切记也将目录更改为克隆。

本示例的其余部分将新存储库放入名为“ newrepo”的目录中。 使用mktemp -d创建一个临时目录可能更好。

#! /bin/sh -e
# set -x  # for debug
[ -d newrepo ] && { echo "error: newrepo directory already exists"; exit 1; }
git clone scheme://example.com/path/to/repo.git newrepo
cd newrepo
for name in ... # see above for the rest

现在,您可以运行/tmp/doit.sh并确保一切正常。 如果是这样,请继续; 如果不是,请修复脚本并重新开始。

一切正常后,我们就可以进行git push

$ cd newrepo
$ git push origin 'refs/heads/*:refs/heads/*'

最后一步是使用refspec进行推送 ,这里的refspec说:“对于我的每个分支,都使用相同的原产地名称进行礼貌(非强制)推送到原产地”。 因为我们确信有我们的分行具有相同的名称,如feature/life -作为那些origin ,这就是我们想要的。

(注意:以上内容完全未经测试。请注意错别字等。)

我已经按照@torek的建议解决了,您可以按照以下脚本添加.gitignore文件:

#! /bin/sh -e
# set -x  # for debug
[ -d mydir] && { echo "error: mydir directory already exists"; exit 1; }
git clone <git-repo-url> mydir
cd mydir
for name in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin); do
     [ "$name" = origin/HEAD ] && continue
     branch=${name#origin/}
     git checkout $branch
     echo ".classpath" >> .gitignore && echo ".project" >> .gitignore && echo ".settings/" >> .gitignore && echo "log/" >> .gitignore && echo "target/" >> .gitignore
     git add .gitignore
     git commit -m 'adding gitignore'
done

完成上述操作后,请使用以下命令推送代码:

git push origin 'refs/heads/*:refs/heads/*'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM