How do I make git move its tracking from the current directory, to that of a directory within the current directory. (What it is now)
/current_dir/
/dir_i_want_to_track/
...
...
I want to track dir_i_want_to_track
but right now its tracking current_dir
(What I want)
/dir_i_want_to_track/
...
...
Edit for clarification @AD7six
These directories are within a repo. I started initializing the repo at /current_dir
, and so git has been tracking all changes within /current_dir/
. However, moving forward I want git to track all changes one directory deeper at /dir_i_want_to_track/
, ignoring the other directories within /current_dir/
., so that when I go onto the repo it only shows
/dir_i_want_to_track/
...
and not the other directories.
(I'd also like to keep a history of all previous commits)
CodePudding user response:
Do it slow and steady
The solution proposed here is the combination of 2 simple tasks that require no advanced git knowledge:
- Move the git repository
- Move files in a git repository
Consider the following, which simulates the state in the question:
mkdir -p /tmp/current_dir/dir_i_want_to_track
touch /tmp/current_dir/dir_i_want_to_track/README.md
cd /tmp/current_dir
git init
git add dir_i_want_to_track/README.md
git commit -m "Initial commit"
Here's our start state:
cd /tmp/current_dir
tree
.
└── dir_i_want_to_track
└── README.md
1 directory, 1 file
Move the git repository
Git does not care what the path is to a local repository (except for some edge cases in older versions of git) - so just rename like you would any other folder. In this step we will rename current_dir
such that it is current_dir/dir_i_want_to_track
.
From the parent directory:
cd /tmp
mv current_dir current_dir_moved
mkdir current_dir
mv current_dir_moved current_dir/dir_i_want_to_track
That will achieve this intermediary state:
cd /tmp/current_dir
tree
.
└── dir_i_want_to_track
└── dir_i_want_to_track
└── README.md
2 directories, 1 file
Note that at this point current_dir
is no longer a git repository.
Move files in a git repository
Moving files in git is done with git mv:
cd /tmp/current_dir/dir_i_want_to_track
git mv dir_i_want_to_track/* .
git commit -m "move everything one dir up"
Thus achieving our desired end state:
cd /tmp/current_dir/dir_i_want_to_track
tree
.
└── README.md
0 directories, 1 file
CodePudding user response:
Although there could be unexpected behaviors, you can do it this was:
- Make sure your repository is clean (make a commit if it's not).
- Move the hidden directory called
.git
and located incurrent_dir
todir_i_want_to_track
. - From your new repository, run a
git add --all
and agit commit -m "Change root of repo"
By doing that, your Git history will tell you you "moved" a bunch of files from a subdirectory to the main directory and that you deleted all the files located in the main directory.
CodePudding user response:
Try git filter-branch --subdirectory-filter. Say you are now on the branch foo
.
# backup the current branch foo
git branch foo_backup
# rewrite the branch foo
git filter-branch --prune-empty --subdirectory-filter dir_i_want_to_track
The branch foo
gets rewritten. The commits that don't touch dir_i_want_to_track
will be empty commits. In most cases, you don't want to keep them. --prune-empty
instructs to remove these empty commits on the new branch.
git filter-branch
gives a warning that suggests you use other tools like git filter-repo
. So you could also try these tools.
After the new branch is created, you need to use git push --force origin foo:foo
to update the branch foo
in the remote repository. Make sure that no one else is updating foo
while you are rewriting and uploading it, otherwise their work might get lost.
Update: as @AD7six pointed out, you may want to keep the history. If so, just make a new commit that tracks dir_i_want_to_track
as the root directory.
# if you have run the previous commands and rewritten the branch, first go back to the previous foo.
# if not, skip the following command.
git reset foo_backup --hard
# create a new commit based on the current head and merge it
git merge $(git commit-tree -p HEAD -m "xxx" HEAD:dir_i_want_to_track)
# amend the commit message
git commit --amend
The git commit-tree
part creates a new commit. Its parent is the foo
head, its commit message is xxx
and its root tree is the version of dir_i_want_to_track
in the foo
head. This way, the branch is not rewritten. Instead, it's just like that you remove all the other directories and files, move everything inside dir_i_want_to_track
to the root directory of the repository, and then make a new commit.