uniquejava / blog

My notes regarding the vibrating frontend :boom and the plain old java :rofl.
Creative Commons Zero v1.0 Universal
11 stars 5 forks source link

Git - How do you merge two Git repositories? #221

Open uniquejava opened 6 years ago

uniquejava commented 6 years ago

合并: 将若干个不相干的项目合并到一个项目

将git升级到最新版 macOS下: brew upgrade git --verbose

当前的我的git版本: 2.18.0

合并过程

TLDR:

  1. cd /tmp/project1
  2. PREFIX=project1 && git filter-branch
  3. cd /path/to/project2
  4. git remote add project1 /tmp/project1
  5. git pull project1 master --rebase --allow-unrelated-histories (参数--allow-unrelated-histories在git 2.9以后的版本不需要添加)

假定项目名为project1, 需要把这个project1项目整体放到另一个叫project2的项目中,

要同时保留project1提交历史,

先把project1拷贝到任意目录, 比如 /tmp目录下. 然后执行如下命令

cd /tmp/project1  # 进到project1目录中(要迁移的项目)
PREFIX=project1 #看情况修改这个PREFIX的值 (表示一会merge时要移到名为project2/project1的子目录中)
PREFIX=Tools/project1 #或者又比如这里改成两层目录, 表示一会merge时要移到project2/Tools/project1这个子目录中

# mac下执行如下超长命令(会用到上面的PREFIX变量值)
git filter-branch --index-filter '
    git ls-files -s |
    sed "s, ,&'"$PREFIX"'/," |
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info &&
    mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE
' HEAD

git filter-branch这个命令超级长. 用来批量变更文件路径. 让project1仓库中的所有文件的路径前多上一层PREFIX

GIT_INDEX_FILE 是GIT的内置环境变量, 不需要赋值. 详见: https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables

最后是进到project2项目根目录, 执行merge操作.

cd /path/to/project2 # 进到project2项目根目录
git remote add project1 /tmp/project1 # 添加remote
git pull project1 master --rebase # 合并仓库
#如果报错 fatal: refusing to merge unrelated histories
git pull project1 master --rebase --allow-unrelated-histories

背后的思想

The submodule approach is good if you want to maintain the project separately. However, if you really want to merge both projects into the same repository, then you have a bit more work to do.

The first thing would be to use git filter-branch to rewrite the names of everything in the second repository to be in the subdirectory where you would like them to end up. So instead of foo.c, bar.html, you would have projb/foo.c and projb/bar.html.

Then, you should be able to do something like the following:

git remote add projb [wherever]
git pull projb

The git pull will do a git fetch followed by a git merge. There should be no conflicts, if the repository you're pulling to does not yet have a projb/ directory.

By Greg Hewgill

Linux版

Linux和mac的sed命令略有不同. 对于tab键. Linux是用的字面量 \t, mac要实际的按下tab键(看起来是个长空格), 详见 References 链接4

git filter-branch --index-filter \
    'git ls-files -s | sed “s-\t-&some-project/-" |
     GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
     git update-index --index-info &&
     mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD

Referecences

  1. Can I move the .git directory for a repo to it's parent directory?
  2. How do you merge two Git repositories?
  3. Unix sed笔记
  4. Simple sed replacement of tabs mysteriously failing
  5. Trying to pull files from my Github repository: “refusing to merge unrelated histories”
uniquejava commented 5 years ago

拆分: 如何将项目中的某个子目录拆成独立的新仓库(同时保留历史).

详见: https://help.github.com/en/articles/splitting-a-subfolder-out-into-a-new-repository

假设子目录的名称为xxx

使用的命令如下

git check master
git filter-branch --prune-empty --subdirectory-filter xxx master
git remote set-url origin git@github.ibm.com:org_name/xxx.git
git push -u origin master

git check 1.x
git filter-branch --prune-empty --subdirectory-filter xxx 1.x # (如果有错误提示加 -f参数)
git push -u origin 1.x

git check 2.x
git filter-branch --prune-empty --subdirectory-filter xxx 2.x # (如果有错误提示加 -f参数)
git push -u origin 2.x
Sunmx commented 4 years ago

linux redhat 用的如下命令,window10 sed "s, ,&'"$PREFIX"'/," | 这里也过不去 git filter-branch --index-filter ' git ls-files -s | sed "s,\t,&'"$PREFIX"'/," | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE ' HEAD

uniquejava commented 4 years ago

linux redhat 用的如下命令,window10 sed "s, ,&'"$PREFIX"'/," | 这里也过不去 git filter-branch --index-filter ' git ls-files -s | sed "s,\t,&'"$PREFIX"'/," | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE ' HEAD

看来mac和linux的sed命令略有区别. windows不认识sed 😃