Search code examples
gitversion-control

Git format-patch and branch conflicts


I need to create patches from one repo (repo-a) and merge them into another (repo-b). These patches needs to contain the commits themself, so I found that git format-patch and git am is a perfect fit.

We are using multiple branches in repo-a and from time to time, files are added from two different branches and merged into main.

git am doesn't like this.. Here is a full example of the problem;

mkdir repo-a; cd repo-a

git init

touch randomfile
git add randomfile
git commit -m "Adding an initial file"

git checkout -b anotherbranch
touch a-file
git add a-file
git commit -m "Adding a-file from anotherbranch"

git checkout main
touch a-file
git add a-file
git commit -m "Adding a-file from main"

git merge anotherbranch

git format-patch -o patches HEAD~2
# patches/0001-Adding-a-file-from-anotherbranch.patch
# patches/0002-Adding-a-file-from-main.patch

cd ..
mkdir repo-b; cd repo-b
git init
cp -r ../repo-a/patches ./

git am patches/*
# Applying: Adding a-file from anotherbranch
# applying to an empty history
# Applying: Adding a-file from main
# error: a-file: already exists in index
# Patch failed at 0002 Adding a-file from main
# hint: Use 'git am --show-current-patch=diff' to see the failed patch
# When you have resolved this problem, run "git am --continue".
# If you prefer to skip this patch, run "git am --skip" instead.
# To restore the original branch and stop patching, run "git am --abort".

The above fails because git already has the file. Normally, git is happy and adds the patches as it should..

Is there a way to do this, and keep the git commits? I don't want to create one big patch, I want the commits as well.

I have read https://git-scm.com/docs/git-format-patch and enter link description here. I have also tried some random options (like --find-copies-harder), but without any luck.

Some additional info:

  • rebo-b is made from repo-a using cp -r, rm -rf .git and-some-other-files and a new git init.
    • rebo-b is therefor the main repo, rebo-a is just a stripped down version.
    • The main goal of all this is to have someone be able to work on repo-b, but without them having access to everything that is in rebo-b. After copying repo-b to repo-a, I am doing a lot of file-deletions, but only deletions.

Solution

  • I found a way to do this in the way I wanted.

    git remote add otherrepo ../otherrepo
    git fetch otherrepo
    
    # If you want to fetch lfs objects as well
    git lfs fetch --all otherrepo
    
    # -X subtree: Or you will get a lot of merge-conflicts, some of them with empty lines.
    # --signoff: To add signoff on the merge-commit (not the merged commits)
    # --allow-unrelated-histories: This is the main trick!
    git merge -X subtree --signoff --allow-unrelated-histories otherrepo/main
    

    The whole history and everything works as it should. The merge-commit contains what is merged, and history, graph, authors and everything looks good.