如何将.gitignore添加到Git中存储库中的所有分支?
我的存储库中有5个以上的分支。 我想将.gitignore文件添加到每个分支,并将其推送到远程存储库 在克隆远程存储库之后,我尝试逐个运行以下命令 我按顺序运行的命令:如何将.gitignore添加到Git中存储库中的所有分支?,git,github,Git,Github,我的存储库中有5个以上的分支。 我想将.gitignore文件添加到每个分支,并将其推送到远程存储库 在克隆远程存储库之后,我尝试逐个运行以下命令 我按顺序运行的命令: for branch in $(git branch --all | grep '^\s*remotes' | egrep --invert-match '(:?HEAD|master)$'); do git branch --track "${branch##*/}" "$branch"; done for bran
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用于每个ref
其次,正如编写脚本一样——一次性脚本是个好主意,如果需要,在新的(新鲜、干净的)克隆上重复编写和使用脚本要容易得多,直到通过一个循环完成循环中所有必要的操作
最后,根本不要在这里进行git推送。分开做。Git有一种内置的方式来推动“所有分支”
您的第一个循环读取(使用我的格式):
这看起来像是您希望使用现有的远程跟踪分支(origin/*
或其他任何分支)并从中创建新的本地分支,将新的本地分支设置为将相应的远程跟踪分支作为其上游。出于某种原因(我想我知道原因),您排除了master
,并且您还排除了恼人的符号HEAD ref,它显示为:
remotes/origin/HEAD -> origin/master
其余循环不排除master
(但也无法处理git分支打印的*
,因此它们至少会产生一些错误消息)。因此,看起来您也希望在master
上执行此操作。这意味着您可能在第一个循环中跳过它,因为它已经存在,这在新克隆中通常是真的
因此,让我们编写一些我们希望在新的git克隆上运行的东西,即除了master
之外没有分支的克隆。(尽管如此,请再次参阅脚注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
。我们可以跳过文字标题,这要简单得多。奇特的方法是使用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
如果分支是主分支
,则该分支已存在,并将其签出。如果分支是其他分支,则它不存在,但由于这是一个新的克隆,因此只有一个远程跟踪分支存在,即具有$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”:
将所有这些写入shell脚本文件(/tmp/doit.sh
或/tmp/t.sh
是我最喜欢的脚本名称)。添加一个#/bin/sh-e
行或在顶部设置-e
并使文件可执行-e
确保脚本在任何命令因任何原因失败时退出。(也为调试添加set-x
)在循环之前添加显式的git clone
行,以便它克隆存储库,这样我们就可以确保有一个新的克隆。请记住将目录也更改为克隆
剩下的
if [ -f .gitignore ]; then
... do whatever should be done here ...
else
... create it ...
fi
cat << END >> .gitignore
.classpath
.project
.settings
log/
target/
END
git add .gitignore
git commit -m 'add gitignore'
done
#! /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
$ cd newrepo
$ git push origin 'refs/heads/*:refs/heads/*'
#! /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/*'