如何合并两个github帐户

时间:2016-06-08 04:27:00

标签: git github

我有两个GitHub帐户,其中一个是很久以前在我的工作中创建的,并且有一个用户名,指的是我工作的公司。 我有另一个帐户,这是我个人的GitHub帐户,我不能停止使用。我可以合并这两个帐户,这样我只能在其中一个帐户中工作吗?

4 个答案:

答案 0 :(得分:16)

在github上无法合并2个帐户,您可以将所有权转移到您的个人帐户。

package com.github.ttwd80.ming;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class PreShareUrl {

    private String bucketName;
    private String keyName;
    private String region;
    private int secondsToExpire;
    private String accessKey;
    private String secretKey;
    private String amzDate;

    public String getBucketName() {
        return bucketName;
    }

    public void setBucketName(String bucketName) {
        this.bucketName = bucketName;
    }

    public String getKeyName() {
        return keyName;
    }

    public void setKeyName(String keyName) {
        this.keyName = keyName;
    }

    public String getRegion() {
        return region;
    }

    public void setRegion(String region) {
        this.region = region;
    }

    public int getSecondsToExpire() {
        return secondsToExpire;
    }

    public void setSecondsToExpire(int secondsToExpire) {
        this.secondsToExpire = secondsToExpire;
    }

    public String getAccessKey() {
        return accessKey;
    }

    public void setAccessKey(String accessKey) {
        this.accessKey = accessKey;
    }

    public String getSecretKey() {
        return secretKey;
    }

    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }

    public String getAmzDate() {
        return amzDate;
    }

    public void setAmzDate(String amzDate) {
        this.amzDate = amzDate;
    }

    public String generate() throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
        StringBuilder sb = new StringBuilder();
        sb.append("https://");
        sb.append(createHost());
        sb.append("/");
        sb.append(keyName);
        sb.append("?");
        sb.append("X-Amz-Algorithm=AWS4-HMAC-SHA256");
        sb.append("&");
        sb.append("X-Amz-Date=");
        sb.append(amzDate);
        sb.append("&");
        sb.append("X-Amz-SignedHeaders=host");
        sb.append("&");
        sb.append("X-Amz-Expires=");
        sb.append(secondsToExpire);
        sb.append("&");
        sb.append("X-Amz-Credential=");
        sb.append(URLEncoder.encode(createCredential(), "UTF-8"));
        sb.append("&");
        sb.append("X-Amz-Signature=");
        sb.append(calculate());
        return sb.toString();
    }

    private String createHost() {
        StringBuilder sb = new StringBuilder();
        sb.append(bucketName);
        sb.append(".s3-");
        sb.append(region);
        sb.append(".amazonaws.com");
        return sb.toString();
    }

    private String createCredential() {
        StringBuilder sb = new StringBuilder();
        sb.append(accessKey);
        sb.append("/");
        sb.append(createCredentialScope());
        return sb.toString();
    }

    private String calculate() throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
        String canonicalRequest = createCanonicalRequest();
        System.out.println("canonicalRequest");
        System.out.println(canonicalRequest);

        String stringToSign = createStringToSign(canonicalRequest);
        System.out.println(stringToSign);

        byte[] signingKey = newSigningKey(secretKey, amzDate.substring(0, 8), region, "s3");
        System.out.println(bytesToHex(signingKey));
        byte[] signature = sign(stringToSign.getBytes(Charset.forName("UTF-8")), signingKey, "HmacSHA256");

        return bytesToHex(signature);
    }

    private String createStringToSign(String canonicalRequest) throws NoSuchAlgorithmException {
        StringBuilder sb = new StringBuilder();
        sb.append("AWS4-HMAC-SHA256");
        sb.append("\n");
        sb.append(amzDate);
        sb.append("\n");
        sb.append(createCredentialScope());
        sb.append("\n");
        String hashedCanonicalRequest = bytesToHex(doHash(canonicalRequest));
        sb.append(hashedCanonicalRequest);
        return sb.toString();
    }

    private String createCredentialScope() {
        StringBuilder sb = new StringBuilder();
        sb.append(amzDate.substring(0, 8));
        sb.append("/");
        sb.append(region);
        sb.append("/");
        sb.append("s3");
        sb.append("/");
        sb.append("aws4_request");
        return sb.toString();
    }

    private String createCanonicalRequest() throws UnsupportedEncodingException {
        String contentSha256 = "UNSIGNED-PAYLOAD";
        StringBuilder sb = new StringBuilder();
        sb.append("GET");
        sb.append("\n");
        sb.append("/");
        sb.append(keyName);
        sb.append("\n");
        sb.append("X-Amz-Algorithm=AWS4-HMAC-SHA256");
        sb.append("&");
        sb.append("X-Amz-Credential=");
        sb.append(URLEncoder.encode(createCredential(), "UTF-8"));
        sb.append("&");
        sb.append("X-Amz-Date=");
        sb.append(amzDate);
        sb.append("&");
        sb.append("X-Amz-Expires=");
        sb.append(secondsToExpire);
        sb.append("&");
        sb.append("X-Amz-SignedHeaders=host");
        sb.append("\n");
        sb.append("host:");
        sb.append(createHost());
        sb.append("\n");
        sb.append("\n");
        sb.append("host");
        sb.append("\n");
        sb.append(contentSha256);
        return sb.toString();
    }

    private byte[] doHash(String text) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(text.getBytes(Charset.forName("UTF-8")));
        return md.digest();
    }

    public static String bytesToHex(byte[] bytes) {
        final char[] hexArray = "0123456789abcdef".toCharArray();
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    private byte[] newSigningKey(String secretKey, String dateStamp, String regionName, String serviceName)
            throws InvalidKeyException, NoSuchAlgorithmException {
        byte[] kSecret = ("AWS4" + secretKey).getBytes(Charset.forName("UTF-8"));
        byte[] kDate = sign(dateStamp.getBytes(), kSecret, "HmacSHA256");
        byte[] kRegion = sign(regionName.getBytes(), kDate, "HmacSHA256");
        byte[] kService = sign(serviceName.getBytes(), kRegion, "HmacSHA256");
        return sign("aws4_request".getBytes(), kService, "HmacSHA256");
    }

    protected byte[] sign(byte[] data, byte[] key, String algorithm)
            throws NoSuchAlgorithmException, InvalidKeyException {
        Mac mac = Mac.getInstance(algorithm.toString());
        mac.init(new SecretKeySpec(key, algorithm.toString()));
        return mac.doFinal(data);
    }

}

