Note: Creating a Pull Request (PR) directly from one unrelated remote repository (repo1) to another (repo2) is not supported by Git or platforms like GitHub, GitLab, and Bitbucket. Pull Requests are designed to work within a single repository or between a repository and its forks.
Yes, I should get repo2
as fork from repo1,
so no problem occurred in the first place. But sometimes repo2
already exist and you can’t just recreate it as fork. So, what to do?
GOTCHAS
Before I’ll proceed I want to talk about two problems that I had to solve.
Protected baranch — allow force pushing or unprotect main branch or any other protected branch. Otherwise, the script below will fail.
Here you can read what it is and what is for.
You can read about this concept on GitLab or GiHub.
To our business:
Quote from GitLab:
Force pushing
Complex operations in Git require you to force an update to the remote branch. Operations like squashing commits, resetting a branch, or rebasing a branch rewrite the history of your branch. Git requires a forced update to help safeguard against these more destructive changes from happening accidentally.
Force pushing is not recommended on shared branches, because you risk destroying others’ changes.
If the branch you want to force push is protected, you can’t force push to it unless you either:
* Unprotect it.
* Allow force pushes to it.
Then you can force push and protect it again.
https://docs.gitlab.com/ee/topics/git/git_rebase.html#force-pushing
Here https://docs.gitlab.com/ee/user/project/protected_branches.html#allow-force-push-on-a-protected-branch you can find what to do on GitLab.
Quote from GitHub:
By default, GitHub blocks force pushes on all protected branches. When you enable force pushes to a protected branch, you can choose one of two groups who can force push:
1. Allow everyone with at least write permissions to the repository to force push to the branch, including those with admin permissions.
2. Allow only specific people or teams to force push to the branch.
If someone force pushes to a branch, the force push may mean commits that other collaborators based their work on are removed from the history of the branch. People may have merge conflicts or corrupted pull requests. Force pushing can also be used to delete branches or point a branch to commits that were not approved in a pull request.
Enabling force pushes will not override any other branch protection rules. For example, if a branch requires a linear commit history, you cannot force push merge commits to that branch.
Here https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule#editing-a-branch-protection-rule or here https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule#deleting-a-branch-protection-rule exact command are described.
Handling .idea, .gitignore, .dockerignore
In my case .gitignore
and .dockerignore
was missing. .gitignore
among the others has .idea
as directory to be ignored. So, I run the script below but.idea
folder that was pushed by mistake (again no guard from .gitignore
). So after this I ended up with situation that I have .idea
, .gitignore
, .dockerignore
in my working tree.
To make story short:
If you already somehow have unwanted files in Git remote (.idea for example) the easiest way to fix it is to go to Git remote, and remove those files (.idea for example) from their and pulling the change to Git local.
Also, I want to copy all branches, not just main.
# Clone repo1
git clone https://path-to-repo1.git repo1
cd repo1
# Clone repo2
git clone https://path-to-repo2.git ../repo2
cd ../repo2
# Delete the history of repo2
rm -rf .git
# Copy the history of repo1 to repo2
cd ../repo1
cp -r .git ../repo2/
# Push all branches to repo2
cd ../repo2
git remote set-url origin https://path-to-repo2.git
Note: Make sure to replace
https://path-to-repo1.git
andhttps://path-to-repo2.git
with the actual URLs of your repositories.
If you want to copy default branch only (usually main
) you can type:
git push -u --force origin main
from repo2
directory.
Note: The
--force
option is used to overwrite the history ofrepo2
with the history ofrepo1
. Be very careful with this command as it will rewrite the history of the remote repository.
If however, you want to copy all branches, you need to write some bash script. In repo2
directory, create file push_branches.sh
(of course, you can give it any name you want).
Put the following content:
#!/bin/bash
# Fetch all branches from repo1
git fetch origin
# Push all branches to repo2
for branch in $(git branch -r | grep -v '\->' | grep -v 'origin/HEAD' | sed 's|origin/||'); do
git checkout $branch
git push -u --force origin $branch
done
Now:
chmod +x push_branches.sh
and
./push_branches.sh
If you have problems read GOTCHAS again at the beginning of the post.