What do the commands with this '-' sign do? - linux

I have this command:
git checkout -b <name>
What does -b do in this command? Where can I read about such commands in git and in the terminal in particular?

The -b option specifies a git branch to check out.
For more information, view the git documentation.
The description of the -b option in the git documentation is a little dense:
git checkout -b|-B <new_branch> [<start point>]
Specifying -b causes a new branch to be created as if
git-branch[1] were called and then checked out. In this case you can
use the --track or --no-track options, which will be passed to git
branch. As a convenience, --track without -b implies branch
creation; see the description of --track below.
If -B is given, <new_branch> is created if it doesn’t exist;
otherwise, it is reset. This is the transactional equivalent of
$ git branch -f <branch> [<start point>]
$ git checkout <branch>
that is to say, the branch is not reset/created unless "git checkout"
is successful.

They are command options or parameters.
Commands can take many different options as input, and usually (but not always) these options are prefixed by - or --, followed by a letter or word, and then sometimes followed again by a value for that option.
For git checkout the -b option allows you to specify a value for branch name.
You can type git --help to view high level options or git checkout -h to find out about options specific to checkout function. However, Git being a large complex tool, has many many options so suggest to check out the official documentation online, rather than only the built in help on terminal.
Getting help for terminal commands in general: For most commands, you can type <command> --help or try -h if that didn't work. To read the long-form manual for a command type man <command>. To search through a list of all available commands try apropros <search terms> to find one you want.
BONUS TIP: If you are new to Linux terminal in general, and want to learn various commands quickly without having to google a lot, may I suggest installing the tldr tool.
sudo apt install tldr
Once installed via the above command, you can run tldr <command name>.
For example try tldr tar and it gives you some nice examples about how to use the tool.

Related

git diff --numstat by strings instead of file paths

I'm trying to run git diff --no-index --numstat <string> <string> on Linux (Debian Docker container), but I'm failing in finding a way to achieve this. In essence I want to pass the files' contents as strings instead of their file paths. The goal is to retrieve the stats from the --numstat flag.
This command should be executable outside of a git repository/directory and on Linux. So far, I've found two solutions which lack the former requirements:
git diff --no-index --numstat /dev/fd/3 /dev/fd/4 3<<<$(echo "<string>") 4<<<$(echo "<string>"): This works on MacOS, but fails to work on Linux.
git diff --numstat $(echo <string> | git hash-object -w --stdin) $(echo <string> | git hash-object -w --stdin): which only works inside git repositories (got this partial solution from here)
Certainly there must be a way to achieve this, either via some git command or other bash concepts I'm unaware of. Any help would be great.
Thanks!
The reason that solution 1. isn't working is that /dev/fd/3 and /dev/fd/4 are symlinks and git diff does not follow symlinks but instead uses their link target string as their "content".
The only way to pass a string to git diff directly instead of a file is as stdin - which obviously only works for one of the files. So I see only two possible solutions to your problem:
write the strings to (temporary) files first, then pass them to git diff
use another tool, as suggested by #B--rian in the comment
Another, shorter version of 1. using process substitution would be:
git diff --no-index --numstat <(echo "<string1>") <(echo "<string2>")
Which unfortunately doesn't work either for the same reason/because git diff does not support process substitution, see https://stackoverflow.com/a/49636553/11932806

How to check for the presence of a git repository in a directory using bash script

