How to copy commits from one Git repo to another?

LinuxGitGithub

Linux Problem Overview


Last week I created a Github repo and forgot to select a license for the repo. Now there are already 3 large commits.

I have asked the 3 contributors if it is ok if I delete the repo and then create it again with the same name and this time selecting the license when creating the repo, and they were fine with that.

Question

Is there a way I can get the commits into the new repo (this time the first commit is the LICENSE file) and still keep the commit meta info?

Linux Solutions


Solution 1 - Linux

> Is there a way I have get the commits into new repo (this time the first commit is the LICENSE file) and still keep the commit meta info?

Yes, by adding a remote and cherry-picking the commits on top of your first commit.

# add the old repo as a remote repository 
git remote add oldrepo https://github.com/path/to/oldrepo

# get the old repo commits
git remote update

# examine the whole tree
git log --all --oneline --graph --decorate

# copy (cherry-pick) the commits from the old repo into your new local one
git cherry-pick sha-of-commit-one
git cherry-pick sha-of-commit-two
git cherry-pick sha-of-commit-three

# check your local repo is correct
git log

# send your new tree (repo state) to github
git push origin master

# remove the now-unneeded reference to oldrepo
git remote remove oldrepo

The rest of this answer is if you still want to add the LICENSE to your previous repo.

Yes. You can place your LICENSE commit as the first commit by rebasing.

Rebasing is gits way of rearranging commit order while keeping all the commit authors and commit dates intact.

When working on a shared repo, it's generally discouraged unless your entire team is git-fluent. For those that aren't, they can just clone a fresh copy of the repository.

Here's how you get your LICENSE commit as the first commit.

  1. Update and rebase your local copy ==

Check out your project and place the LICENSE file in a commit ON TOP of your current 3 commit stack.

#create LICENSE file, edit, add content, save
git add LICENSE
git commit -m 'Initial commit'

Then do an interactive rebase on the master branch to REARRANGE the commits.

git rebase -i --root

It will open an editor. Move the bottom line (your "Initial commit" commit, the most recent commit) to the top of the file. Then save and quit the editor.

As soon as you exit the editor, git will write the commits in the order you just specified.

You now have your local copy of the repository updated. do:

git log

to verify.

  1. Force push your new repo state to github ==

Now that your copy is updated, you have to force push it to github.

git push -f origin master

This will tell github to move the master branch to its new location. You should only force push in rare occasions like this where everybody working with it is aware of the pending change, else it will confuse your collaborators.

  1. Synchronize collaborators to github ==

Lastly, all the collaborators will have to synchronize to this repository.

First they must have clean repositories as the following command can be destructive if there are unsaved changes.

# make sure there are no unsaved changes
git status 

# pull the latest version from github
git fetch  

# move their master branch pointer to the one you published to github.
git reset --hard origin/master

That's it. Everybody should be in sync now.

Solution 2 - Linux

I had a similar problem where I forgot to fork a repo to my github and added several commits before I realized my mistake.

I found a pretty simple solution.

First remove the remote to the original repo

git remote remove origin

Second add a remote to the new fork on my github

git remote add origin <my repo URL>

Then I pushed to origin master and all of my commits showed up on my github.

Solution 3 - Linux

Based on @Moocowmoo's answer but trying to streamline it bit more

What this does differently is tries to avoid conflicts as much as possible, just assuming that the remote is correct.

It doesn't however handle deleted files well, so there is still a manual element.

# assuming you are already on the branch you want to be
git remote add oldrepo https://github.com/path/to/oldrepo
git fetch oldrepo

# take all or subset of changes from a branch
git cherry-pick --strategy recursive --strategy-option theirs oldestCommitHash^..latestCommitHash

# or take all changes included in a specific merge commit (easiest)
git cherry-pick --strategy recursive --strategy-option theirs mergeCommitHash^..mergeCommitHash

# handling deleted files/unhandled conflicts
# just keep repeating this section
git mergetool
# either c/m or d based on if you want to keep or delete the files
git cherry-pick --continue

Solution 4 - Linux

  • Destination Git = UrlD (existing content doesn't matter)

  • SourceGit = UrlS

      git clone UrlS
    
      git remote add origin2 UrlD
    
      git push -f origin2 master
    

Now the Destination will have the same data as Source(You can also use origin instead of origin2)

Solution 5 - Linux

I used the following approach:

  • Clone the source repo to a folder like /c/SrcRepo

  • Clone the destination repo to a folder like /c/DstRepo and switch to the destination branch

  • In the root folder of the destination repo run the command:

    git pull /c/SrcRepo srcBranch --allow-unrelated-histories

No necessary to create an additional remote reference

Solution 6 - Linux

In my case I needed to find out differences between the old and new repos. So in the new repo added the old one.

git remote add old https://gitlab.site.az/old-blog.git

Fetch all remotes

git fetch --all

Find different commits

git log --graph --oneline --pretty=format:"%h%x09%an%x09%ad%x09%s" --abbrev-commit --date=relative develop..old/develop

Get commits you selected

git cherry-pick SHA1 SHA2 SHA4

Solution 7 - Linux

you can try this, it's easy and straightforward. This will push all commits before (and including) the hash you use as <last-commit-hash-from-old-repo> to the other repo:

git clone https://github.com/path/to/new-repo.git new-repo
cd new-repo
git remote add old https://github.com/path/to/old-repo.git
git remote update
git merge --allow-unrelated-histories <last-commit-hash-from-old-repo>
git push origin main

if anyone needs to push all commits from a repo to another as a single commit (like I needed), you can simply add --squash to the merge command like this:

git clone https://github.com/path/to/new-repo.git new-repo
cd new-repo
git remote add old https://github.com/path/to/old-repo.git
git remote update
git merge --squash --allow-unrelated-histories <last-commit-hash-from-old-repo>
git push origin main

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJasmine LognnesView Question on Stackoverflow
Solution 1 - LinuxMoocowmooView Answer on Stackoverflow
Solution 2 - LinuxRuss BainView Answer on Stackoverflow
Solution 3 - LinuxWiR3DView Answer on Stackoverflow
Solution 4 - LinuxBlue CloudsView Answer on Stackoverflow
Solution 5 - LinuxMirrorBoyView Answer on Stackoverflow
Solution 6 - LinuxNagibabaView Answer on Stackoverflow
Solution 7 - LinuxErfan AzaryView Answer on Stackoverflow