Git is a source control system: a system that can be used to manage a directory tree storing source code, documentation or other files (this is called a repository), offering the following main features:
Git uses three important operations, which every user should understand:
Advanced users should become familiar with a git feature called branching.
Branches are multiple versions of the file tree that exist in parallel. Their main use is to keep the clean version in the master branch (known as 'trunk' in SVN) and the work-in-progress version in a separate branch. Once you are happy with the changes, you merge them into the stable branch. This is very useful especially when there are at least two people working on the same repository: each one maintains his own development branch, and they all eventually merge into the stable branch.
A nice feature of branching in git is that when switching to another branch, git automagically makes all the files and changes appear and disappear, depending on whether they belong to the current branch or not. So there is no need to make duplicate directories etc.
A nasty problem is that git does not know what to do with uncommited changes when you switch the branch (what it does is to just carry the changes over, which is most likely not what you intend). You should always commit everything before you switch branches, or stash the changes (more about that below).
The rule of thumb is that you should always have a clean tree (no uncommited changes) whenever you move code around (downloading from remote repository, switching branches, merging changes between branches).
Use the following gitconfig, which has some sane settings. (save it as ~/.gitconfig or /etc/gitconfig). Fill in your name and e-mail.
[user] name = John Doe email = john.doe@epfl.ch [color] ui = auto [color "branch"] current = yellow local = yellow remote = green [color "diff"] meta = yellow bold frag = magenta bold old = red bold new = green bold [color "status"] added = green changed = yellow bold untracked = cyan deleted = red [format] pretty = %C(yellow)%h%Creset %C(bold blue)%an <%ae>%Creset %s %C(green bold)(%cr)%Creset %C(green)(%ci)%Creset%C(yellow bold)%d%Creset [merge] conflictstyle = diff3 [alias] delta = "!f() { git diff $1^ $1; }; f" deltaf = "!f() { git diff --name-status $1^ $1; }; f"
You may also find it useful to customize your shell's prompt when working in a git directory. There are many options available, search for something like custom shell prompt git.
git clone https://mygaspar@git.epfl.ch/repo/smalltest.git
git status
If you use the gitconfig file given above, you should see in yellow files tracked by git which have changes not added to commit, in green files tracked by git which have changes added to commit but not commited yet (i.e. the commit has not been finalized) and in blue the files which are not tracked by git.
$warn If you see a message such as "Your branch is ahead of 'origin/master' by 1 commit", it means that you commited locally but did not push (i.e. upload) the commit to the remote repository. Keep in mind that in git commits are always local, and the push needs to be done manually. $warn
git diff
git add path/to/file
git add path/to/file
git add -p path/to/file
First, check that you added all the necessary files to the commit, then commit:
git status git commit -m 'The commit message'
In git, the remote repository is called origin, and the name of the main branch is master (like trunk in SVN). Therefore the following command means "push the commited changes into the repository origin on branch master":
git push origin master
$warn Warning: you should always commit before pulling. $warn
If you have rebase conflicts, see instructions for solving them in the next sections.
git pull --rebase origin master
git log
git log -p
git log --stat
git log --graph
Note: this is not an actual git command; it is an alias defined in the gitconfig given above.
git delta thecommithash
Note: this is not an actual git command; it is an alias defined in the gitconfig given above.
git deltaf thecommithash
$warn When in doubt, make a manual backup! $warn
Run this command and then commit again:
git commit --amend
I strongly suggest you make a manual backup of your files first.
git reset --soft HEAD~1
git reset HEAD path/to/file
git reset
git checkout -- path/to/file
git rm --cached path/to/file
git rm path/to/file
git stash
git stash pop
git checkout the_right_branch
You ran some command found on the Internet, which was supposed to help you modify your commit history, but instead you lost your last commit(s). They do not even show up in the log anymore, and you start to panic.
First, make a backup of your repository (copy the entire directory somewhere else).
Then inspect the output of:
git reflog
If you see your commit there (let's say its hash is acc3551b13), you can still recover it. Run:
git merge acc3551b13
There is always a branch called master, which is similar to trunk in SVN.
To find out how using more than one branch can be useful, see the 'Git branch workflow' below.
These are branches that have been created or downloaded locally. Normally git will not download all existing branches from the remote unless instructed specifically.
git branch
Remote branches are prefixed with remotes/.
git branch -a
git checkout -b the_branch_name:
git checkout the_branch_name
git checkout -b the_branch_name origin/the_branch_name
git branch -d the_branch_name
$warn WARNING: NEVER start a merge when you have uncommited changes in any branch. $warn
Note: you might have to solve merge conflicts.
git merge branch_x
$warn WARNING: NEVER start a merge when you have uncommited changes in any branch. $warn
Note: you might have to solve rebase conflicts.
git rebase branch_x
Merge takes all the changes in one branch and merges them into another branch in one commit, logging that two parallel timelines have joined. Use it ONLY for intentional changes (new features, modified behavior etc.)
Rebase moves the point at which you branched in the past to a new starting point at the current time, putting all the individual commits that happened in the meantime in a linear timeline. The previous parallel timelines disappear from history. Use it for unrelated changes (e.g. synchronizing changes to module A with changes to module B).
The 'Git branch workflow' below shows when to use merge and when rebase.
$warn WARNING Commit your changes whenever you switch branches, otherwise git checkout will carry the uncommited changes to the other branch. Alternatively you can do a git stash to store away your work and finally git stash pop when you want to restore it. Make sure you are in the right branch when you commit/stash/unstash. $warn
You should always keep the clean, stable version of your work in the master branch, especially if you share your repository with someone else. Do not work in master, instead use a different development branch called yourname-devel (e.g. john-devel).
More advanced users also create a separate branch for any well-defined task which requires several commits with changes that are independent of the work currently hapenning in the master branch; these development branches are usually called feature branches.
There are a few important actions you need to know how to perform:
Create the branch john-devel and switch to it:
git checkout -b john-devel git push -u origin john-devel
Make some changes. Commit as usual.
git add blah blah blah git commit -m 'Blah'
You notice master has been updated remotely (e.g. by a coworker), and you decide to incorporate the changes into your branch. First, commit your changes in the development branch.
git add blah blah blah git commit -m 'Blah'
Switch to master and pull the changes from remote:
git checkout master git pull --rebase origin master
Bring those changes back into the development branch (rebase will redo your commits on top of them, unless there are conflicts):
git checkout john-devel git rebase master
Now you can continue your work in the development branch.
All the commits you make (in any branch) are local to your machine. It is good practice to make several small commits during the day, and upload all your changes to the remote repo at the end of every day--or whenever you switch from one machine to another (e.g. desktop to laptop).
Push commited changes from local into the remote repository:
git push origin john-devel
Pull changes from remote into local (you should always commit first):
git pull --rebase origin john-devel
Note that the last two commands are similar to the way of pulling/pushing changes in the master branch.
This should be done when the task implemented in the development branch is completed.
First, make sure you have committed all the changes in the development branch. Then switch to master and merge:
git checkout master git pull --rebase origin master git merge john-devel
If you use the gitconfig recommended above, text files with conflicts will contain something like this:
<<<<<<< Changes from the current branch. ||||||| The common ancestor version. ======= Changes from branch_x. >>>>>>>
You need to edit the file so that in the end it is clean, without any markers (<<<<, ||||, ====, >>>>).
It might be useful to inspect the commit history starting from the common ancestor. To do this, run:
git log --merge -p path/to/file
Once you have resolved the conflicts in a file, run:
git add path/to/file
Once you have resolved all the conflicts, you must do a commit to complete the merge:
git commit -m 'Merged branch_x, resolved conflicts'
If you want to abort the merge and reset your working copy to the state it was before the merge:
git merge --abort
Versions of git older than 1.7.4 need:
git reset --merge
Versions of git older than 1.6.2 need:
git reset --hard
This is similar to solving merge conflicts. You clean up files with conflicts, and then run:
git rebase --continue
Repeat until git is happy.
It might happen that you want to drop your local changes from a commit completely in a way that looks like an empty commit, in which case git will suspect that you are making a mistake. In this case you need to run:
git rebase --skip
If you want to abort the rebase and reset your working copy to the state it was before the rebase:
git rebase --abort
Tip: make your life easy and rebase often (daily is usually fine), otherwise you will have tons of conflicts which might be difficult to merge. Rebasing weeks of work is bad practice.
You need to install git-svn. Afterwards, use git operations as usual, except for the following:
git svn clone --stdlayout https://the.svn.repo
git svn rebase
git svn dcommit
git svn log
git update-index --assume-unchanged /path/to/file
git update-index --no-assume-unchanged /path/to/file
$warn WARNING: using git push --mirror will first erase the content of the remote repo, then upload your version. If anything breaks during this process, you might have a bad time!!! Backup first using git clone --mirror. $warn
Step 1: mirror the remote into a new directory
mkdir tmp cd tmp git clone --mirror https://the.remote.repo
Now backup:
cd .. cp -r tmp tmp-backup cd tmp
Step 2: change your name in all commits
git filter-branch --commit-filter 'if [ "$GIT_AUTHOR_NAME" = "Bob" ]; then export GIT_AUTHOR_NAME="Robert"; export GIT_AUTHOR_EMAIL=robert@example.com; fi; git commit-tree "$@"'
Step 3: force the remote repository to become a perfect copy of this repository
git push --mirror
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch the/path/to/file' --prune-empty --tag-name-filter cat -- --all git show-ref --head git update-ref -d refs/original/refs/heads/master git update-ref -d refs/original/refs/remotes/origin/master git update-ref -d refs/original/refs/stash git push origin master --force