I am trying to work with git on my project.
I want to set up the terminal such that whenever I cd into a directory that contains a git project, the terminal should indicate which git branch I am currently on.
If there is a git project, the terminal show only the name of the branch,
for example
(master) $
otherwise it should show the current directory path.i.e
username#machinename:path/to/directory $
I found a similar question answered here but i don't know how to modify the answer to suit my need, because am not good with bash scripting.
Any suggestion will be highly appreciated.
Have a look at this project https://github.com/jimeh/git-aware-prompt, it should solve your whole problem and when not, you can change it to meet your needs. Main logic is in prompt.sh.
To find current git branch name in directory, you can always run
git rev-parse --abbrev-ref HEAD
It will return branch name, HEAD (when detached) or nothing when directory is not par of git repository. If you need only this information, you can update your .bashrc. Edit variable PS1, which is bash prompt format.
PS1='(`git rev-parse --abbrev-ref HEAD 2> /dev/null`) \$ '
This is example how to display branch name anywhere in the prompt. The git script will help you and recognize whether to show branch or directory. It will update your PROMPT_COMMAND, which is called every time the bash prompt line is displayed, by checking for git branch name which you can then use in PS1 as a variable. You can then update your existing PS1='${debian_chroot:+($debian_chroot)}\u#\h:\w\$ ' to
PS1='${debian_chroot:+($debian_chroot)}\u#\h:\w \(\$git_branch\)\$ '
You have many tools which do it.
myzsh for example or just a simplt bash that you add to your bashrc
http://martinvalasek.com/blog/current-git-branch-name-in-command-prompt
example:
function parse_git_branch () {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
RED="\[\033[0;31m\]"
YELLOW="\[\033[0;33m\]"
GREEN="\[\033[0;32m\]"
NO_COLOR="\[\033[0m\]"
PS1="$GREEN\u#\h$NO_COLOR:\w$YELLOW\$(parse_git_branch)$NO_COLOR\$ "
The Git package in Linux usually comes with a prompt script that you can use to see the repository status. To enable it, source the git-prompt.sh script in a shell startup file (e.g. ~/.bashrc), then set a custom prompt with the %s parameter. For example, in ArchLinux you could do:
[ -r /usr/share/git/completion/git-prompt.sh ] && . /usr/share/git/completion/git-prompt.sh
PS1='[\u#\h \W$(__git_ps1 " (%s)")]\$ '
When changing to a directory of a Git repository, the prompt will change to show the branch name. Extra details can be set to be shown by the prompt (see the link above).

What's the easiest way to use the output paths from a git command in a subsequent git command?

I far too frequently use the mouse to do things like this:
/home/me-$ git log --name-status -1
commit a10e63af1f4b1b2c28055fed55d4f2bb3225a541
Author: Me <me#me.com>
Date: Tue Aug 18 13:04:04 2015 -0400
XYZ-376 make ctors public
M x/y/z/Class1.java
M x/y/z/Class2.java
/home/me-$ git checkout -- x/y/z/Class2.java # <-- copy/paste with the mouse
I know that some git commands accept wildcards, and this mitigates this problem somewhat, but I'm wondering if there is a way do specifically reference pathspecs, etc. from previous commands.
How can I run commands like this without using the mouse, and without retyping long paths by hand?
I typically use a subshell ($(<command in subshell here...>)) for this.
For example, sometimes I had many files deleted and I had to git rm every one of them.
There's the command git ls-files --deleted that returns the names of all the missing files. I can combine it with git rm like this:
git rm $(git ls-files --deleted)
This is somewhat a bad example, because (as I discovered later), this operation can be achieved much easier with git add --all. But I think it illustrates the point.
In your case, if you wanted to checkout all files that have been changed in the previous commit, it would be hard to parse the output of git log --name-status, because it contains additional information, but you could use something like git diff HEAD^ --name-only instead.
So:
git checkout $(git diff HEAD^ --name-only)
will do it in your example.
One nice thing that I noticed using the $(...) syntax is that it works both in Bash and in PowerShell.
This'd be the kind of thing you run a shell under emacs for, run all your shells in it and have a command to walk back through the buffer looking for patterns in the output.
For retrieving output from a previous command that you didn't capture inside the shell session, you're going to have to get it from your terminal emulator's buffers somehow. The xterm family has a configurable "copy the whole scrollback buffer" thingy, then xclip -o will print the selection and you can pipe it through an extraction filter.
But it's either capture the output within the session or scrape it from the output buffers afterwards, that's everywhere the data's ever been.
On OS X, "Mouseless Copy" supported by iTerm2 (and probably some other terminal emulators) is a workable solution: https://www.iterm2.com/features.html
search for some portion of the string (⌘F)
expand selection right (tab) or left (shift-tab)
paste selection with (option-enter) or copy/paste in the usual way

How to track changes of my Linux distrib with git?

I am experimenting some linux configuration and I want to track my changes? Of course I don't want to to put my whole OS under version control?
Is there a way (with git, mercurial or any VCS) to track the change without storing the whole OS?
This is what I imagine:
I do a kind of git init -> all hashes of all files are stored, but not the content of the files
I make some changes to my file system -> git detect that the hash of this file has changed
I commit -> the content of the file is stored (or even better the original file and the diff are stored! I know, that is impossible... )
Possible? Impossible? Work-arounds?
EDIT: What I care about is just to minimize the size of the repository and to have a repository containing only my changes. Having all files in my repository is not relevant for me. For example if i push to github I just want it to contain only the files that has changed.
Take a look at etckeeper, it will probably do the job.
What you want is git update-index --info-only or ... --index-info, from the man page: " --info-only is used to register files without placing them in the object database. This is useful for status-only repositories.". --index-info is its industrial-scale cousin.
Do that with the files you want to track, write-tree to write the index structure into the object db, commit-tree that, and update-ref to update a branch.
To get the object name use git hash-objectfilename.
Here is what we do...
su -
cd /etc
echo "*.cache" > .gitignore
git init
chmod 700 .git
cd /etc; git add . && git add -u && git commit -m "Daily Commit"
Then setup crontab:
su -
crontab -e
# Put the following in:
0 3 * * * cd /etc; git add . && git add -u && git commit -m "Daily Commit"
Now you will have a nightly commit of all changes in /etc
If you want to track more than /etc in one repo, then you could simply do it at the root of your filesystem, except add the proper ignore paths to your /.gitignore. I am unclear on the effects of having git within git, so you might want to be extra careful in that case.
I know this question is old, but I thought this might help someone. Inspired by #Jonathon's comment on the How to record concrete modification of specific files question, I have created a shell script that enables you to monitors all the changes done on a specific file, while keeping all the changes history. the script depends on the inotifywait and git packages being installed.
You can find the script here
https://github.com/hisham-hassan/linux-file-monitor
Usage: file-monitor.sh [-f|--file] <absolute-file-path> [-m|--monitor|-h|--history]
file-monitor.sh --help
-f,--file <absolute-file-path> Adding a file to the monitored files List. The <absolute-file-path>
is the absolute file path of the file we need to action.
PLEASE NOTE: Relative file path could cause issues in the script,
please make sure to use the abolute path of the file. also try to
avoid sym links, as it has not been tested.
example: file-monitor.sh -f /absolute/path/to/file/test.txt -m
-m, --monitor Monitoring all the changes on the file. the monitoring will keep
happening as long as the script is running; you may need to run it
in the background.
example: file-monitor.sh -f /absolute/path/to/file/test.txt -m
-h, --history showing the full history of the file.
To exit, press "q"
example: file-monitor.sh -f /absolute/path/to/file/test.txt -h
--uninstall uninstalls the script from the bin direcotry,
and removes the monitoring history.
--install Adds the script to the bin directory, and creates
the directories and files needed for monitoring.
--help Prints this help message.

Moving a git repo to another server

I have a git clone/repo on a development server, but I am now moving to another one. I don't want to commit all my local branches and changes to the main repository, so how can I make an exact copy of everything on oldserver to newserver?
I tried oldserver:~$ scp -rp project newserver:~/project
but then I just get loads and loads of "typechange" errors when trying to do anything on newserver.
Someone said something about x-modes, but how can I preserve that when moving files between servers?
If you want a git solution, you could try
git clone --mirror <oldurl> <newurl>
though this is only for bare repositories.
If this is a non-bare repo, you could also do the normal clone, followed by something like this:
git fetch origin
git branch -r | grep '^ *origin/[^ ]*$' |
while read rb; do git branch --no-track ${rb#*/} $rb; done
git remote rm origin
The middle step can of course be done in 5000 different ways, but that's one! (note that the continuation line \ isn't necessary after the pipe in bash - it knows it needs more input)
Finally, I'd suggest using rsync instead of scp (probably with -avz options?) if you want to directly copy. (What exactly are these typechange errors?)
I've actually done this, and all I did was tar the repo up first and scp it over. I would think that scp -rp would work as well.
"Typechange" would normally refer to things like a symlink becoming a file or vice-versa. Are the two servers running the same OS?
You may also want to try the simple dumb solution -- don't worry about how the typechanges got there, but let git fix them with a reset command:
git reset --hard HEAD
That only makes sense if (1) the problems all pertain to the checked-out files (and not the repository structure itself) and (2) you haven't made any changes on newserver which you need to preserve.
Given those caveats, it worked for me when I found myself with the same problem, and it doesn't require you to think about git's internals or how well your file-transfer process is preserving attributes.

Resources