Git: Recovery of files possible after local remove before push? - linux

I wanted to "clean" my git repo before pushing by removing every JPG file, so I entered:
find . | xargs rm *.png
in the git root and now everything is delted. Also my *.py files are deleted, but I do not know why? It is a Linux, Ubuntu machine. Is there any chance to recover my files? Maybe over my OS?

The command you typed is plain wrong:
find .
This command outputs the name of every file and directory below ., including hidden files.
xargs
This command takes its input and runs the command given as its argument, feeding it one line at a time as an argument. Therefore, it will run rm *.png <line1_from_find>, then rm *.png <line2_from_find>, etc.
There is no safeguard like stop on errors, so if you let the command run completely, it unlinked all files and you know have an empty directory tree. And git will not help you, because it works by storing its metadata and current state within a .git directory at the root of the working directory. In which you just deleted all files.
So no, unless you made a copy, either manually or by pushing you state to some other place, it's probably gone, but see below. For future reference, here is the correct command to destroy all files ending in png:
find . -name '*.png' -delete
Optionnaly add -type f before the -delete if you may have directories ending in .png, to filter them out.
Okay, what now: it happens that git marks some of its internal state as read-only, which rm honors if you didn't use rm -f and you might be able to recover some data from that. Go to the .git directory at your working directory's root. It will contain a objects directory, and some files may have survived there.
Those files are raw compressed streams, you can see their content using that command:
zlib-flate -uncompress <path_to_the_file
(the zlib-flate command comes from qpdf package on ubuntu)

for me the following worked:
$ git checkout -- name_of_deleted_directory
or
$ git checkout -- path_to_local_delected_directory
In my case, I deleted a directory by mistake and I didn't change any code in that directory but I had changed code in other directories of my git repo.

Related

Extract tar archive excluding a specific folder and its contents

With PHP I am using exec("tar -xf archive.tar -C /home/user/target/folder") to extract the contents of a specific archive (archive.tar) into the target directory (/home/user/target/folder), so that all existing contents of the target directory will be overwritten by the new ones that are contained in the archive.
It works fine and all files in the target directory are being overwritten after extract, but there is one directory in the archive that I would like to omit (from extracting and thus overwriting the existing one in the target folder)...
For example, the archive.tar contains:
folderA/
folderB/
folderC/
folderD/
fileA.php
fileB.php
fileC.xml
How could I extract (and overwrite) all except (for example) folderC/? In other words, I want folderC and its contents to remain intact in the user's directory and not be overwritten by the one contained in the tar archive.
Any suggestions?
(Tar on the hosting server is GNU version 1.23.)
You can use '--exclude' to omit a folder:
tar -xf archive.tar -C /home/user/target/folder" --exclude="folderC"
There is the --exclude PATTERN option in the tar tool.
Check: tar on linuxcommand.org
To be on the safe side, you could remove all write permissions from the folder. For example:
$ chmod 000 folderC/
An then do a normal tar extract (as regular user). You'll get some error messages on console, but your folder will remain untouched.... At the end of the tar, change back your folder original permissions. For example:
$ chmod 775 folderC/
Of course '--exclude' tar option is the right solution to this particular problem, but, if you are not completely 100% sure about a command syntax, and yor're handling critical data, my solution puts you on the safe side :-).
Write --exclude='./folder' at the beginning of the tar command.
In your case that is,
exec("tar -x --exclude='./C' -f archive.tar -C /home/user/target/folder")

Checking changes made before/after installing application?

On Linux, I need to know which files were added/modified/moved/deleted after compiling and installing an application from source code, ie. the command-line, Linux equivalent to the venerale InCtrl5.
Is there a utility that does this, or a set of commands that I could run and would show me the changes?
Thank you.
Edit: The following commands are sort of OK, but I don't need to know the line numbers on which changes occured or that "./.." were updated:
# ls -aR /tmp > b4.txt
# touch /tmp/test.txt
# ls -aR /tmp > after.txt
# diff -u b4.txt after.txt
If you only need to know which files were touched, then you can use find for this:
touch /tmp/MARK
# install application here
find / -newercm /tmp/MARK
This will show you all files whose contents or metadata have changed since you touched /tmp/MARK (including newly added files).
I would personally use something like Mercurial (version control) to do this.
The main reason, is that it is not only effective but it is also clean, since it will only add a hidden directory to the top of the tree where you want to check these changes.
Let's say that you need to know what files changed in /etc/. So before installation (you need to have mercurial installed) you add the directory to mercurial:
cd /etc
hg init
hg add
hg ci -m "adding all files in /etc/ to track them down"
The above will effectively "add" all the files to track them. To verify nothing has changed:
hg st
Should return no files.
If you (or the installation) modifies a file, you should see something like this:
hg st
M foo.sh
The "M" before the file states the given file was modified.
For new files you would see a ? before the file like:
? bar.sh
After you are done and no longer want Mercurial, simple remove the hidden directory:
cd /etc
rm -rf .hg

svn problem. I can't add it because it's already in another SVN

