使用rebase重写历史记录后如何重新应用Git标签?

问题描述 投票:0回答:2

我有一个项目,我开始在我的旧笔记本电脑上工作,然后继续在我的新笔记本电脑上工作。在我的旧笔记本电脑上,我已经使用

user.name
user.email
正确配置了 Git,但是当我切换到新笔记本电脑时,我只是克隆了存储库并继续工作,而无需配置 user.name
user.email
。因此,我从新笔记本电脑所做的提交归因于我的本地计算机用户的 
user.name
[computer_name]@local
user.email
。我想修改我的新笔记本电脑所做的所有提交,并在
here找到了执行此操作的方法。

git rebase -r <last commit from my old laptop> \ --exec 'git commit --amend --no-edit --reset-author'
注意,我是唯一一个在这个仓库上工作的人,所以重写历史并不是一个大问题。
然而,

确实出错的一件事是,我在 Git 存储库中创建的所有标签和版本都处于孤立状态。 GitHub 在每个标签旁边显示一条消息,内容如下:

~“此标签指向任何存储库分支之外的提交,或指向不同的存储库”~。

这是因为修改提交的作者会更改其标识哈希。因此,标签指向

rebase 命令之前旧提交的哈希值。

因此,需要将每个标签重新应用到与其指向的旧提交相对应的新提交。

我该怎么做?

git git-rebase git-tag git-rewrite-history
2个回答
0
投票
rev-list

awk
log
tag
来做到这一点。
git rev-list --all --tags | \
while read commit; do \
    new_commit=$(git log --format="%H" -n 1 $commit); \
    git tag -f $(git tag --contains $commit) $new_commit; \
done

以下是其功能的详细说明:

    git rev-list --all --tags
  1. :列出可从存储库中的任何引用(分支、标签)访问的所有提交。
  2. while read commit; do ... done
  3. :从
    git rev-list
    的输出中读取每个提交 ID,并为每个提交执行以下命令。
  4. new_commit=$(git log --format="%H" -n 1 $commit)
  5. :使用
    %H
    格式选项检索与旧提交ID对应的新提交ID,它代表完整的提交哈希。
  6. git tag -f $(git tag --contains $commit) $new_commit
  7. :使用
    $commit
    命令和
    $new_commit
    (强制)选项,将包含旧提交 ID (
    git tag
    ) 的标签重新应用到相应的新提交 ID (
    -f
    )。这会覆盖具有相同名称的新提交上的任何现有标签。
    
    
  8. 这样,每个旧标签将被重新定位以指向相应的新提交 ID。

P.S.:完全公开,我使用人工智能助手来解决这个问题。


0
投票

#!/usr/bin/env bash # fix git tags after rewriting the git history # with "git-filter-repo" or "git rebase" # what branches are allowed for tags? # usually, tags are not allowed on backup branches #branches="master branch2 branch3" branches="master" branches_regex="$(printf '|%s' $branches)" branches_regex="(${branches_regex:1})" echo "branches regex: $branches_regex" while read tag_commit tag_ref; do tag_name=${tag_ref#*/*/} echo echo "checking tag $tag_name (commit $tag_commit) (date $tag_author_date)" tag_author_date=$(git log -1 --format='format:%ad' $tag_ref) tag_commit_branches="$(git branch --contains $tag_commit --format='%(refname)')" if ! echo "$tag_commit_branches" | grep -q -x -E "refs/heads/$branches_regex"; then echo "tag $tag_name is not part of branches $branches_regex" found=false for branch in $branches; do commit_candidates="$(git log $branch --format=format:"%ad %H" | grep "^$tag_author_date ")" if [[ -z "$commit_candidates" ]]; then #echo "error: found no commit candidates for tag $tag_name" : elif [[ $(echo "$commit_candidates" | wc -l) == 1 ]]; then commit_hash=${commit_candidates##* } echo "ok: found one commit candidate ($commit_hash) in branch $branch with author date $tag_author_date" echo git tag -f $tag_name $commit_hash git tag -f $tag_name $commit_hash found=true break else echo "error: found multiple commit candidates for tag $tag_name" echo "please fix this tag manually with one of these commands:" while read commit_candidate; do commit_hash=${commit_candidate##* } echo " git tag -f $tag_name $commit_hash" done <<<"$commit_candidates" fi done if ! $found; then echo "error: found no commit candidates for tag $tag_name in branches $branches_regex" fi else tag_branches="$(echo "$tag_commit_branches" | grep -x -E "refs/heads/$branches_regex" | sed 's|^refs/heads/||')" echo "ok: tag $tag_name is part of branches" $tag_branches fi done < <( git tag -l --format='%(objectname) %(refname)' )

© www.soinside.com 2019 - 2024. All rights reserved.