繁体   English   中英

Git:更改提交者信息

[英]Git: changing committers info

我正在使用此脚本来修改提交:

rm -rf repo

echo "clonning $1"
git clone $1 repo

cd repo
git checkout dev

echo "setting remote origin to $2"
git remote set-url origin $2

array=( 'email1@gmail.com' 'email2@gmail.com' )
for OLD_EMAIL in "${array[@]}"
do
  echo $OLD_EMAIL
  git filter-branch -f --env-filter '
  CORRECT_NAME="New name"
  CORRECT_EMAIL="new@email.com"
  if [ "$GIT_COMMITTER_EMAIL" = '$OLD_EMAIL' ]
  then
      export GIT_COMMITTER_NAME="$CORRECT_NAME"
      export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
  fi
  if [ "$GIT_AUTHOR_EMAIL" = '$OLD_EMAIL' ]
  then
      export GIT_AUTHOR_NAME="$CORRECT_NAME"
      export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
  fi
  ' --tag-name-filter cat -- --tags
done
echo "Authors list:"
git log --format='%cE' | sort -u
echo -n "Push to destination (y/n)? "
read answer
if echo "$answer" | grep -iq "^y" ;then
    git push
else
    echo Aborted
fi

cd ../

它从第一个仓库中提取数据,修改提交者信息并推送到第二个仓库。

如果有人直接提交第二个回购,问题就出现了。 如何将这些更改应用于第一个回购?

如果我正确理解你的问题(阅读评论后),你的回购目前看起来像这样:

初始状态

第一个repo(ad)中的提交已被修改以创建备用提交(a'-d'),这些提交被推入第二个仓库,然后添加了其他提交(例如)。

重新编辑您的历史记录

因为你在两个repos中的身份信息之间没有1:1的关系,试图修改带有filter-branch的'-d'以恢复原始历史,虽然理论上可行,但是需要一个积极的方法识别“原始提交”,而没有确定提交(其哈希)所需的一条信息。

提交基本上由几条信息组成:

  1. 树的哈希
  2. 提交的父级的哈希值
  3. 作者的身份信息
  4. 创作的时间戳
  5. 提交者的身份信息
  6. 提交的时间戳
  7. 提交消息
  8. 所有信息的大小

所有这些都经过哈希处理,以便为您的提交创建唯一标识符。 改变了2,3,5和8之后,我们留下了树,它不一定是唯一的,时间戳(不一定是唯一的)和提交消息,它不一定是唯一的。

可能只是比较树和其中一个时间戳,你可以获得一个不错的匹配,所以让我们为该场景编写一些伪代码。

# create a variable to hold the information from teh current commit
pseudoidentifier=$TREE + $AUTHOR_TIMESTAMP

# go to the first repo
cd /path/to/firstrepo

# output the log | grep to search | sed to remove everything after delimeter
oldhash=`git log --format="{hash}~{tree}{authortimestamp}" | grep pseudoidenfier | sed "s/~.+$//"`

# get the new identity using a custom formatted show command
newidentity=`git show -q --format="{formatted identity}" $oldhash`

# parse out the name and email, probably with sed
CORRECT_NAME=`sed 's/pattern//' $newidentity`
CORRECT_EMAIL=`sed 's/pattern//' $newidentity`

# go to the second repo
cd /path/to/secondrepo

export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"

不幸的是,编写速度慢,测试困难且耗时。 可能需要多次重新运行整个事物。 因为你的最终目标是重新统一代码。 还有其他一些选项可能会减少头痛并且速度更快。 特别是如果你确实需要保持第二个回复,身份更新完好无损。

替代方法

如果没有共同的历史记录,您仍然可以使用更多手动方式将两者同步。 在这种情况下,我建议使用以下三种方法。

一点前期工作

在开始之前,我们可以检查d和d'处的代码是否确实相同。 我们可以使用git show命令来做到这一点:

$ git show -q --format="%T" d
a017285da45ec06fc744815f33a2e22627f4a799
$ git show -q --format="%T" d'
a017285da45ec06fc744815f33a2e22627f4a799

此命令将输出提交指向的树对象,如果两个树匹配,则表示您正在处理相同的代码。 完全可能在没有匹配的代码库的情况下执行以下过程,但在这种情况下您可能必须解决冲突。 这一步真的只是告诉你两者将如何轻松地融合在一起。

Cherry-Pick方法

如果您最初修改提交的repo完好无损,则可以从两者中获取分支到单个repo中,并尝试使用cherry-pick复制提交。

git checkout <branch at d>
git cherry-pick d'...g

(注意语法是3个点)这将在d'之后(但不包括)d'应用每个提交的更改,直到并包括g到d。 创建新提交e'-g'。

樱桃采摘后的历史

补丁方法

如果您没有简单的方法将更改从两个分支转换为单个存储库,则可以为第二个存储库上的提交创建一系列修补程序并将其应用于第一个存储库。

在第二个回购

git checkout <branch of g>
git format-patch --output-directory <dir> d'...g

(再次,语法是3个点)这将在d'之后(并且不包括)d'之前和之后为每个提交输出一系列补丁文件。 然后将这些文件复制到第一个存储库中可以获取这些文件的位置。

在第一个回购

git checkout <branch of d>
git am /path/to/patches/*

你最终会在樱桃采摘方法的同一个地方。

补丁后的历史

创建一个移植

如果存在大量冲突并且您不需要保留身份更改信息,则还可以使用git replace来执行移植。

git replace --graft e d

这将创建一个commit e的副本,其中d作为父项,并添加一个引用,表示在尝试访问e时使用e'commit。 有效地使d成为两者的共同祖先并允许您执行传统合并(h)。

在此输入图像描述

那又怎样?

保持两个没有共同历史记录同步的回购将一直导致你这样的问题,并且随着两者的缓慢分歧(例如,当你解决冲突时)它们会变得更糟。 随着时间的推移,这两种方法都需要越来越多的资源来维护两个回购。

我建议,一旦两个repos同步,选择其中一个并从那时起专门使用那个。 如果您需要两个遥控器,只需将该回购推送给它们。 然后,您可以轻松地使用许多经过验证的真实工作流程中的任何一个来维护两个回购。

如果这不是一个选项,我建议一丝不苟地检查两个回购头的树木,以验证它们是否经常相同。

你有两个选择来完成这个任务:

  1. 如果你信任用户,你可以让他们更改他们的电子邮件(只有这个git repo或所有repos,为所有repos添加--global
 git config user.email email@server.com 
  1. 如果你想通过预提交git钩子强制执行它,那么你将添加到第二个存储库并让它们全部拉出新的更新。 有关这方面的更多信息,请点击 此处此处

暂无
暂无

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

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