I'm just learning git and I have a bit of a conundrum...
There are two projects that I do not own:
Now, I want to take one file from Delila and put it into Julio since Julio contains a heap of goodness I need and Delila contains that feature of wonderment that I could really do with.
So, pragmatically, I can do this:
Except the tea tastes sour. I've taken credit for someone else's work (if you look in the history of the file you see only me) and I've lost, potentitally useful historical information (why oh why oh why did that crazy loon do that..?).
So what would the correct thing be to do in this case?
Thanks to @djechlin I have been playing with this, but I still cannot make it work. Here I have mocked up the situation by creating the two repositories Julio and Delila locally. So, here is the starting situation:
~/playing/Julio (master)
$ git log
commit f72960c18392d843d40adfd1c7ab943162005879
Author: xxxxx
Date: Tue Sep 24 08:46:50 2013 +0200
A change after Delila left the building
commit eca80d52acefcb02baae48e717bd8c2d98685c5e
Author: xxxxx
Date: Tue Sep 24 08:31:15 2013 +0200
initial commit from Julio
~/playing/Delila (master)
$ git log
commit 0e7c530246bc782dbf30fb4ac425e031d3626bbe
Author: xxxxx
Date: Tue Sep 24 08:39:06 2013 +0200
Added changes for Delila
commit eca80d52acefcb02baae48e717bd8c2d98685c5e
Author: xxxxx
Date: Tue Sep 24 08:31:15 2013 +0200
initial commit from Julio
You can see that Delila has been forked from Julio and some changes have happend to it. Specifically, the Added changes for Delila commit is the one that I want to maintain.
Now, starting in ~/playing I do this, as per the answer:
~/playing
$ mkdir me
~/playing
$ cd me
~/playing/me
$ git clone ../Delila
Cloning into 'Delila'...
done.
~/playing/me
$ cd Delila
~/playing/me/Delila (master)
$ git remote rm origin
~/playing/me/Delila (master)
$ git filter-branch --subdirectory-filter someFolder -- --all
Rewrite 0e7c530246bc782dbf30fb4ac425e031d3626bbe (2/2)
Ref 'refs/heads/master' was rewritten
~/playing/me/Delila (master)
$ mkdir someFolder
~/playing/me/Delila (master)
$ mv * someFolder
mv: cannot move `someFolder' to `someFolder/someFolder'
Now, I do not want the entire folder so I do this:
~/playing/me/Delila (master)
$ git rm theNewFeature
rm 'theNewFeature'
~/playing/me/Delila (master)
$ git rm anotherFileFromJulio
rm 'anotherFileFromJulio'
Is this the wrong thing to do?
Back to the answer:
~/playing/me/Delila (master)
$ git add .
~/playing/me/Delila (master)
$ git commit -m "filtered Delila"
[master b7fde89] filtered Delila
2 files changed, 0 insertions(+), 0 deletions(-)
rename anotherFileFromJulio => someFolder/anotherFileFromJulio (100%)
rename theNewFeature => someFolder/theNewFeature (100%)
Now I want to "fork" Julio so I do this:
~/playing/me
$ git clone ../Julio
Cloning into 'Julio'...
done.
~/playing/me
$ cd Julio
~/playing/me/Julio (master)
$ git remote rm origin
OK, back to the steps from the answer...
~/playing/me/Julio (master)
$ git remote add repo-A-branch ../Delila
~/playing/me/Julio (master)
$ git pull repo-A-branch master
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 8 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (8/8), done.
From ../Delila
* branch master -> FETCH_HEAD
Merge made by the 'recursive' strategy.
someFolder/theNewFeature | 1 +
1 file changed, 1 insertion(+)
create mode 100644 someFolder/theNewFeature
~/playing/me/Julio (master)
$ git remote rm repo-A-branch
That should be it, so let's look at the log of our special feature we have ported...
~/playing/me/Julio/someFolder (master)
$ git log theNewFeature
commit b7fde8940d761f7babe13d8b6cdfa12fe1685390
Author: xxxxx
Date: Tue Sep 24 09:01:43 2013 +0200
filtered Delila
sigh So what am I doing wrong? Where has the history gone?
This is actually fully within the range of git's capabilities. In general, this is something you ought to be able to expect git to do. Commits are not just codebase snapshots, they are (roughly - merges create branching) linked list of codebase snapshots with a complete history. Git lets you rewrite history so it resembles what you think should have happened. In particular, you don't want to destroy the file's history, but you want to import that too.
Your issue is you don't want to pull in all of the forked repo. So just use filter-branch to import what you need. This accomplishes in one shot what you need: keep these files, keep their histories, but destroy all history that's not pertinent to these files.
I expect to make this doable for yourself, you will either need to 1) become facile with filter-branch or 2) isolate your relevant files in one directory.
This is described in this post here.
Use filter-branch to destroy everything in the original repo not in the directory/ies you care about. Yes, you want to clone and divorce a copy of the original repo first.
git clone <git repository A url>
cd <git repository A directory>
git remote rm origin
git filter-branch --subdirectory-filter <directory 1> -- --all
mkdir <directory 1>
mv * <directory 1>
git add .
git commit
And, simply, pull and merge from the new repo that only contains the things you care about. Keep in mind git repos don't have some ID that say what repo they are. This is a vanilla operation - there just happens to be a copy of repo B lying around that only contains new files.
git clone <git repository B url>
cd <git repository B directory>
git remote add repo-A-branch <git repository A directory>
git pull repo-A-branch master
git remote rm repo-A-branch
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With