svn add guess_language/
svn: warning: 'guess_language' is already under version control
Why is this? When I downloaded it, it was under SVN. (I downloaded it from SVN)
How do I release that svn...so that I can turn it into a regular directory?
Remove the .svn directory inside guess_language/ and it's parent (if that also came from another SVN repository). This should allow you to add it to another SVN repository.
This also must be done recursively through guess_language's children. A command which can do this for you (depending on your Linux environment) is:
find . -name '.svn' -type d -exec rm -rf {} \;
(You probably shouldn't just take that for granted, test it with a non-deleting version, i.e find . -name '.svn' -type d and check the only directories listed are the ones you want to remove.)
you can force it to be added to your repository. Use:
svn add --force [folder]
Inside the guess_language directory there will be a hidden directory called .svn. This is how SVN knows that the directory is under version control. Delete that directory and you will then be able to add it to your SVN repository. You will have to do this for every directory, as each directory will have its own .svn directory.
(As an aside, if you look at the contents of a file called entries inside that directory, you can see the url of the SVN repository that the directory originally belonged to)
If you want a "copy" of the directory out of version control, use svn export. The exported directory will contain all the under version control contents of the original one, but will be a "regular directory".
Best regards.
Nuke all the .svn directories.
cd guess_language
find . -name .svn | xargs rm -fr
As the others said, remove the .svn directories to make subversion forget that it's a working copy checkout out from some repository. In the future you can svn export instead of svn checkout to download the files from svn without creating a working copy from them.

Copying the .svn directories from a checkout to a non-checkout to make it a checkout

I have a large application in a production environment that I'm trying to move under version control. So, I created a new repo and imported the app, minus various directories and files that shouldn't be under version control. Now, I need to make the installed copy a checkout (but still retain the extra files). At this point, in a recent version of SVN, I'd simply do a checkout over top the existing directory using the --force option. But sadly, I have an ancient version of SVN, from before when the --force option was added (and can't yet upgrade... long story).
So, I checked out the app to another directory, and want to simply copy all of the .svn directories into the original directory, thus turning the original into a checkout whilst leaving alone the extra files. Now, maybe I'm just having a rough day and missing something that's in plain site, but I can't seem to be able to figure this out. Here are the approaches I've tried so far:
Use rsync: I can't seem to hit the right combination of include and exclude directives to recursively capture all the .svn directories but nothing else.
Use cp: I can't figure out a good way to have it hit all the .svn directories across and down through the whole app.
Use find with -exec cp: I'm running into trouble with the leading part of the pathnames of the found files messing up the destination paths. I can exclude it using -printf '%P', but that doesn't seem to go into the {} replacement for exec.
Use find with xargs to cp: I'm running into trouble with find sending over child directories before sending their parents. Unfortunately, find does not have a --breadth option.
Any thoughts out there?
Other info:
bash 3.0.0.14
rsync 2.6.3 p28
cp 5.2.1
svn 1.3.2
Use tar and find to capture the .svn dirs in a clean checkout, then untar into your app.
cd /tmp/
svn co XXX
cd XXX
find . -name .svn -print0 | tar cf /tmp/XXX.tar --null -T -
cd /to/your/app/
tar xf /tmp/XXX.tar
Edit: switched find/tar command to use NUL terminator for robustness in the face of filenames containing spaces. Original command was:
tar cf /tmp/XXX.tar $(find . -name .svn)
(5) Can't you just make a checkout to a different directory, then copy the extra files to that directory, verify that everything's fine before switching to running the app from the new directory?

How can I recursively copy a directory into another and replace only the files that have not changed?

I am looking to do a specific copy in Fedora.
I have two folders:
'webroot': holding ALL web files/images etc
'export': folder containing thousands of PHP, CSS, JS documents that are exported from my SVN repo.
The export directory contains many of the same files/folders that the root does, however the root contains additional ones not found in export.
I'd like to merge all of the contents of export with my webroot with the following options:
Overwriting the file in webroot if export's version contains different code than what
is inside of webroot's version (live)
Preserve the permissions/users/groups of the file if it is overwritten (the export
version replacing the live version) *NOTE I would like the webroots permissions/ownership maintained, but with export's contents
No prompting/stopping of the copy
of any kind (ie not verbose)
Recursive copy - obviously I
would like to copy all* files
folders and subfolders found in
export
I've done a bit of research into cp - would this do the job?:
cp -pruf ./export /path/to/webroot
It might, but any time the corresponding files in export and webroot have the same content but different modification times, you'd wind up performing an unnecessary copy operation. You'd probably get slightly smarter behavior from rsync:
rsync -pr ./export /path/to/webroot
Besides, rsync can copy files from one host to another over an SSH connection, if you ever have a need to do that. Plus, it has a zillion options you can specify to tweak its behavior - look in the man page for details.
EDIT: with respect to your clarification about what you mean by preserving permissions: you'd probably want to leave off the -p option.
-u overwrites existing files folder if the destination is older than source
-p perserves the permission and dates
-f turns off verbosity
-r makes the copy recursive
So looks like you got all the correct args to cp
Sounds like a job for cpio (and hence, probably, GNU tar can do it too):
cd export
find . -print | cpio -pvdm /path/to/webroot
If you need owners preserved, you have to do it as root, of course. The -p option is 'pass mode', meaning copy between locations; -v is verbose (but not interactive; there's a difference); -d means create directories as necessary; -m means preserve modification time. By default, without the -u option, cpio won't overwrite files in the target area that are newer than the one from the source area.

Resources