Git thinks a file within a symlinked directory has been deleted after recreating the symlink, how can I fix it? - linux

I have a symlinked directory within my repository, which links to files elsewhere on the filesystem. For whatever reason, the symlink breaks every now and then, and it turns into a regular empty folder. So I deleted the empty folder, and recreated the symlink with ln -s ../../ ext, which appears to have worked as I can browse that folder and see the contents. But when I run git status, it appears all the files that should be visible within the ext folder are missing. How can I make git see that they are there again, within the symlinked directory?
This is on Ubuntu 18 by the way.

Your setup is odd, because Git does not follow symlinks, it just stores them.
That is, if you have a symbolic link ext -> ../.. and you run git add ext, Git creates, in the index, an entry with mode 120000 (symlink) to store the blob contents ../... Committing will create a commit that, when extracted, will create the symbolic link ext pointing to ../... Git will not store any files within ext when it is storing this symbolic link.
If, on the other hand, you have an existing commit that contains files named ext/foo and ext/bar, and you clone this repository at this commit, or extract this commit into a new and otherwise empty work-tree, Git will see that in order to write to files named ext/foo and ext/bar, your OS requires that ext exists as a directory. It will therefore create the empty directory ext, in which it will then create files foo and bar as your OS requires, so as to create files that to Git are merely named ext/foo and ext/bar. These two names, ext/foo and ext/bar, will now be in the index, so that the next commit you make will also contain these two files.
It sounds like you:
cloned a repository (perhaps with git clone --no-checkout?);
manually created a symbolic link in the work-tree named ext, pointing to some existing directory (perhaps one with some files inside it);
convinced git checkout to create ext/foo and ext/bar without first removing the symbolic link ext and replacing it with a directory ext.
This is not a supported mode of operation1 and you should not be surprised when it goes wrong.
1It leads to security issues: Git is meant not to write any files "outside" the work-tree area, and writing to files "under" a symbolic link to a directory outside the work-tree would allow this to occur. Rather than carefully limit symbolic link usage, Git just generally doesn't store files "beyond" any link in the first place—though it's probably possible, through careful manipulation of the index and, at the OS level, the file system in which your work-tree resides, to trick Git manually.

just dont put a repo in a repo, its not worth it

Related

How to detach a folder from being tracked without deleting any files from it?

