home | lab | find me | science | publications | software | toolbox | site map


git tips



git is a fast version control system that changes the way you work (for the better!)

Issuing commands

In the shell, you may change directory to anywhere in the working tree. No matter where you are, git commads apply to the entire repository.

When adding files as arguments to some git commands, such file paths may be relative to the current folder.

An exception is submodules (see below), since they are working trees of their own.

Commits

Commits are always local to your machine.

Data is never lost as long as you don't use advanced commands like git rebase ... and others.

All commits, no matter in what situation they were done, are listed by git reflog. The reflog keeps a listing of all changes to the HEAD. So no matter what, you can always check the reflog and then git cherry-pick <commit-hash> the changes back to your current branch.

If a commit has been done on a (no branch), it's not lost when checking out the master branch or any other. It's stored in a limbo of commits, which is visible by git log -p. Then just git cherry-pick <commit-hash> to bring it into the current branch.

Before committing, one has to use git add <file-name(s)> to specify which files will be committed.

If some files were git add'ed, but not committed, and then you gi checkout <branch-name>, if those files were new they'll disappear from your working file tree. But they are not lost! [Well: they may be lost if you run git gc afterwards.] To recover the "lost" files, run git fsck --lost-found which will scan the repository and then create a folder .git/lost-found/commit and .git/lost-found/other, containing listings of shasums of all git add and git commit operations. To inspect one, do git show <hash>, and to rescue it back to your current branch, do git cherry-pick <hash>.

If you added several commits in a row that fix on another, you may want to squash them into a single commit before pushing them off to a remote, shared repository. For example, to squash together the last two commits, do git rebase -i HEAD~2, where the '-i' means fire an interactive editor (as specified in your shell's $EDITOR). In the editor, each line is a commit. Replace the second 'pick' with a 'squash', then save and quit, then edit the commit message, then save and quit again. Done.

Then pushing will give a "non-fast-forward push" error; to avoid that, do git push +HEAD.

If you had pushed those or a subset of those commits to the remote server before rebasing, then whoever pulls will need to do so with git pull --rebase to avoid the conflict of their current HEAD not being an ancestor of any of of your pushed commits.

Submodules

A submodule is simply a git repository that has been added as part of another, as a component.

To parent repository keeps track of a specific commit (as labeled by its hash) in the submodule.

On cloning a repository that has submodule(s), the latter are init initialized. To do so, call git submodule init <submodule-name> && git submodule update <submodule-name>. The name of the submodule is also the name of the folder in which it lives.

When a submodule repository has been edited and has new commits, it's HEAD will differ from the registerd HEAD that the parent repository is tracking. If now the parent repository is git pull'ed from a remote, then the submodule will be left out as in a (no branch) branch.

To update the tracked HEAD of the submodule in the parent, simply git add <submodule-name> and then git commit that change.

In practice, one treats the submodule as a name. Be careful not to git add <submodule-name>/ (note the ending slash), because this would add to the parent repository all the files of the submodule. If this happens by accident, be sure to git reset --hard HEAD, and then git add <submodule-name> again.

When working with submodules, you should always:

Branches

A (no branch) situation is present in a submodule when pulling the parent git repository, which has listed an earlier commit hash for the submodule repository that doesn't match with the current HEAD of the submodule.

So: always run git branch in the submodule repository to list the branches, and identify a (no branch) situation, before editing and committing files in the submodule. Will save you pain.

If you are in a (no branch) situation, simply git checkout master (or any other branch you want to work in) before proceeding to edit any files.



Last updated: 2012-05-08 11:10 Zurich time. Copyright Albert Cardona.