有关详情:https://help.github.com/articles/merging-multiple-user-accounts/

答案 1 :(得分:7)

虽然Github概述了有限的&#34; Merging multiple user accounts&#34;过程,也在前面的答案中提到过,它不是一个完整的解决方案。它不解决第三方存储库贡献的所有权。

GitHub将显示已删除用户的评论(这将是您根据GitHub的帐户合并建议删除的帐户)&#34; ghost&#34;用户的评论 - 不会将其归因于幸存的帐户。请在此处查看更多详细信息:

https://help.github.com/articles/deleting-your-user-account/

所以实际上截至2016年11月,没有一般方法可以将所有贡献从一个帐户完全合并到另一个帐户。

答案 2 :(得分:3)

在此处回复最新答案(与2019年相关)。

幸运的是,这是一个相对快速的过程,用于 1)转移回购所有权 2)管理(添加/删除/更改)帐户电子邮件地址 3 ),将最多个提交历史记录保留/传输到配置文件的贡献图中

转移存储库所有权只需几步。

  • 从“回购”>“设置”页面>“选项”>滚动到底部,在“危险区域”中寻找红色的“传输”按钮
  • 填写必填字段,输入存储库名称以确认并输入新所有者的GH用户名
  • 新所有者收到一封带有身份验证令牌的电子邮件,该电子邮件将在24小时后过期。请务必检查您要转移到的帐户的电子邮件,并点击链接以完全完成所有回购转移

帐户之间的回购转移包括所有问题,拉取请求,分叉,星号,以及为git和http设置的自动重定向。传输完成后,尽管您应该更新遥控器的原始URL:git remote set-url origin new_url

Git提交历史记录,SAML和其他项目与您在GitHub以及您的远程本地设置中拥有的电子邮件相关联。当您在要合并/合并到的用户帐户上添加原始文档,编写电子邮件/对其进行验证/确认时,会将提交历史记录保存/传输到贡献图。

  • 从GH控制台>单击您的个人资料照片下拉菜单>设置页面
  • 单击左侧栏中的电子邮件>添加电子邮件地址字段>添加新电子邮件
  • 在收件箱中查看您刚刚添加的电子邮件地址,然后单击包含的链接。您应该登陆GitHub仪表板,看到一封电子邮件验证确认横幅

关于历史记录转移的先前注释是指PR和属于此“灰色区域”历史记录的问题,并且在合并帐户时不会转移。

在将电子邮件添加到GH用户帐户并对其进行验证后,大多数提交历史记录都会转移。给GitHub一点时间在帐户之间传播历史和贡献。

您将丢失与原始请求请求相关的提交,以及与您要删除的帐户相关的发行历史。帐户删除后,这些“ ...将被归属我们的” Ghost”用户,尽管问题/ PR本身不受影响。”(来自GH支持)如果您想了解更多信息,我为此撰写了一篇简短的博客文章,其中包含有关转移回购所有权,添加电子邮件以及更多内容的步骤和视觉效果-how to merge/combine two (or many) GitHub user accounts

GitHub确实建议将一个用户帐户用于个人和专业(工作)存储库(source),绝对可以考虑这样做!

尽管有多种方法可以简化多个帐户的工作流程,但是管理多个用户帐户可能很麻烦,因此,在这种情况下,这种响应不适合您,并且您希望保持多个帐户不变,请参见{{ 3}}。

答案 3 :(得分:0)

GitHub有一个方便的命令行工具:hub位于https://hub.github.com

我已经写了一个示例,将您所有组织中的所有存储库移至my_new_organisation_name

#!/usr/bin/env bash

orgs="$(hub api '/user/orgs' | jq -r '.[] | .login')";
repos="$(for org in $orgs; do hub api '/orgs/'"$org"'/repos' | jq -r '.[] | .name';
         done)"

for org in $orgs; do
    for repo in $repos; do
        ( hub api '/repos/'"$org"'/'"$repo"'/transfer'
                  -F 'new_owner'='my_new_organisation_name' | jq . ) &
    done
done

对于用户而不是组织,请将my_new_organisation_name设置为替换用户名,删除外部循环,然后将repos=行替换为:

repos="$(hub api /users/SamuelMarks/repos | jq -r '.[] | .name')"

编辑:如果您喜欢GUI,则找到了https://stackoverflow.com/a/54549899