-
-
Save x3ro/6242017 to your computer and use it in GitHub Desktop.
#!/bin/bash | |
# We need the TAB character for SED (Mac OS X sed does not understand \t) | |
TAB="$(printf '\t')" | |
function abort { | |
echo "$(tput setaf 1)$1$(tput sgr0)" | |
exit 1 | |
} | |
function request_input { | |
read -p "$(tput setaf 4)$1 $(tput sgr0)" | |
} | |
function request_confirmation { | |
read -p "$(tput setaf 4)$1 (y/n) $(tput sgr0)" | |
[ "$REPLY" == "y" ] || abort "Aborted!" | |
} | |
cat << "EOF" | |
This script rewrites your entire history, moving the current repository root | |
into a subdirectory. This can be useful if you want to merge a submodule into | |
its parent repository. | |
For example, your main repository might contain a submodule at the path src/lib/, | |
containing a file called "test.c". | |
If you would merge the submodule into the parent repository without further | |
modification, all the commits to "test.c" will have the path "/test.c", whereas | |
the file now actually lives in "src/lib/test.c". | |
If you rewrite your history using this script, adding "src/lib/" to the path | |
and the merging into the parent repository, all paths will be correct. | |
NOTE: This script might complete garble your repository, so PLEASE apply this | |
only to a clone of the repository where it does not matter if the repo is destroyed. | |
EOF | |
request_confirmation "Do you want to proceed?" | |
cat << "EOF" | |
Please provide the path which should be prepended to the current root. In the | |
above example, that would be "src/lib". Please note that the path MUST NOT contain | |
a trailing slash. | |
EOF | |
request_input "Please provide the desired path (e.g. 'src/lib'):" | |
# Escape input for SED, taken from http://stackoverflow.com/a/2705678/124257 | |
TARGET_PATH=$(echo -n "$REPLY" | sed -e 's/[\/&]/\\&/g') | |
# Last confirmation | |
git ls-files -s | sed "s/${TAB}/${TAB}$TARGET_PATH\//" | |
request_confirmation "Please take a look at the printed file list. Does it look correct?" | |
# The actual processing happens here | |
CMD="git ls-files -s | sed \"s/${TAB}/${TAB}$TARGET_PATH\//\" | GIT_INDEX_FILE=\${GIT_INDEX_FILE}.new git update-index --index-info && mv \${GIT_INDEX_FILE}.new \${GIT_INDEX_FILE}" | |
git filter-branch \ | |
--index-filter "$CMD" \ | |
HEAD | |
I wanted to say thank you for this script. It saved my life.
Love the script! However there seems to be a problem with it if the history contains empty commits. I managed to solve the problem by modifying line 60 to:
CMD="git ls-files -s | sed "s/${TAB}/${TAB}$TARGET_PATH//" | GIT_INDEX_FILE=${GIT_INDEX_FILE}.new git update-index --index-info && [ ! -f ${GIT_INDEX_FILE}.new ] || mv ${GIT_INDEX_FILE}.new ${GIT_INDEX_FILE}"
thank you for this script...
Great article. Thanks for the script and thanks to @jeremysears for the updated command.
Saved my day. Thx :)
thanks for the script!
Great! Thank you
Thank you!
While reading the article's example, I feel confuse; why is the submodule not inside the parent directory?
after reading the script, I think the script should be executed on the root/parent directory? but the article instruct to change to the directory of your submodule
first and then execute the script? am I misunderstand something important?
I'm a bit confused when tried to integrate my submodule into the root/parent repository without losing its history, also the use case is unique since some submodule have another submodule (yes, I regret creating a bunch of submodule that is not necessary in my case)
the repository I talking about is this
I will assume that you’ve cloned both your repositories into the same directory, one as parent/, and one as sub/.
does this statement mean, that I need to clone two repository that are actually point to the same repository and rename it to parent and sub respectively?
after following the instructions on article:
[hemlo@asus tmp]$ cd sub
[hemlo@asus sub]$ cp ../git-rewrite-to-subfolder .
[hemlo@asus sub]$ ./git-rewrite-to-subfolder
This script rewrites your entire history, moving the current repository root
into a subdirectory. This can be useful if you want to merge a submodule into
its parent repository.
For example, your main repository might contain a submodule at the path src/lib/,
containing a file called "test.c".
If you would merge the submodule into the parent repository without further
modification, all the commits to "test.c" will have the path "/test.c", whereas
the file now actually lives in "src/lib/test.c".
If you rewrite your history using this script, adding "src/lib/" to the path
and the merging into the parent repository, all paths will be correct.
NOTE: This script might complete garble your repository, so PLEASE apply this
only to a clone of the repository where it does not matter if the repo is destroyed.
Do you want to proceed? (y/n) y
Please provide the path which should be prepended to the current root. In the
above example, that would be "src/lib". Please note that the path MUST NOT contain
a trailing slash.
Please provide the desired path (e.g. 'src/lib'): nvim
100644 1293391370fa01bae5bb02f365cf74290a55a888 0 nvim/.gitmodules
100644 1e119b0170031e8f88f949542d14731c5aeb51aa 0 nvim/README.md
160000 4793864bd3e60d121874a9e6d214a9f7645e3a19 0 nvim/bash-config
100644 d9203eb1875f9ce9508d198c12e9da59e42489a2 0 nvim/common.list.pkg.txt
100644 f86195a541f13dc1112025787df0e3575208e89d 0 nvim/common.list.pkg_aur.txt
160000 dc5960ed1c4a2db3bf7b43cbdec0e0076baf8e3b 0 nvim/external-sources/paru-bin
160000 a0274bc20e11d8672bb2953fdd1d3010c0e708c5 0 nvim/external-sources/st
100644 c44b7890cda5261fcfed0582833dc42e41592aea 0 nvim/guest.list.pkg.txt
100644 c5b17856da251d0855a2ba058321b3bc796efee0 0 nvim/host.list.pkg.txt
100755 34e1030a28427323d44303d3c460835e42b11531 0 nvim/install.sh
100644 4475ba8580fab08d1ca3eb1426ac4bec47f27e63 0 nvim/managed_manually.txt
160000 a636c245b52ad19a8e55e3f225bf1aab972eea26 0 nvim/nvim
160000 4a4a04f5ed6ff1837c7193fdf78696056ba54fc8 0 nvim/scripts
160000 122e57315367b7e4ab40e9824b0f90b14bd3ba7e 0 nvim/systemd
160000 e21d726e03baacb21f55cbf9dc863eacde4a4c32 0 nvim/window-manager
Please take a look at the printed file list. Does it look correct? (y/n) y
WARNING: git-filter-branch has a glut of gotchas generating mangled history
rewrites. Hit Ctrl-C before proceeding to abort, then use an
alternative filtering tool such as 'git filter-repo'
(https://github.com/newren/git-filter-repo/) instead. See the
filter-branch manual page for more details; to squelch this warning,
set FILTER_BRANCH_SQUELCH_WARNING=1.
Proceeding with filter-branch...
Rewrite adf3c6b1a3b604b9f9a801a55fe8c45fc9b27dba (49/67) (1 seconds passed, remaining 0 predicted)
Ref 'refs/heads/main' was rewritten
error: Untracked working tree file 'nvim/.gitmodules' would be overwritten by merge.
[hemlo@asus sub]$ cd ../parent/
[hemlo@asus parent]$ rm -r ./nvim
[hemlo@asus parent]$ nvim .gitmodules
[hemlo@asus parent]$ git add -A . && git commit
[hemlo@asus parent]$ git remote add sub ../sub/
[hemlo@asus parent]$ git fetch sub
remote: Enumerating objects: 249, done.
remote: Counting objects: 100% (249/249), done.
remote: Compressing objects: 100% (84/84), done.
remote: Total 249 (delta 94), reused 117 (delta 94), pack-reused 0 (from 0)
Receiving objects: 100% (249/249), 23.80 KiB | 11.90 MiB/s, done.
Resolving deltas: 100% (94/94), done.
From ../sub
* [new branch] main -> sub/main
[hemlo@asus parent]$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
[hemlo@asus parent]$ git merge --allow-unrelated-histories -s ours --no-commit sub/main
Automatic merge went well; stopped before committing as requested
[hemlo@asus parent]$ git clone git@gitlab.com:reyuki/nvim.git
Cloning into 'nvim'...
remote: Enumerating objects: 41, done.
remote: Counting objects: 100% (41/41), done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 41 (delta 15), reused 0 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (41/41), 5.48 KiB | 5.48 MiB/s, done.
Resolving deltas: 100% (15/15), done.
[hemlo@asus parent]$ rm -rf nvim/.git
[hemlo@asus parent]$ git add nvim/
[hemlo@asus parent]$ git commit -m "integrate nvim"
[main 46cc1d7] integrate nvim
[hemlo@asus parent]$ git log nvim/after/plugin/xxd.vim
commit 46cc1d78b931696a026793d776ed6f5c185f4921 (HEAD -> main)
Merge: 6808e93 640b756
Author: Your Name <user@example.com>
Date: Fri Nov 22 15:54:01 2024 +0700
integrate nvim
but as you can see, the history of file xxd.vim is not present, did i miss anything?
problem solved, I ended up using a script that I get from stackoverflow :)
This is awesome. Thank you! Also note that in your main article related to this, the syntax for the following command has changed:
To: