Git and Magit Basics
I'm not a huge fan of git's CLI or its documentation, This page exists to remind of the basics whenever I forget them, which is basically always.
Local, remote, clone, fork
A git repo can be standalone or it can be associated with one or more remote repos, which acts as a source and destination for commits. You can create a local, standalone repo by running
On the other hand, if you create a local git repo via a git clone command
git clone <URL>
then a remote repo is set up to point to the URL cloned from. By default the command will give the remote repo an easy to remember name like origin but you can change that behaviour with the -o or --origin option:
git clone -o <name> <URL> git clone --origin <name> <URL>
You can check your remote repos with this command:
git config remote.$(git config branch.$(git symbolic-ref --short HEAD).remote).url
And you can add a remote (called origin in this example) after the fact by doing this:
git remote add origin <URL>
Forking isn't a concept in git, but rather a concept in github and other similar code sharing platforms.
Normally, if you want to contribute to a project on github, you have a couple of options.
- if you have write access to the repo, you can just clone it and start hacking.
if you do not have write access to the repo, you can fork it, which will create a copy of the repo into your own account. Now you can clone it and start hacking. Getting the changes back to the original repo (known as the upstream in github parlance) requires the use of something called a pull request
git push -u origin master git push --set-upstream origin master
To check the status of a repo
will give you a summary of what's changed in the repo.
git status -s
will give a useful shorter summary, with M, A, R telling you what's been modified, added, removed. Two columns are shown, telling you the status with respect to the index and to the working directory.
will give you a diff between your working directory and the index, while
git diff --staged
will give you the diff between your index and the repo, while
git diff HEAD
gives you the diff between the working directory and the latest commit. This is probably the closest thing you have to hg diff.
All of these will dump the diff to stdout. You can configure another tool by doing adding the following line to your "~/.gitconfig":
[diff] external =
Where you have to configure a special script because git calls it like this:
script "path", "old-file", "old-hex", "old-mode", "new-file", "new-hex", "new-mode"
But that means that all your diffs will use this script, which is possibly not what you want. So got offers another kind of diff, called difftool:
which is specifically designed for viewing diffs when the standard one won't do. You configure it like this
[diff] tool = <tool>
Git offers a range of difftools pre-configured "out-of-the-box" (kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, diffuse, opendiff, p4merge and araxis), and also allows you to specify your own.
One other thing: I usually like to
- get a directory diff before looking at the individual diffs and b. avoid the tool prompts
You can get the former with -d and the latter with -y, like this:
git difftool -d -y
And remember that difftool takes the same arguments as diff, so add a HEAD if you want the difference between the working directory and the last commit:
git difftool -d -y HEAD
If you like using meld:
git difftool --tool meld --staged -y -d
Undoing an add
To undo the add to the index, use
git reset HEAD <file>
Undoing a commit
To undo the last commit, use
git reset --soft HEAD~1
(reset will move the branch pointer to HEAD~1, which is the commit right before HEAD. The --soft makes ure everything in your working directory remains intact)
git has a notion of bare repositories. Bare repositories are repositories that contain no files, just the metadata.
You create a bare repository by use the --bare option during git init or git clone.
By default you can only push to a bare repository. That's why it's important to know about them. Pushing to a non-bare repo is considered weird because you won't be at the tip when you do so. Your working directory will be out of sync with your metadata.
In mercurial, this doesn't seem to be considered as weird. You push to the remote repo, and the remote repo has to do a hg update to get the latest changes.
Anyway, you can still push to a non-bare repo, you just have to configure it to do so. On the remote repo, you have to run this:
git config receive.denyCurrentBranch ignore
That will set up the non-bare repo to accept changes.
The equivalent to
hg strip <changeset>
in git is
git reset --hard <changeset> git gc --prune=now
To rest the state of your working directory:
git reset --hard
To clean all untracked files :
git clean -f
To clean all untracked files including directories
git clean -fd
To clean all files, including ignored ones:
git clean -xf
To stage all changes and new files :
git add .
But to stage all changes, including removed files:
git add -A
To create and switch to a branch
git checkout -b new-branch
Switch back to master:
git checkout master
Merge the commits from the previous branch:
git merge new-branch
Delete the old branch:
git branch -d new-branch