Skip to content

Instantly share code, notes, and snippets.

@jbrains
Last active July 23, 2017 17:56
Show Gist options
  • Save jbrains/981912ca90eefe49bd03edd52111f681 to your computer and use it in GitHub Desktop.
Save jbrains/981912ca90eefe49bd03edd52111f681 to your computer and use it in GitHub Desktop.
Extract subproject from git repository by grafting commits onto the corresponding files
# CONTRACT
# SOURCE_SUBPRPOJECT_ROOT points to the "same" directory tree
# as TARGET_PROJECT_ROOT. We're extracting the directory tree
# at SOURCE_SUBPROJECT_ROOT into TARGET_PROJECT_ROOT.
#
# There must be a single, linear history in the SOURCE repository.
# Graft the current commit into the target
pushd "$SOURCE_SUBPROJECT_ROOT"
commit_comment="$(git log -1 --pretty=%B)"
rsync $RSYNC_OPTIONS --delete -aiP "$SOURCE_SUBPROJECT_ROOT/" "$TARGET_PROJECT_ROOT"
pushd "$TARGET_PROJECT_ROOT"
git add -A
git commit --allow-empty -m "${commit_comment}"
popd
# Decide what to do next
next_commit_sha1="$(git log --reverse --ancestry-path HEAD..master --pretty=%H | head -n 1)"
if [ -n "${next_commit_sha1}" ];
then
git checkout ${next_commit_sha1}
echo "Keep going."
else
echo "Done!"
fi
popd
@Neppord
Copy link

Neppord commented Jul 23, 2017

Thanks for a nice bit of bash! I learnt new things reading it (pushd/popd and that -1 is applied before --reverse).

I don't understand the use-case for the script. Why not filter-branch or cherry pick?

You might want to use rev-list instead of log --pretty=%H

@jbrains
Copy link
Author

jbrains commented Jul 23, 2017

I didn't think I could cherry-pick because the TARGET project's file tree is inside a subtree of the SOURCE project, and I didn't know any other way to say "apply these changes, but remove /a/b/c/ from the beginning of every file path (and also ignore incidental changes to files outside of the tree /a/b/c/". If filter-branch or cherry-pick could do that, then that's something for me to learn.

@jbrains
Copy link
Author

jbrains commented Jul 23, 2017

Good to know about rev-list! There are always many ways to do it. :)

@Neppord
Copy link

Neppord commented Jul 23, 2017

Sounds like you are re-implementing subtree modules. bbl with some research :).

@Neppord
Copy link

Neppord commented Jul 23, 2017

One more ting though, how does the target repo look like? Is it empty or does it already have some history?

@Neppord
Copy link

Neppord commented Jul 23, 2017

so what you might want is this git push ../tmp $(git subtree split --prefix=src):refs/heads/new_branch where ../tmp is a new git repo and new_branch is the branch you want to create with the subtree in src

@Neppord
Copy link

Neppord commented Jul 23, 2017

ah, there was a command for that :P git subtree push --prefix=src ../tmp newer_branch doeas (i think) the same as the one above.

@jbrains
Copy link
Author

jbrains commented Jul 23, 2017

Excellent! I'll have to try it to see whether it does what I expected. I hope I remember that in case there is a next time. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment