[英]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/HEAD
, origin/master
等。
接下来,我们要跳过那些实际上是符号引用(例如HEAD
引用。 我们可以跳过文字HEAD,这要简单得多。 一种奇特的方法是使用git symbolic-ref
进行测试,但没有意义,由于历史原因,我们将看到的唯一实际的是HEAD,所以我们就可以这样做:
[ "$name" = origin/HEAD ] && continue
现在,我们需要做的是创建并签出一个本地分支,该分支将相应的远程跟踪分支设置为其上游。 我们可以使用内置的git checkout
在一个简单的步骤中完成此操作。
这也让我们避免使用特殊格式的master
: git 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 add
和git 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.