从复制的fork存储库重新应用Git提交到原始存储库

1' *_* -- 4 git git-rebase git-patch git-rewrite-history

我的一位大学同事认为通过克隆存储库并将其内容复制到新的初始化存储库但没有.git原始存储库中的文件夹来分叉存储库是个好主意.之后,他只使用一次提交就提交了此副本,整个团队就开始根据此提交开发项目:

A <- B <- C     <- D <- E    (original repository)
\  clone  /        |_____| 
 \       /            |
  \     /     Ofc. work on the original repository was continued after cloning...
   \   /
     M <- N <- O <-P    (our "fork", commits from my team)
Run Code Online (Sandbox Code Playgroud)

现在,我的第一个目标是获得以下存储库结构:

A <- B <- C <- N <- O <- P
Run Code Online (Sandbox Code Playgroud)

我在过去几个小时里一直试图做的事情如下:

    • 克隆原始存储库.
    • git diff > /path/to/patch 从叉子里面.
    • git apply 在原始存储库中.
    • 工作,但不保留提交.
  1. 各种其他不起作用的东西.
    • 克隆原始存储库.
    • 创建并切换到新分支.
    • A使用将其重置为提交git reset --hard COMMIT_HASH_A.
    • 创建一个补丁N <- O <- P使用git format-patch COMMIT_HASH_M --stdout > /path/to/patch的叉子.
    • 使用此修补程序在原始存储库中应用git am -3 /path/to/patch.在解决了几个冲突(例如重复创建空文件)之后,这将导致以下错误: fatal: sha1 information is lacking or useless (some_file_name). Repository lacks necessary blobs to fall back on 3-way merge. 这是我无法继续的地方.

那么如何创建一个存储库,包括原始存储库和我们团队的所有提交,如上所述,最终拉取请求可以发送到原始存储库?可以git-rebase帮忙吗?

cod*_*edd 6

TL; 博士;

在您的原始 repo 克隆中,您应该:

git remote add colleague /path/to/colleague
git fetch colleague
git checkout -b colleague colleague/master
git rebase master
git checkout master
git merge colleague
Run Code Online (Sandbox Code Playgroud)

这将为您提供线性历史记录,并且不会留下冗余且无父级的M提交。

这与David Siro's answer不同,后者将产生一个合并提交,同时M在您合并的分支中留下一个冗余/无父提交。我不喜欢那种悬空提交的场景。

原帖

我复制了你好的和坏的存储库历史,并且能够通过基本上重新设置远程来解决问题。

这些是我遵循的步骤:

  1. 克隆原始存储库
  2. 将遥控器添加到错误的回购中
  3. 获取错误的 repomaster分支
  4. 分支到获取的错误 repo
  5. 将坏的主分支重新设置为您的主分支(将声称已经应用了一些更改)
  6. 将此分支合并到您的主人中
  7. 推回原始存储库
  8. 安排你同事的死亡

通过该设置,我使用的命令和关键输出如下。

#
# Step 1
#
$ git clone <path-to-original-repo>
$ cd original-repo

#
# Step 2
#
$ git remote add messed-up-repo <path-to-messed-up-repo>

#
# Step 3
#
$ git fetch messed-up-repo

#
# Step 4
#
$ git checkout -b bad-master bad-orig/master

#
# Step 5
#
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: commit M
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.
Applying: commit N
Applying: commit O
Applying: commit P

#
# Step 5.1: look at your new history
#
$ git log --oneline --graph --decorate
* cc3121d (HEAD -> bad-master) commit P
* 1144414 commit O
* 7b3851c commit N
* b1dc670 (origin/master, origin/HEAD, master) commit E
* ec9eb4e commit D
* 9c2988f commit C
* 9d35ed6 commit B
* ae9fc2f commit A

#
# Step 6
#
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git merge bad-master 
Updating b1dc670..cc3121d
Fast-forward
 n.txt | 1 +
 o.txt | 1 +
 p.txt | 1 +
 3 files changed, 3 insertions(+)
 create mode 100644 n.txt
 create mode 100644 o.txt
 create mode 100644 p.txt

#
# Step 7
#
$ git push
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (9/9), 714 bytes | 0 bytes/s, done.
Total 9 (delta 3), reused 0 (delta 0)
To /tmp/repotest/good-orig.git
   b1dc670..cc3121d  master -> master

#
# Step 7.1: look at your history again
#
$ git log --oneline --graph --decorate
* cc3121d (HEAD -> master, origin/master, origin/HEAD, bad-master) commit P
* 1144414 commit O
* 7b3851c commit N
* b1dc670 commit E
* ec9eb4e commit D
* 9c2988f commit C
* 9d35ed6 commit B
* ae9fc2f commit A
Run Code Online (Sandbox Code Playgroud)

您现在可以用火销毁同事的混乱存储库,并让其他人继续使用原始的、现在已修复的存储库。

注意:在你的帖子中,你说你想要提交:

A <- B <- C <- N <- O <- P
Run Code Online (Sandbox Code Playgroud)

但我的解决方案包括提交DE中间:A <- B <- C <- D <- E <- N <- O <- P。如果你真的想扔掉这些提交,即假设它不是你的帖子中的错字,那么你可以简单地git rebase -i HEAD~5删除pick这些提交的行,然后git push --force到你的好仓库的来源。

我假设您了解重写历史记录的含义,并且您需要与您的用户进行交流,以免他们受到影响。


为了完整起见,我按如下方式复制了您的设置:

  1. 创建原始的良好回购历史: A <- B <- C
  2. 手动复制原始内容以搞乱 repo
  3. 生成混乱的提交历史记录:M <- N <- O <- P,其中M与原始内容相同A <- B <- C
  4. 将工作添加到原始仓库: ... C <- D <- E


Dav*_*iro 5

如果您不坚持线性历史记录,则可以将fork合并到原始存储库中.

在原来的repo drirectory:

git remote add fork /path/to/fork
git fetch fork
git merge fork/master
Run Code Online (Sandbox Code Playgroud)

如果可以快速转发合并,这将保留提交并可能导致班轮历史记录(无合并提交).

  • 这是简短而简单的,但并不完整。我已经为你添加了缺少的命令并给了你我的 +1,即使我的答案在下面,但我不喜欢由此产生的浮动 `M` 提交。我的回答产生了线性历史。 (2认同)