How to fix a git tracked file that is treated as untracked? - linux

Symptoms
I have a strange issue where I want to checkout a different branch <branch2>, but when I try I get the message that
$ git checkout <branch2>
error: The following untracked working tree files would be overwritten by checkout:
<filename.xlsx>
Please move or remove them before you switch branches.
Aborting
However git ls-files lists <filename.xlsx> as a tracked file.
Workaround
If I do a git checkout -f <branch2> it works, and the <branch2> version of the excel file is present and correct (similarly if I rm <filename.xlsx> and then checkout I get the correct file.)
To move back to <branch1> I get the exact same issue (<filename.xlsx> is tracked, but for checkout appears to be untracked).
Testing/Troubleshooting
Investigating further this seems to be related to a Windows/Linux issue:
I work predominantly in a VirtualBox VM of Debian, so I use my git tooling and terminal there, and access via a VirtualBox shared folder.
Some of my code (this repository included) lives on the host system (Windows 10) as it is platform specific.
If I use Git for Windows this issue does not occur.
If I clone to a linux filesystem this issue does not occur.
If I clone from upstream to a different Windows folder and access from linux I get the same issue.
Other branches in the same repository that have the same file with different contents again do not suffer from the same issue (ie checkouts work as expected)
Other commits with the same version of the file have the same issue.
A small repo with just these two file versions does not exhibit the same behaviour, so, unfortunately, no easy way to create MCVE.
Final Thoughts
Honestly, it is something that is relatively easy to work around, and seems limited in scope so far to only these two copies of the , but it has me intrigued. If anyone with greater knowledge of git has any ideas on how to diagnose/fix the root cause of this issue I would be very grateful.
Extra debugging
Here is the results of git ls-files --debug from <branch1>
CodeSheet.xlsx
ctime: 1489465633:751038200
mtime: 1489465633:751038200
dev: 38 ino: 5432
uid: 0 gid: 999
size: 14752 flags: 0
Here is the results of git ls-files --debug from <branch2>
Codesheet.xlsx
ctime: 1489467487:720851100
mtime: 1489467487:720851100
dev: 38 ino: 5502
uid: 0 gid: 999
size: 12546 flags: 0

Just a guess: this could be a case of a file with a different case but the same name.
From the case-insensitive Windows OS perspective, it is tracked, but from a case-sensitive Debian OS perspective, it is not tracked.
Try:
git config core.ignorecase true
The OP Gavin mentions in the comments using "Changing capitalization of filenames in Git", with the git mv command.

Related

Cannot git pull due CONFLICT(MODIFY/DELETE) and symlink

