我的存储库中有超过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
不知道,但它没有按预期执行。
请帮忙。
答案 0 :(得分:2)
首先,git branch
是用户友好的,不是编程友好的。不要将它用于编程:使用编程友好的"管道"命令,git for-each-ref
。
其次,作为Leon said in a comment,编写脚本 - 一个一次性的脚本是一个好主意,如果需要,可以更轻松地编写和使用新的(新鲜,干净)克隆,直到你做对了 - 一个循环在循环中完成所有必要的工作。
最后,根本不要执行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
上执行此操作。这意味着你可能只是因为它已经存在而在第一个循环中跳过它,这在新的克隆中通常是真正的 1 。
所以,让我们写一些我们期望在新的git clone
上运行的东西,即没有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
等符号引用的内容。我们可以跳过文字HEAD,这简单得多。奇特的方式是使用git symbolic-ref
来测试它,但没有意义,我们将看到的唯一实际的(由于历史原因)是HEAD,所以让我们这样做:< / p>
[ "$name" = origin/HEAD ] && continue
现在我们需要做的是创建并签出一个 local 分支,该分支将相应的远程跟踪分支设置为其上游。我们可以使用内置的git checkout
在一个简单的步骤中完成此操作。
这也让我们避免使用特殊套管master
:git clone
已经运行git checkout master
,创建master
并将其设置为origin/master
作为其上游,但我们还是需要使用git checkout master
。这将检查master
创建的现有 git clone
(git clone
运行时git checkout master
)。因此,我们的下一步是构建正确的分支名称:
branch=${name#origin/}
git checkout $branch
我们只想剥离origin/
,而不是&#34;一切都是最后一个斜杠&#34;,以防其中一个远程跟踪分支命名为origin/feature/life
而另一个名为{{例如{1}}。我们需要本地origin/feature/zorg
,我们可以从中feature/life
更新。
如果分支是origin/feature/life
,它已经存在,并将其检出。如果分支是其他任何东西,它不存在,但由于这是一个新的克隆,只有一个远程跟踪分支 存在 - 具有master
的那个 - 所以我们&#39; ll创建本地分支并将其检出,并将远程跟踪分支设置为其上游。
现在我们要创建一个$name
,在其中放入一堆东西,添加它并提交它。一个重要的问题是我们刚签出的提交中是否已经存在.gitignore
,如果存在,我们想要做些什么。我无法为你解答这个问题。另一个是我们刚要签出的提交中是否存在我们要添加到这个.gitignore
的任何文件,如果是,那么该怎么做。再一次,我无法回答这个问题。不过,我会注意到.gitignore
后跟touch .gitignore
只会在git status
新创建.gitignore
时打印。直接测试可能更明智:
touch
如果&#34;应该做什么&#34;我没有什么特别的东西,我们可以简单地使用 if [ -f .gitignore ]; then
... do whatever should be done here ...
else
... create it ...
fi
添加它,如果它不存在则会创建它,或者如果它存在则添加它。
我们可以使用一个>>
和一个&#34; here-document&#34;而不是五个单独的echo ... >> .gitignore
:
cat >> .gitignore
现在我们像往常一样 cat << END >> .gitignore
.classpath
.project
.settings
log/
target/
END
和git add
,这就是我们循环的结束:
git commit
将所有这些写入shell脚本文件( git add .gitignore
git commit -m 'add gitignore'
done
或/tmp/doit.sh
是我最喜欢的脚本名称)。在顶部添加/tmp/t.sh
行或#! /bin/sh -e
并使文件可执行 - set -e
确保如果任何命令因任何原因失败,脚本将退出。 (也可以添加-e
进行调试。)在循环之前添加一个显式set -x
行,以便克隆存储库,这样我们就可以确保有一个新的克隆。请记住将目录更改为克隆。
本例的其余部分将新的repo放入名为&#34; newrepo&#34;的目录中。使用git clone
制作临时目录可能更好。
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
最后一步是使用 refspec 进行推送,并且refsepec在这里说&#34;对于我的每个分支,使用同名 on origin&#34;。由于我们确保我们的分支具有相同的名称,例如$ cd newrepo
$ git push origin 'refs/heads/*:refs/heads/*'
- 与feature/life
上的名称相同,这正是我们想要的。
(注意:以上都是未经测试的。请注意拼写错误等。)
答案 1 :(得分:0)
我已根据@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/*'