Git Subtree only one file or directory
Solution 1
If I understand, you seem to want to only merge in a certain directory of a different repository, and you want it to be a subtree in your repository. I am going to call the directory of interest in the project.git path_of_interest_in_project
and call the destination in your repo directory_desination_path
.
Try adding the remote project.git as a remote, then checking out one of its branches locally. Then use git-subtree split
to split out just the directory of project.git you are interested in. After that merge it into your repo using subtree merge.
git remote add project [email protected]:kicaj/projectname.git
git branch project_master project/master
The branch project_master should now store the entire history of your project.git repo.
Then you'll need to use the git-subtrees-split
process.
git checkout -f project_master
git subtree split --squash --prefix=path_of_interest_in_project -b temp_branch
There should now be a branch called temp_branch
containing just the directory you are interested in. Now you can perform a git-subtree-merge
to bring it all into your repo.
git checkout -f master
git subtree merge --allow-unrelated-histories --prefix=directory_destination_path temp_branch
This should merge in the temp_branch into your master branch.
Solution 2
Suppose you wanted to add the images/
prefix of the octocat git repo at the ref master
.
Suppose we want to use the remote hosted at https://github.com/octocat/octocat.github.io.git (Note: GitHub returns error: Server does not allow request for unadvertised object
in the following fetch
command is you specify a sha1 not associated with named ref)
Starting on the branch you wish to add the subtree to, let's first fetch the desired commit history and checkout our new branch
git fetch https://github.com/octocat/octocat.github.io.git master:tmp_octocat_master
git checkout tmp_octocat_master
Next, let's create a new history where only the files under our desired prefix (images/
) exist.
git subtree split --prefix=images -b subtree_split_branch
Finally, let's add this subtree to our desired branch (presumably the last branch you were on, git checkout -
)
git checkout -
git subtree add --prefix=public/images subtree_split_branch
Now you should have all the desired files on your current branch with a full git history.
Alt Squashed history
At time you want the commits in our subtree to be squashed into a single commit. This to a certain extent defeats the purposes of adding a subtree but it has it's place. The following is a variation of what is described above to limit the history pulled into your repo
Starting on the branch you wish to add the subtree to:
git fetch --depth=1 https://github.com/octocat/octocat.github.io.git master:tmp_octocat_master
git checkout tmp_octocat_master
Note: we are specifying --depth=1
in the above since we are using the --squash
is the following git subtree split
command.
git subtree split --squash --prefix=images -b subtree_split_branch
git checkout -
git subtree add --prefix=public/images subtree_split_branch
kicaj
Updated on June 14, 2022Comments
-
kicaj almost 2 years
I use Git Subtree like below:
git subtree add --prefix=directory_destination_path --squash [email protected]:kicaj/projectname.git master
But in path:
directory_destination_path
copy all repo fromprojectname.git
How to copy to
directory_destination_path
only subdirectory or only some file fromprojectname.git
?EDIT:
One more question:
How to update (automatic) files changes in both repositories were still the same? It is possible? -
kicaj about 10 years
git subtree split squash --prefix=path_of_interest_in_project temp_branch
always return: does not exist; use git subtree add -
kicaj about 10 yearsI change
path_of_interest_in_project
toModel/Behavior
- there are directories -
kicaj about 10 yearsI would like use
repo1/Model/Behavior/file.php
torepo2/Model/Behavior/file.php
They should always the same content regardless of which I change -
eddiemoya about 10 yearsI had a typo. It should be
--squash
-
eddiemoya about 10 yearsAs far as them being in sync, theres no built in way to just automatically keep these files (only) in sync. You would have to write a script to handle it all. An easier thing might be to track these files as independent repo's and use them as subtress in both projects. This is simply not a good workflow overall.
-
2rs2ts over 9 yearsProblems: you need to
git fetch
before you cangit branch
otherwise you getfatal: Not a valid object name
. And when I got to thegit subtree split
I wasn't sure what to do after that because I gotfatal: ambiguous argument 'temp_branch': unknown revision or path not in the working tree.
. -
Lefteris almost 9 yearsThere was a typo in the command. I edited it. A -b was needed before the name of the branch. It now works exactly as the OP intended.
-
ChenYilong over 8 yearsthen how to update the only one file or directory? do every steps again?
-
rudolph9 over 5 yearsAs far I can tell,
git subtree split --squash --prefix=path_of_interest_in_project -b temp_branch
only ifpath_of_interest_in_project
is a directory. In which case it grabs the commits related to all the files in that directory. Is there a way to specify one and only one file? -
rudolph9 over 5 yearsNOTE: I do not believe
git subtree split
currently supports specifying a single file. It builds off and passed the--prefix
command directly togit read tree
. > --prefix=<prefix>/ Keep the current index contents, and read the contents of the named tree-ish under the directory at <prefix>. The command will refuse to overwrite entries that already existed in the original index file. Note that the <prefix>/ value must end with a slash. -
Jan33 over 3 yearswhy do we need
public
in--prefix=public/images
? -
mhr over 3 yearsThen how can this subtree get updated based on its own remote?
-
fuzzyTew about 3 yearsThis answer must be out of date and should be updated.
git subtree merge
withoutgit subtree add
produces a "does not exist" error for me. The--allow-unrelated-histories
flag is not accepted either. -
stimulate over 2 yearsalso
git subtree split --squash
gives "The '--squash' flag does not make sense withgit subtree split
" -
stimulate over 2 yearsOmitting
--squash
and usinggit subtree add
instead ofmerge --allow-unrelated-histories
worked fine in my case! :)