Overriding remote git repository

alex_ber
4 min read1 day ago

--

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:

Allow force pushes

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.

https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#allow-force-pushes

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. .gitignoreamong the others has .ideaas 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 and https://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 repo2directory.

Note: The --force option is used to overwrite the history of repo2 with the history of repo1. 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 repo2directory, 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.

--

--