Our Laravel project is using symlinks. Recently when I tried to pull from my colleague's work, I get this message:
CONFLICT (modify/delete): resources/lang/en/validation.php deleted in HEAD and modified in a262067feb430a072c1d3abf2ec500150212ff0f. Version a262067feb430a072c1d3abf2ec500150212ff0f of resources/lang/en/validation.php left in tree.
error: failed to symlink 'resources/lang/en/validation.php': File name too long
Upon trying to git rm the file, I am told it doesn't exist and is deleted in HEAD. Then when I pull I get the same message as above. Upon trying to touch the file and git add the file, and commit and then pull (in order to push my changes to the same branch), I get a similar error message:
CONFLICT (content): Merge conflict in resources/lang/en/validation.php
CONFLICT (modify/delete): resources/lang/en/auth.php deleted in HEAD and modified in a262067feb430a072c1d3abf2ec500150212ff0f. Version a262067feb430a072c1d3abf2ec500150212ff0f of resources/lang/en/auth.php left in tree.
error: failed to symlink 'resources/lang/en/auth.php': File name too long
I have tried to skip-worktree the file, assume-unchanged the file and to change the git config setting via git config --local core.longpaths true to allow long-paths. None have worked. I think it has to do with the symlink, but I haven't run the script yet and so I don't know how this is a barrier to pulling for git.
When I do try to run the symlink, I get this error message:
error: unable to create symlink resources/lang/en/auth.php: File name too long
error: unable to create symlink resources/lang/en/validation.php: File name too long
Long story short, I cannot git pull, and therefore cannot git push. What's the solution? I don't want to git push force it.
Running git pull is just running two Git commands:
First, git pull runs git fetch. This obtains any new commits needed for the second command.
Second, git pull runs ... well, this can be complicated. You are having it run the default, though: git merge.
Usually when git pull fails, one of these two commands that it runs is the one that actually failed. The second command fails more often unless you have a particularly flaky Internet connection. In your case, it's the git merge that failed.
The word failed is usually too strong, really. Most merges do not actually fail. They just stop in the middle of the operation due to a conflict (or two conflicts, in your particular case). But your merge is a little special. It really does have an internal failure, which repeats several times:
error: unable to create symlink resources/lang/en/auth.php: File name too long
error: unable to create symlink resources/lang/en/validation.php: File name too long
This is happening because your OS is placing a hard limit on the length of the target of a symbolic link. As you found:
It seems it was trying to make a symlink out of the content inside the file instead of the file name ...
Git's internal limits are much bigger than your OS's.
A symbolic link is just data, at one level, and that's how Git tends to store it (as a blob object, but one with mode 120000 rather than the normal file mode of 100644 or 100755). At another level, the data will be interpreted as a file name, and that file name tends to have a length limit, such as 1024 or 4096 bytes.
What would git show do?
git show will spill out the contents of the symlink, when pointed to a symbolic-link object.
$ git hash-object -w -t blob /usr/share/misc/termcap
d305cd8e161ecc8a78b0485d1926b9600efc6cb7
$ git update-index --add --cacheinfo 120000,d305cd8e161ecc8a78b0485d1926b9600efc6cb7,crazy
$ git commit -m "add crazy-long symlink"
[master dbb6e35] add crazy-long symlink
1 file changed, 4725 insertions(+)
create mode 120000 crazy
The normal tools will no longer work with this repository (which I made just to hold this crazy-long symlink):
$ git log | sed 's/#/ /'
commit dbb6e35967041fa4b03812866999ea0acd640dce
Author: Chris Torek <chris.torek gmail.com>
Date: Sun Nov 15 19:52:05 2020 -0800
add crazy-long symlink
commit c6e238c122dcd41410e7fdcfaa47ac112e935a35
Author: Chris Torek <chris.torek gmail.com>
Date: Sun Nov 15 19:51:58 2020 -0800
initial commit
$ git checkout HEAD^
This works fine, but trying to check out the second commit fails:
$ git checkout master
error: unable to create symlink crazy: File name too long
D crazy
Previous HEAD position was c6e238c initial commit
Switched to branch 'master'
What happens at this point is that Git simply leaves the symbolic link out of the working tree entirely. That's why it is in state D. You can still do work with the repository, but you cannot use the regular tools in the regular way.
With your merge, what you can do is delete the bad symbolic links entirely (safely), create correct (good) ones, and add them.

Branch-specific configuration file maintenance with git

