Can git track files in another folder - linux

I am new to git and I keep all my git repos in one folder inside an NTFS disk so that both Windows and Linux partitions can see it. The problem is that executable files in that folder can't be given execution permissions in Linux.
For the repos that contain executable files, I've been working in a directory of the Linux partition, so that I can execute them, and then once I'm done editing them, I copy them back to the relevant repo folder to keep version-controlling them.
Side note (for GolezTrol):
When I say executables, I mean, for example, *.cpp or *.java files. If I want to compile those on an NTFS partition, I will get an error if I try to run the executable. So I can't work in the NTFS folder, I have to work in the Linux partition. Think for example, the workspace folder in Eclipse. I can't make any app work if I place it in the NTFS folder. So I have to move it to the Linux partition, edit my files, and then copy the relevant files back to the repo folder in the NTFS partition. I'm not tracking the executables, I'm tracking the files that produce those executables. I hope this clears it up.
I was wondering if there is a way to keep the version-control of those files in their repo folder, while the files live in the Linux partition, so that I don't have to copy them back when I'm finished editing, and I can still see them from Windows. Something like a link to the executables folder that lives in the repos folder, maybe (it would probably be nice to be able to edit them from Windows too, as if they really lived in the repo folder, but I guess that won't be possible).
I searched SO and found a similar question. I tried the first answer, although it's not exactly what I'm aiming for, but it didn't work for me. I placed the .git file in my executables folder, containing:
gitdir: path/to/repo/in/NTFS/disk/.git
and then initialized the repo, but I got an error:
$ git init
fatal: Not a git repository: path/to/repo/in/NTFS/disk/.git
So I went back to the repo folder (in the NTFS disk), did git init and came back to the executables folder. Now I get a different error:
$ git init
fatal: Invalid gitfile format: path/to/executables/folder
I think I didn't understand the answer.
Regarding the second answer, I couldn't understand how to implement it either.
So, wrapping up, my question is... how can I have the executable files in a folder in the Linux partition but version control them from the repo folder in the NTFS disk? Would it be possible to make Windows see those files?
P.S. I would like to avoid (if possible) getting into mounting or editing fstab files.
P.S2. This question is different to the one I linked. I'm thinking more of a sort of link to the executables folder from the repo folder. It would be ideal to see the files from Windows too. If that is not possible, I'm open to other answers, since the answers in the linked question didn't work for me. Had those answers solved my problem, I wouldn't be asking this question.
Update:
My executables directory:
$ tree -L 1 -aF --dirsfirst
.
├── file.txt
└── .git
0 directories, 2 files
Contents of file.txt: file
Contents of .git: gitdir: /media/admin/DATA/github/af-62/.git
My NTFS directory (that is, /media/admin/DATA/github/af-62):
$ tree -L 1 -aF --dirsfirst
.
├── .git/
├── .gitignore
└── LICENSE.md
1 directory, 2 files
(Please don't pay too much attention to the files, they're placeholder files for now.)
The -a option shows hidden files, as those whose name starts with a dot, and the --dirsfirst shows directories first, so in the first case, .git is at the end while in the second .git is at the beginning.
In the NTFS directory:
$ git log
commit f8f7e3bac01f51e5d819a31e28c1a42c181b0407
Author: private <user#example.com>
Date: Wed Jul 15 11:50:44 2015 +0200
First commit.
$ git checkout /path/to/executables/folder/file.txt
fatal: /path/to/executables/folder/file.txt: '/path/to/executables/folder/file.txt' is outside repository
In the executables directory:
$ git init
fatal: Invalid gitfile format: /path/to/executables/folder/.git
$ git checkout file.txt
fatal: Invalid gitfile format: .git
$ git checkout /media/admin/DATA/github/af-62/LICENSE.md
fatal: Invalid gitfile format: .git
According to jvdm's linked resource, "[...the .git file...] It must point to a valid Git bare repository", but /media/admin/DATA/github/af-62/ is a valid repository, isn't it? What am I doing wrong?

You need to tell git that /path/to/executables/folder is the working
dir of the git repository /path/to/repo/in/NTFS/disk/.git, one way
to do it:
cd /path/to/executables/folder
echo gitdir: /path/to/repo/in/NTFS/disk/.git > .git
Now notice that a git status (if /path/to/executables/folder was
empty) will show all your files as deleted. Then you can:
git checkout .
To checkout them into your working dir.

Related

Where can I find for the location of the repos managed by Gitosis in Linux

We are using Gitosis in our Linux OS server to manage our projects. One time, I mistakenly pushed the config file which contains errors and then I wasn't able to push changes or clone copies of other projects from the server anymore, including gitosis-admin itself. Now, I need to login to the server using the root user and edit the config file there.
So, when I logged on to the server I saw these files:
Then I cd into gitosis-admin:
Then I cd again into gitosis-admin:
Then I vim the config file. This is what I see:
The content is obviously not what I am expecting, because I should have other repos listed in this config file.
I also double checked with git reflog to see the commit history:
Then I thought there might be another gitosis-admin located somewhere else so I search using the command: find / -type d -name 'gitosis-admin'
This is what I got:
The two directories are the ones that I checked. And they do not match the one I have in my local computer.
I tried searching for one of our projects but still I got no result at all.
Then I thought that the root might not have access to the repo files so I switched to the git user by executing the following command:
sudo git
But still, I can't find the directory of the repos.
So now, I need to know where are the repos located so that I might find the "real" gitosis-admin there.
You might be wondering am I checking on the wrong server here. So to prove that I am not mistaken, this is a screenshot of the host address that I am connected to:
This is the remote address of the gitosis-admin git repo shown in source tree:
A typical directory would be the repositories sub-directory of the git user's $HOME directory, that is
~git/repositories
It is possible to change this location using the repositories key of the gitosis section in the configuration file, which typically is a file named .gitosis.conf in the git user's home directory.
To answer the implied question (namely which file to fix to restore gitosis access), that would be ~git/.gitosis.conf as well.
(This is all documented in the gitosis repository's readme file.)

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.

Git ignore and changing the history (on Windows)

I've already read several posts about this here (like Git ignore & changing the past, How to remove files that are listed in the .gitignore but still on the repository?, and Applying .gitignore to committed files), but they have several problems:
Commands that only work on Linux.
Incomplete commands (like the first post I've linked to).
Only for one file.
I have pretty much no experience with Git so I was hoping for some help here.
What I'm basically trying to do is rescue one of my projects history. It's currently Hg and I converted it to Git with Hg-Git (all very easy) and it includes the history (great!). However, I also added a .gitignore file and added several new files & folders that I want completely gone from the history (like the bin and obj folders, but also files from ReSharper). So I'm looking for a way to apply the .gitignore file to all of my history. The commands should work on Windows as I have no intention of installing Linux for this.
No need to add the .gitignore in the history (there is no added value to do it), just add it for your future commits.
For the remove of files and directories in your history, use bfg-repo-cleaner which is fast, easy and works very well on Windows (done in scala).
It will do the job for you!
This is working for me:
Install hg-git.
cd HgFolder
hg bookmark -r default master
mkdir ../GitFolder
cd ../GitFolder
git init --bare
cd ../HgFolder
hg push ../GitFolder
Move all files from GitFolder to a '.git' folder (in this GitFolder) and set this folder to hidden (not the subfolders and files).
cd ../GitFolder
git init
git remote add origin https://url.git
Copy all current content (including .gitignore) to GitFolder.
git add .
git commit -m "Added existing content and .gitignore".
git filter-branch --index-filter "git rm --cache d -r --ignore-unmatch 'LINES' 'FROM' 'GITIGNORE'" --prune-empty --tag-name-filter cat -- --all
git rm -r --cached .
git add .
git gc --prune=now --aggressive
git push origin master --force
There is probably an easier way to do this and it might not be perfect but this had the result I wanted.

svn2git - "hot migration" preserve file permissions

We are migrating SVN to Git. On a project.
Everything is well but I have a problem with preserving the permissions (file mode) of some untracked (ignored) dirs and files.
We the following process:
CleanUp the SVM repo (tidy up, clean uncommited stuff and so forth)
svn2git on local environment (migrating from networked SVN - so latest rev, no further commits, this does include a proper authors.txt mapping and proper tracking of branches, tags, etc.)
Create ignored files & dirs li (.gitignore)st - partially automated from svn propget, manual finish (row by row)
Add the remote and push to it (We're using github but it should hardly matter)
At this stage the remote is ready, all the history is converted. Now comes the hard part I want to hot-migrate the server deployments without changing the dirs, moving files or creating symlinks.
Let's say there are two mirrored environments are on two different servers - one for beta and one for prod. Let us say the dir is /var/www/depl/ for example/. The thing is that as every Web project, there are dirs and files that we don't need to track.
I will be writing my steps wit the commands since I think it could also be a nice guide for others.
So the strategy for on the servers is:
Go there cd /var/www/depl/
BackUp to another dir via rsync and preserve the permissions as they are!!
Delete all .svn directories recursively find -type d -name .svn -exec rm -rf {} \;
Init an empty git repo git init (notice we're not using a 'bare' repo)
Add the GitHub remote and call it "origin", also download all branches git remote add -f https://github.com/ORG/REPO
Check status (the local copy should be clean)
Pull (so fetch + merge but it is actually only a merge) git pull origin master
This last step is what breaks my permissions. Remember those files that I don't want/need to track? It now seems that those have their permissions modified.
They are all properly ignored but when I apply the pull/merge it breaks.
OK, for sure the issue is coming from the remote repository and via the merge. And it is not an issue, but rather how the files were commited (with what file modes).
The question is:
At the last step, when pulling the updates in, can I instruct git to preserve the current file permissions for all files? As in the current dir and recursively down?
So: do not change any local permissions?
Yes, maybe I will have a diff and stuff to commit afterwards, but that is not such a big issue as are the broken permissions.
So? Is there a way? The servers are running Linux of course.
Thanks in advance.
Cheers!
Well, I managed to find a way. The 'secret', as I thought, was in using rsync.
I actually solved my issue, while I was writing the question. :)
Anyway, after some research it turns out that rsync --archive will update the target's permissions provided that the timestamps didn't change. The SAMBA mailing list helped a lot!
A prerequisite is that you ensure that NOTHING WILL CHANGE in those dirs - so put the website in maintenance mode, stop all crons. Make it inaccessible so you don't have headaches later.
The migration (after you have migrated all you history into git) steps are as follows:
Take your production env to the SVN stage that you desire - update, checkout etc. Make sure that this is the same as the incommig git copy and/or keep your changes in patches.
BackUp the deployment directory with rsync rsync -av --progress /var/www/depl/ /var/www/deplBackUp1/ - notice that this includes the .svn dirs
Delete the .svn dirs: cd /var/www/delp/ find -type d -name .svn -exec rm -rf {} \;
Now backUp again in a different location rsync -av --progress /var/www/depl/ /var/www/deplBackUp2/ - the goal is to have two copies
Init the new git repo git init
Add a remote git remote add -f REMOTE_NAME https://github.com/ORG/REPO
Pull everything in from the branch you desire git pull origin master
Now rsync back from your (no-.svn dir backUp) rsync -av --progress /var/www/deplBackUp2/ /var/www/depl
You may also want to look into using bare git repositories for your server deployments.
This last step will fix any file mode issues you may have created with your new VCS.
If you ever need to do this and run into trouble, tag me in a comment - I will try to help.
Cheers!

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.

Resources