Merge git repository in subdirectory

后端 未结 7 1332
有刺的猬
有刺的猬 2020-11-30 19:32

I\'d like to merge a remote git repository in my working git repository as a subdirectory of it. I\'d like the resulting repository to contain the merged history of the two

7条回答
  •  没有蜡笔的小新
    2020-11-30 20:01

    After getting the fuller explanation of what is going on, I think I understand it and in any case at the bottom I have a workaround. Specifically, I believe what is happening is rename detection is being fooled by the subtree merge with --prefix. Here is my test case:

    mkdir -p z/a z/b
    cd z/a
    git init
    echo A>A
    git add A
    git commit -m A
    echo AA>>A
    git commit -a -m AA
    cd ../b
    git init
    echo B>B
    git add B
    git commit -m B
    echo BB>>B
    git commit -a -m BB
    cd ../a
    git remote add -f B ../b
    git merge -s ours --no-commit B/master
    git read-tree --prefix=bdir -u B/master
    git commit -m "subtree merge B into bdir"
    cd bdir
    echo BBB>>B
    git commit -a -m BBB
    

    We make git directories a and b with several commits each. We do a subtree merge, and then we do a final commit in the new subtree.

    Running gitk (in z/a) shows that the history does appear, we can see it. Running git log shows that the history does appear. However, looking at a specific file has a problem: git log bdir/B

    Well, there is a trick we can play. We can look at the pre-rename history of a specific file using --follow. git log --follow -- B. This is good but isn't great since it fails to link the history of the pre-merge with the post-merge.

    I tried playing with -M and -C, but I wasn't able to get it to follow one specific file.

    So, the solution, I feel, is to tell git about the rename that will be taking place as part of the subtree merge. Unfortunately git-read-tree is pretty fussy about subtree merges so we have to work through a temporary directory, but that can go away before we commit. Afterwards, we can see the full history.

    First, create an "A" repository and make some commits:

    mkdir -p z/a z/b
    cd z/a
    git init
    echo A>A
    git add A
    git commit -m A
    echo AA>>A
    git commit -a -m AA
    

    Second, create a "B" repository and make some commits:

    cd ../b
    git init
    echo B>B
    git add B
    git commit -m B
    echo BB>>B
    git commit -a -m BB
    

    And the trick to making this work: force Git to recognize the rename by creating a subdirectory and moving the contents into it.

    mkdir bdir
    git mv B bdir
    git commit -a -m bdir-rename
    

    Return to repository "A" and fetch and merge the contents of "B":

    cd ../a
    git remote add -f B ../b
    git merge -s ours --no-commit B/master
    # According to Alex Brown and pjvandehaar, newer versions of git need --allow-unrelated-histories
    # git merge -s ours --allow-unrelated-histories --no-commit B/master
    git read-tree --prefix= -u B/master
    git commit -m "subtree merge B into bdir"
    

    To show that they're now merged:

    cd bdir
    echo BBB>>B
    git commit -a -m BBB
    

    To prove the full history is preserved in a connected chain:

    git log --follow B
    

    We get the history after doing this, but the problem is that if you are actually keeping the old "b" repo around and occasionally merging from it (say it is actually a third party separately maintained repo) you are in trouble since that third party will not have done the rename. You must try to merge new changes into your version of b with the rename and I fear that will not go smoothly. But if b is going away, you win.

提交回复
热议问题