繁体   English   中英

如何使用 bash 将多个 git 分支重命名为小写

[英]how to rename multiple git branches into lowercase using bash

我想用小写重命名多个分支,因为在迁移之前我们必须将所有大写分支转换为小写。 git 分支:

CPORT_121

GC_211

Lower-Upper_DEMO

现在我尝试了下面的一个,但它不起作用。

git branch | tr A-Z a-z | xargs -n 2 git branch -m

error: refname refs/heads/cport_121 not found
fatal: Branch rename failed
fatal: '*' is not a valid branch name.

这是对循环进行编码的错误方法。 (评论中的结帐循环也不是真正的正确方法。)出于脚本目的,我们应该尽可能使用git for-each-ref ,而这里完全有可能。 如果我们想为每个需要重命名的refs/remotes/origin/*远程跟踪名称创建本地分支名称,我们将从这个开始:

git for-each-ref \
  --format="%(if)%(symref)%(then)%(else)%(refname:strip=3)%(end)" \
  refs/remotes/origin | sed '/^$/d' > /tmp/branchlist

这将创建一个包含所有远程跟踪名称的文件 ( /tmp/branchlist )。 if/then/else/end序列删除了HEAD符号 ref 并且sed清除了相应的空行(不是绝对必要的,但很有用)。

其中一些分支名称可能已经很好了! 我们可能不想对这些大惊小怪。 所以现在我们可以grep大写:

LC_ALL=C grep -E '^[A-Z]+$' /tmp/branchlist > /tmp/upper

如果您的 grep 使用 POSIX 排序规则(我的至少在某些系统上使用),则此处的LC_ALL是必需的。

现在检查/tmp/upper以确保其中没有任何名称在/tmp/branchlist中也显示为小写字母可能是明智的。 这是一次性手动操作,但如果您愿意,可以将其自动化:

tr A-Z a-z < /tmp/upper | grep -F -f - /tmp/branchlist

请注意,这将错误地匹配子字符串,例如,如果有一个“坏”名称OOPS和一个“好”名称whoops ,即使它不同,也会找到“好”名称; 修复它更难,我不会打扰。

我们现在要在本地存储库中创建一个名称与大写名称匹配的小写名称分支:

awk '{ print "git branch --no-track " tolower($0) " refs/remotes/origin/" $0 }' \
  < /tmp/upper

确保这会生成所需的命令,然后通过管道输入sh

awk '{ print "git branch --no-track " tolower($0) " refs/remotes/origin/" $0 }' \
  < /tmp/upper | sh

我们已经生成了所需的分支名称。

但是,与其创建这样的分支名称,对我来说,运行直接远程创建名称的git push命令更有意义。

为此,我们希望:

git push origin

接下来是一系列本地远程跟踪名称和所需的分支名称:对于每个大写名称,我们想要该名称的小写版本作为分支名称。 所以那将是:

(printf "git push origin"
awk '{ printf(" %s:%s", "refs/remotes/origin/" $0, "refs/heads/" tolower($0)) }' \
  < /tmp/upper
echo "")

验证这是否产生了所需的git push命令,然后通过管道传输到 sh。

您可能希望稍后git push --delete仅大写的名称; 现在应该很明显如何做到这一点。 之后,此存储库的其他用户可能想要运行git fetch --prune来更新他们的远程跟踪名称。

我会尝试,但我真的很害怕这样的行为:|。 因此,请小心并确保您不会丢失数据。

# Create three random branches for the test
git branch www_FUNK0 origin/master
git branch WWW_funk1 origin/master
git branch WWW_FuNk2 origin/master

git branch | grep -i www_funk
# This is the output of this command:
#  www_FUNK0
#  WWW_funk1
#  WWW_FuNk2

# Iterating through all WWW_FUNK* branches one by one
for b in $(git branch | grep -i www_funk | tr -d ' ')
do 
    # Storing the $b branch into the tmp branch and then
    # delete $b branch
    # and rename tmp branch to the lowercase version of $b
    git checkout -B tmp $b
    git branch -D $b
    git branch -m ${b,,}
done

git checkout master
git branch -D tmp

git branch | grep -i www_funk
# Finally we have this result:
#  www_funk0
#  www_funk1
#  www_funk2

请不要在包含有用数据的回购中尝试这些练习!!!

git branch --format='%(refname:short)' \
| sed -n '/[A-Z]/s/.*/git branch -m & \L&/p'

做分支; 如果您想要其他裁判,您将不得不对此更加挑剔,例如在本地更改远程跟踪名称对任何人都没有任何好处,您需要推送更新:

git for-each-ref --format='%(if)%(symref)%(then)%(else)%(refname:short)%(end)'  \
        refs/remotes \
|  sed -nr 's,([^/]*)/(.*),git push \1 refs/remotes/&:refs/heads/\L\2,p'

然后git fetch --prune

使用bash ,这里有两种正确解析分支名称的方法。

简单的方法:逐行读取分支列表,依靠分支名称不能包含新行的事实:

git branch --format '%(refname:lstrip=-1)' |
while IFS= read -r name; do
    git branch -m "$name" "${name,,}"
done

“正确”方式:使用git for-each-ref--shell选项安全地引用每个名称,以便可以eval编辑。 可以将带引号的名称添加到数组中,以循环:

eval "names=($(
    git for-each-ref refs/heads \
    --format '%(refname:lstrip=-1)' \
    --shell
))"

for name in "${names[@]}"; do
    git branch -m "$name" "${name,,}"
done
  • 格式字符串从分支名称( refs/heads )中去除父目录。
  • 对于git branch ,它也只打印名称,没有前导空格和星号。
  • ${name,,}是 bash 语法,用于小写变量中的所有字符。
  • 我更喜欢第一个命令,因为它更简单且不易出错。
  • 请注意,如果您手动重命名文件refs/heads/branch-name以包含新行,git 拒绝列出该分支并打印损坏的名称错误(对于git branchgit for-each-ref )。 那很好。
  • 这两个命令都需要 bash,并且在/bin/sh中不起作用。

暂无
暂无

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

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