Here is a question keeps me puzzled for a long time as I cannot find nice and more-or-less universal solution to it.
Lets say there are two git branches available, production and dev; each uses it's own configurable parameters for some tasks (i.e. credentials, build path, test/deployment scripts switches et cetera). Same time implementation scripts & code is common for both branches.
Now, the problem arises is - how to maintain branch-specific configuration within git repository the way required. One of common solutions out there is to use 'template' configuration file within git, symlinking and ignoring the concrete for specific branch, like
$ cat .gitignore | grep conf
/concrete.conf
$ ls -l *.conf
lrwxrwxrwx 1 1000 100 12 Oct 29 10:23 concrete.conf -> generic.conf
-rw-r--r-- 1 1000 100 0 Oct 29 10:16 generic.conf
breaking and adjusting concrete.conf on development box next. Yet not a solution I'm in pursuit for.
My requirements (ok, wishes) are:
support separate configuration file per git branch, and
keep branch-specific configuration file managed by git same time
Is it even possible? Could be (actually, preferred to be file sourced by some other one, but it's none related...)
The best that has came to my mind so far is to use post-merge hooks to adjust per-branch configuration per se from some other source ignored by git, but it stinks from the very beginning.
Any suggestions on solution of problem described ?
PS: *nix-specific suggestions (i.e. using symlinks/hardlinks) suggestions is absolutely fine, I do do have any interest in M$ targets
It is possible, and does not involve symlinking.
You do not version my.config, but a template file my.config.tpl, and a value file (with values for each branches)
prod.conf
dev.conf
Then, you can use a content filter driver, using .gitattributes declaration.
(image from "Customizing Git - Git Attributes", from "Pro Git book")
The script generate my.config file by replacing placeholder values with the values of the <branch.conf> file, each time you checkout a branch.
You can know about the current branch name with:
branch=$(git rev-parse --symbolic --abbrev-ref HEAD)
The generated actual my.config remains ignored (by the .gitignore).
That means your actual working tree does not get "dirty".
The smudge script selects the correct value file and generates the correct web.config based on the template the smudge script is applied on during a git checkout.
See a complete example at "git smudge/clean filter between branches".

Is the detached HEAD my current project files or not?

I'm following instructions for a kernel project and am told to:
Export the kernel to use from the repository at the URL:
git://git.yoctoproject.org/linux-yocto-3.14
You will need to switch to the 'v3.14.26' tag,
So I did:
git clone git://git.yoctoproject.org/linux-yocto-3.14
Once the project downloaded, I typed in:
git checkout 'v3.14.26'
and was greeted with a message about how I'm now in detached HEAD state. It also output the following:
HEAD is now at 356a3e1... Linux 3.14.26
But it seemed weird that nothing in the project downloaded or changed; I ran show-branch and was told [master] Merge tag 'v3.14.24'
So is the project actually at version 3.14.26 or not? I don't really get what's going on, though I think I understand what's happening with detached HEAD after reading about it. I'm not going to be making any changes to the solution, I'm just following the guide to use the specific 3.14.26 version of the kernel.
Keeping things simple, HEAD will only be attached if it's pointing to a Branch (something you can commit to). When you point your HEAD to a Tag, your working copy will be based on that commit, but since you cannot commit to a Tag, it will tell you are detached.
To make sure you are where you think you are, run:
git log --decorate=short --oneline --branches=*
If it places HEAD on the same commit as v3.14.26, you're good. Example:
λ git log --decorate=short --oneline --branches=*
bdeddd5 (origin/master, origin/HEAD, master) XXX
5250588 YYY
647f007 ZZZ
d5cc025 (HEAD, tag: v3.14.26) WWW
55736b0 PPP

GIT: Can't Push (Strange Config Issue)

I'm on a fresh install of Linux Mint.
I'm getting the following error when trying to push from any repository:
error: Malformed value for push.default: simple
error: Must be one of nothing, matching, tracking or current.
fatal: bad config file line 8 in /home/leng/.gitconfig
fatal: Could not read from remote repository.
This is very odd, because I definitely have a version that supports the simple push behavior.
The output of git --version is git version 1.8.3.2.
The contents of ~/.gitconfig:
[user]
name = My Name
email = MyEmail#website.com
[color]
ui = true
[push]
default = simple
Here's where it gets creepy.
If I change the behavior to matching (or to nothing, tracking, or current, for that matter), then attempt to push, I get the same exact error message. How is that possible? Is it caching the config somehow? I've even tried rebooting. I've even tried purging GIT completely from the system (and deleting ~/.gitconfig) then reinstalling it.
If I delete the [push] section completely from the .gitconfig file (or if I delete the file entirely), then try to push, then I get this:
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the current behavior after the default changes, use:
git config --global push.default matching
To squelch this message and adopt the new behavior now, use:
git config --global push.default simple
See 'git help config' and search for 'push.default' for further information.
(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode
'current' instead of 'simple' if you sometimes use older versions of Git)
error: Malformed value for push.default: simple
error: Must be one of nothing, matching, tracking or current.
fatal: bad config file line 8 in /home/leng/.gitconfig
fatal: Could not read from remote repository.
...so it appears to be both acknowledging that I haven't chosen a pushing behavior, but then also saying that I've chosen an unsupported behavior. What on earth is going on here?
I even get the error if I delete ~/.gitconfig completely.
Can anyone help me out with this witchcraft?
Thanks!
EDIT:
Here is a .git/config file requested:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = ssh://{my remote repo}
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
Okay, so I fixed it, but the method is absolute witchcraft.
I tried to isolate the problem by purging GIT, deleting the config file, reinstalling GIT, then creating a local bare repository, then cloning it, then attempting to push from there. Pretty much like this:
sudo apt-get purge git-core
rm -f ~/.gitconfig
sudo apt-get install git-core
cd /git
mkdir foo
cd foo
git init --bare
cd /var/www
git clone /git/foo
cd foo
touch blah.txt
git add -A
git config --global user.name "Name"
git config --global user.email "user#email.com"
git commit -m "Blah"
git push
...same exact error message, no change there. (Still some serious witchcraft.)
Then, I deleted one of my repositories that doesn't have a local origin (it connects to its origin via SSH) and cloned the repository anew after deleting it (with a fresh git clone ssh://... command).
I got an error from the clone command:
remote: Malformed value for push.default: simple
remote: Must be one of nothing, matching, tracking or current.
Ah ha! Now it says remote instead of error. So the remote doesn't support this behavior. (That doesn't explain why the error persists on local-only repositories with local origins, then, though.)
So I then SSH'ed into the remote server and updated the git-core there to the latest version, re-attempted to clone the repository from my local machine, and it worked.
Now, I can finally git push. Insanely, this also fixed it so I can git push from the entirely local /var/www/foo to the also entirely local /git/foo (the local origin bare repository). SSH'ing into this remote server and updating it somehow - WITCHCRAFT - fixed my local machine's error.
Why on earth the entirely local repos care about an entirely different machine's GIT version is... beyond me. How utterly, utterly insane.
I had the same error message on git push.
For me it turned out that the remote user's git was an older version (1.7.2.5),
and I had recently updated the remote ~/.gitconfig to include:
[push]
default = simple
The solution was to remove this setting from the remote's configuration.
Since it seems other people are having this issue, and I found a solution HERE, I thought I'd post the solution that worked for me.
IN SHORT:
The solution I found was at this page. Evidently the best solution is to upgrade to a newer version of Git (if possible). That was not an option for me, however. From a local machine, I typed the following command:
git config -–global push.default upstream
This got rid of the Malformed value for push.default: simple error I had been getting. I'm not entirely sure what upstream does, however.
MY CONTEXT (for comparison): I had an empty (bare) repository on a remote computer, and I had a few repositories on a couple "local" workstations. I pull from the remote repository, do some work, and then push my work to the remote repository. Pushing/pulling was accomplished via SSH. Most of the time, while working on a local machine, pushing/pulling would result in the error described above.
In short, before the fix, I had the following ~/.gitconfig file on the remote machine:
[user]
name = Foo Bar
email = FooBarPerson#email.com
[diff]
external = /Users/foobar/bin/git-diff-cmd.sh
[color]
diff = auto
status = auto
branch = auto
[push]
default = simple
After entering in the above command, my ~/.gitconfig file on the remote machine changed to:
[user]
name = Foo Bar
email = FooBarPerson#email.com
[diff]
external = /Users/foobar/bin/git-diff-cmd.sh
[color]
diff = auto
status = auto
branch = auto
[push]
default = upstream
Version information:
Remote machine (repository location): 1.9.4
My laptop: 1.8.5.2 (Apple Git-48)
Other computer I work on: 1.7.7.4
Here's another site that may be useful to some people:
http://www.lorrin.org/blog/2011/10/03/argumentless-git-pull-and-git-push/comment-page-1/

