如何将 Git 仓库中的提交复制到另一个仓库?

196
上周我创建了一个Github存储库,但忘记为存储库选择许可证。现在已经有3个大的提交记录。 我已经询问了3位贡献者,是否可以删除该存储库,然后再次使用相同的名称创建该存储库,并在创建存储库时选择许可证,他们对此表示同意。
问题: 有没有办法将这些提交记录放入新的存储库(这次第一次提交是LICENSE文件),并仍然保留提交元数据?

1
您仍然可以为原始存储库添加许可证。有关详细信息,请参见 https://help.github.com/articles/open-source-licensing/#how-can-i-go-back-through-my-public-repositories-and-give-them-licenses。 - edwinksl
git checerry-pick commit1..commit2 - LF00
7个回答

326

我能否将提交记录导入新的仓库(这次第一个提交是许可证文件),并保留提交的元信息?

可以,通过添加远程并在第一个提交上方挑选相应的提交记录即可。

# add the old repo as a remote repository 
git remote add oldrepo https://github.com/path/to/oldrepo

# get the old repo commits
git remote update

# examine the whole tree
git log --all --oneline --graph --decorate

# copy (cherry-pick) the commits from the old repo into your new local one
git cherry-pick sha-of-commit-one
git cherry-pick sha-of-commit-two
git cherry-pick sha-of-commit-three

# check your local repo is correct
git log

# send your new tree (repo state) to github
git push origin master

# remove the now-unneeded reference to oldrepo
git remote remove oldrepo

如果你仍然想将许可证添加到之前的存储库中,以下是本回答的其余部分。

可以通过变基将许可证提交作为第一个提交。

变基是Git重新排列提交顺序,同时保持所有提交作者和提交日期不变的方式。

在共享存储库上工作时,除非您的整个团队都精通Git,否则通常不鼓励使用。对于那些不熟悉Git的人,他们可以克隆一个新副本。

以下是如何使许可证提交成为第一个提交的步骤:

1. 更新并变基您的本地副本

检出您的项目,并将许可证文件放置在当前的3个提交栈之上的提交中。

#create LICENSE file, edit, add content, save
git add LICENSE
git commit -m 'Initial commit'

然后在主分支上进行交互式变基,以重新排列提交记录。

git rebase -i --root

这将打开一个编辑器。将底部的行(最近的“Initial commit”提交)移动到文件顶部。然后保存并退出编辑器。

一旦你退出编辑器,git会按照你刚刚指定的顺序写入提交记录。

现在,你已经更新了本地仓库的副本。执行以下操作:

git log

2. 强制推送您的新仓库状态到 Github

现在您的副本已经更新,您需要强制将其推送到 Github。

git push -f origin master

这将告诉GitHub将主分支移动到新位置。你应该只在像这样所有使用它的人都知道即将发生的更改的罕见情况下强制推送,否则会让你的合作者感到困惑。

3. 将协作者同步到GitHub

最后,所有协作者都必须同步到此存储库。

首先他们必须拥有干净的存储库,因为以下命令可能会破坏未保存的更改。

# make sure there are no unsaved changes
git status 

# pull the latest version from github
git fetch  

# move their master branch pointer to the one you published to github.
git reset --hard origin/master

就这样。现在每个人都应该同步了。


16

我曾经遇到过相似的问题,在我意识到错误之前,我将多次提交添加到GitHub上的仓库中。

我找到了一个非常简单的解决方法。

首先删除与原始仓库的远程连接

git remote remove origin

其次,添加一个指向在我的GitHub上新分叉的远程连接

git remote add origin <我的仓库URL>

然后,我推送到本地主分支,所有的提交都显示在我的GitHub上。


3
补充一下,当我推送时,我必须执行 git push --set-upstream origin master,但 Git 会提醒你这一点。 - MRichards

11
我采用以下方法:
  • 将源存储库克隆到类似于 /c/SrcRepo 的文件夹中

  • 将目标存储库克隆到类似于 /c/DstRepo 的文件夹中,并切换到目标分支

  • 在目标存储库的根文件夹中运行以下命令:

    git pull /c/SrcRepo srcBranch --allow-unrelated-histories

无需创建额外的远程引用。


3
我不小心在原始仓库上提交了我的更改,而不是在本地提交分叉仓库,你的方法帮助我从原始仓库复制到分叉仓库。 - Moshi
1
传说!它奏效了!这家伙真该得到... - equivalent8
完美!最简单直接的解决方案! - oikonomopo
我的新存储库是一个单一的存储库(目标存储库),我可以将源代码复制到特定路径中吗? - punith bp
@punithbp,你需要重新编写日志历史。 这是一个关于命令的原始页面:https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-filter-branch.html 阅读后文:将整个树移动到子目录中,或从子目录中删除它。另一个链接:https://dev59.com/xE7Sa4cB1Zd3GeqP33yx - MirrorBoy

7

在 @Moocowmoo 的回答基础上,本文尝试进一步简化代码。

这种方法的不同之处在于尽可能避免冲突,只是假定远程正确。

但是它无法很好地处理已删除的文件,因此仍需要手动操作。

# assuming you are already on the branch you want to be
git remote add oldrepo https://github.com/path/to/oldrepo
git fetch oldrepo

# take all or subset of changes from a branch
git cherry-pick --strategy recursive --strategy-option theirs oldestCommitHash^..latestCommitHash

# or take all changes included in a specific merge commit (easiest)
git cherry-pick --strategy recursive --strategy-option theirs mergeCommitHash^..mergeCommitHash

# handling deleted files/unhandled conflicts
# just keep repeating this section
git mergetool
# either c/m or d based on if you want to keep or delete the files
git cherry-pick --continue

6

你可以尝试这个方法,它简单明了。这将把包括你使用作为<last-commit-hash-from-old-repo>哈希值在内的所有提交推送到另一个存储库:

git clone https://github.com/path/to/new-repo.git new-repo
cd new-repo
git remote add old https://github.com/path/to/old-repo.git
git remote update
git merge --allow-unrelated-histories <last-commit-hash-from-old-repo>
git push origin main

如果有人需要将一个仓库的所有提交作为单个提交推送到另一个仓库(就像我需要的那样),您可以在合并命令中添加--squash,如下所示:

git clone https://github.com/path/to/new-repo.git new-repo
cd new-repo
git remote add old https://github.com/path/to/old-repo.git
git remote update
git merge --squash --allow-unrelated-histories <last-commit-hash-from-old-repo>
git push origin main

5
  • Destination Git = UrlD (existing content doesn't matter)
  • SourceGit = UrlS

    git clone UrlS
    
    git remote add origin2 UrlD
    
    git push -f origin2 master
    
现在目标地将具有与源相同的数据(您也可以使用origin而不是origin2)。

请记住,这将重写目标分支上的历史记录。这不仅仅是将您当前的代码作为旧代码的新提交放在其之上。在我的情况下,这很好,但请确保这就是您想要的。 - Andy Weinstein

4
在我的情况下,我需要查找旧仓库和新仓库之间的差异。因此,在新仓库中添加了旧仓库。
git remote add old https://gitlab.site.az/old-blog.git

获取所有远程分支
git fetch --all

查找不同的提交

git log --graph --oneline --pretty=format:"%h%x09%an%x09%ad%x09%s" --abbrev-commit --date=relative develop..old/develop

获取您选择的提交记录

git cherry-pick SHA1 SHA2 SHA4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接