I completed MyProject1 and have uploaded it in git in fine way with commits after adding each new features. And now I'm starting MyProject2 and was trying to add the URL for the remote repository. But then I found out that I had mistakenly added the URL in Documents instead of MyProject1 folder because of which MyProject2 folder is also being tracked in MyProject1. And I'm not being able to add URL to MyProject2 but instead facing merge issues.
Is there any way to detach the track from my Document folder without deleting any of my files from Documents.
Structure is this way(I'm using Linux):
Documents
(And inside Documents there is:)
MyProject1
MyProject2
And other folders which are also being tracked.
We can manually do it with below steps
create a file .gitignore in base directory.
If MyProject1 and MyProject2 are already part of git tracking, Please run commands
git rm -r --cached MyProject1/
git rm -r --cached MyProject2/
Open the file in text editor and add below lines in file
MyProject1/
MyProject2/
Best way:
Create a .gitignore file following #Vinayagam R
Ignore file locally
Those methods won't affect other contributors working on the same remote repository:
Use update-index:
If you want to stop tracking a file at certian point.
git update-index --assume-unchanged yourDirectoryName
--assume-unchanged is the flag which means the files should not change locally. In other words, it is used when ignore files that you do not need to change locally (or should not change).
To revert it use update-index --no-assume-unchanged yourDirectoryName
Using .exclude
In your working directory edit .git/info/exclude

git-annex use a file from a different location

My understanding is that when I perform git annex add somefile, it creates a symlink for that file and places it in the .git/annex/objects folder. Then, when I initialize git-annex in some different location and sync it with the previous one, it downloads a broken symlink, unless I do git annex sync --content, which makes a full copy of the file.
I need to have large files in one location, lets say on a USB Drive, and multiple git repositories that use the large files. So I want to have just the symlinks to the large files in those git repos. How to perform the sync so git-annex downloads a valid symlink that points to a file in a single location ?
There are two ways to do that.
First is using hard-links, second is using symlinks. I recommend hard-links if all your files are going to be in the same filesystem/volume/partition, otherwise the good ol' cp --link is just going to copy the entire thing.
Using hard-links:
git clone --shared main_repo/ new_repo/
Explained by git-annex author himself
Using symlinks:
On main_repo:
git worktree add -b branch_name path_to_new_repo/
Since git-worktree uses a pointer file (which git-annex replaces with a symlink), this will work across different file systems. Changes to "different repos" will be stored in different branches. If you want them all to remain in sync, keep them in sync with standard git commands like git merge. Or you could only make changes to the master branch and git rebase master from the different branches frequently.

Are git commands supposed to be run under the working directory directly?

Suppose I have a git working directory, i.e. the directory which has a subdirectory called .git.
I wonder if the current directory matters when I run a git command.
Is it okay to run a git command
directly under the working directory
directly under some subdirectory of (subdirectory of) the working directory
directly under the parent directory of the working directory?
Consider
git commands which can take an argument which specifies some files, e.g. git add, and
git commands which doesn't take an argument that specifies some files, e.g. git pull, git push.
directly under the parent directory of the working directory?
Actually you can run it anywhere you want as long as you reference the git repo:
git --git-dir=/path/to/my/repo/.git add .
That means wherever you are (.: current folder) will be considered as your working tree. A
You can even specify your working tree:
git --work-tree=/a/path --git-dir=/path/to/my/repo/.git add .
In that latter case, you even can execute that last command anywhere you want. The '.' will be the work-tree /a/path.
Since git 1.8.5, you also have the -C option:
git -C /path/to/my/repo add .
Again, you can execute it anywhere you want, but the command will internally do a cd /path/to/my/repo first, and then execute the add .. That means the '.' will actually be /path/to/my/repo.
Finally, since git 2.5, a git repo supports multiple working trees, so you may execute your command in a folder which does not include a subfolder .git (but actually a kind of symbolic link to /path/to/my/repo/git)
It's OK to run both type of commands in both
directly under the working directory
directly under some subdirectory of (subdirectory of...) the working directory
Note, that you should use paths relative to directory where you are
You can't (by default) run any git command in parent directory. You'll get a message that you aren't in any repo.
I wonder if the current directory matters when I run a git command.
It does. git searches the current working directory for the .git subdirectory, and if it doesn't find it then it searches the parent directory, and so on until it finds it.
directly under the working directory
Yes.
directly under some subdirectory of (subdirectory of) the working directory
Yes.
directly under the parent directory of the working directory?
No, not by default. It is possible to tell git where to find the .git directory so that it doesn't search, but this is not the usual mode of operation.
Documentation on the relevant environment variables:
GIT_DIR is the location of the .git folder. If this isn’t specified, Git walks up the directory tree until it gets to ~ or /, looking for a .git directory at every step.
GIT_WORK_TREE is the location of the root of the working directory for a non-bare repository. If not specified, the parent directory of $GIT_DIR is used.
Source
git commands which can take an argument which specifies some files, e.g. git add, and
These commands need to know both where the .git directory is and the relative position of paths in the work tree.
git commands which doesn't take an argument that specifies some files, e.g. git pull, git push.
Commands like git push or git fetch need to know where the .git directory is, but don't care about the work tree. git pull does since it does a git merge which modifies files in the working tree.

Follow symlinks in SVN

I have a linux directory (and don't need any windows checkout):
/home/me/projects/project1
In this project, I need SVN (1.8.8) to follow a symlink "link1":
/home/me/projects/project1/link1/<some_directories_and_files>
But SVN won't let me do that, it just add link1 but not its content. If I try to add its content, I get an error:
svn add link1/*
svn: E145001: Can't schedule an addition of '/home/me/projects/project1/link1/first_directory' below a not-directory node
I tried converting link1 to hard link but I can't do that either:
ln /path/to/my/linked/directory link1
ln: ‘/path/to/my/linked/directory’: hard link not allowed for directory
Any idea? How do you handle this kind of configuration? I just need to commit everything from /home/me/projects/project1 from a simple svn commit
If I understand your problem, you have:
project1/
project1/link1 -> ../../some/where/else
If you do a simple svn add link1 it adds a symlink entry to the subversion repository, but what you're trying to accomplish is getting the stuff under somewhere else into the tree.
If this is the case, then you're fighting in the wrong direction, you should make the real files and directories under link1, and make the target locations symlinks into the link1 directory. That would be a simple solution to the problem.
Another solution would be to make the location ../../some/where/else an svn location in it's own right, and make link1 an externals definition to that location. When you commit in the main directory, the externals would be committed at the same time which would achieve storing the information; however to ensure that the other location was kept in sync, you would have to make sure to update it to the same version as the stored data.
In my case, on my desktop, I have a settings directory:
$HOME/settings
This is a checked out copy of a directory containing .bashrc, .profile, .vimrc, .vim, etc. files and folders from an svn repo. All my profile files and directories were symlinks into this folder, so for example .profile -> settings/.profile, etc. When I make changes, they are reflected in the svn tree, which I can commit back to in order to ensure that I don't lose my config settings when I go to another system.
If you really want svn to follow symlinks as hardlinks (You can't make directory hardlinks because it would be a bad thing™), then you'll have to hack the svn client source so that it did what you wanted; but this would be a maintenance nightmare.
You could get away with making the symlink into a bind mount point directed at the target, but that has it's own issues - you would need to be root to accomplish this, and it ends up leaving funny entries in your /proc/mounts to accomplish this:
mount --bind /absolute/path/to/some/where/else project1/link1
Bind mounting does not work when mounting to inside the svn tree since the working copy format changes introduced by svn 1.7 - svn operations attempt to move files from .svn/tmp to the target folder, which would be a cross device link. The workaround in this case is to go from the inside out, i.e.:
mount --bind project/link1 /absolute/path/to/somewhere/else
With the change in the svn working copy format of a single .svn folder for the checked out tree, you will need to perform all subsequent operations from the true svn location, as it won’t work from the bind mounted folder, on the assumption that you have not mounted the entire checked out tree at that target location.

How to conveniently sync a file between two git repositories

I have two git local repositories. Both share an identical file, under a different path and under a different name. Currently, when I make changes I have to copy the file from one directory to another.
Is there an alternative way to keep them in sync without manually overwriting the file? I don't want to create a separate repository for this file. I thought one of the following things would work, but apparently, they don't:
git submodule
git subtree
symlink soft
symlink hard
What else is there?
The only other alternative would be a post-commit hook on repoA, which would, on each commit:
check if the file is part of said commit
copy it in repoB with the right path.

Resources