Cygwin: git svn complains about bad config file

On Cygwin using git-svn performing remote operations such as:
git svn rebase
git svn dcommit
etc.
Causes one of many strange error messages to occur regarding bad config files
$ git svn rebase
fatal: bad config file line 1 in /home/tj/.gitconfig
fatal: bad config file line 1 in /home/tj/.gitconfig
Cannot rebase: You have unstaged changes.
Please commit or stash them.
rebase refs/remotes/git-svn: command returned error: 1
There aren't actually any unstaged changes, that error message seems to be an artifact of the config file issue:
# On branch master
nothing to commit (working directory clean)
Occasionally it complains about other lines in the same file, or about lines in .git/config
My actual git config files are very simple, and the exact same ones work fine on other machines (which are also running Cygwin). For reference:
.gitconfig:
[user]
name = tj
email = tj#example.com
.git/config:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
preloadindex = true
[svn-remote "svn"]
url = https://url.to/repository
fetch = :refs/remotes/git-svn
The octo-spacing is a tab in the file, and looking at the file in vim with set list shows no strange characters muddling around.
The strangest part of all is that sometimes it just works without issue. However, after a short period of time, it continues showing the error messages. If anyone knows that the issue may be, or how to resolve it, I would greatly appreciate it.
Thanks!
Edit:
What I've tried so far:
Copying good config files from working machines running Cygwin
Running rebaseall in Cygwin
Reinstalling git-svn package
What I might try:
Reinstalling Cygwin (would rather not)
Edit2: Success?
After fiddling around with this for a few hours, I tried removing things from the git configs one by one and seeing if it made a difference.
Removing preloadindex = true from the .git/config file seems to have resolved the issue, though it is difficult to say for sure.
The culprit was indeed core.preloadindex = true, which does not play nice in cygwin.

Resources