Table of Contents
GIT
For a quick memo about different Source Code Management software, see software:scm.
Introduction
Git is a source code version control system. Unlike Subversion (SVN) and CVS it is distributed, so it allows better local source code management (you can commit, branch and so on on your local repository before pushing it on the public repository; you can also never push it on any public repository).
Cheat sheet
Configuration
- ~/.gitconfig
[user] name = Firstname Name email = <email-address> [core] editor = /usr/bin/myeditor
- more in ~/.gitconfig (optional sections):
[color] diff = auto status = auto branch = auto ui = auto [color "branch"] current = yellow reverse local = yellow remote = green [color "diff"] meta = yellow frag = magenta old = red bold new = green bold [color "status"] added = green bold changed = cyan bold untracked = red bold [alias] d = diff -w --color-words
- More aliases, in your shell configuration file (eg .zshenv):
alias gitk='gitk --color-words'
General tips
<commit-hash>
is the hash of a commit, but it can also be just the few first characters as long as it is not ambiguous.
Local repository management
- %
git init
: create a local git repository for your project in your folder - %
git add [-p] <files|dirs>
(or justgit add .
for all files) : add new or modified files to the index (-p to select chunks to include, y/n/s = yes/no/split) - %
git commit [-m <msg>]
: commit the changes of the index to the repository - %
git commit -a
: commit the changes of the working files to the repository (does a “git add” of all the working files before “git commit”) - %
git tag -a <tag-name> [-m <msg>]
: add a tag - %
git reset –hard [<commit-hash>]
: restore the working files and index to the latest commit [or given commit] (everything after is lost) - %
git revert <commit-hash>
: create a new commit that revertr the given commit - %
git checkout <file>
: restore a working file to the last commited version - %
git checkout <commit-hash>
: switch all working files to the given commit version, usegit checkout master
to go back to head
Branches
- %
git checkout -b <branch-name>
: create a new branch (copy of the current branch) - %
git checkout <branch-name>
: switch to the given branch - %
git branch [-a]
: list available branches (-a
to list all branches, including distant branches) - %
git branch -D <branch-name>
: delete the given branch (force even if not fully merged, -d otherwise) - %
git merge <branch-name>
: merge current branch with the given branch - %
git rebase <branch-name>
: rebase the current branch on top of the given branch (if you have to resolve conflicts, do “git add .
” and “git rebase –continue
” once you resolved conflicts for a commit) - %
git cherry-pick <commit-hash>
: apply the changes introduced by a given commit to the current branch (ie import the commit)
Collaborative repository management
- %
git –bare init
: create a git repository in the folder without working files, used for remote repositories, see howto for more details - %
git clone <repo-addr>
: copy the distant repository (<repo-addr> can be “http:<repo>” or “ssh:<user>@<repo>”) - %
git pull [<repo-addr>]
: update from the distant repository (fetch and merge) - %
git pull –rebase [<repo-addr>]
: instead of merging your pending commits with the new ones on master, rebase your pending commits on the top of master (fetch and rebase) ; it creates a cleaner tree and avoids artificial “merged” commits. - %
git stash ; git pull|merge|rebase ; git stash pop
: to pull or merge or rebase when you have non-commited modifications ; store the modifs, pull or rebase, apply the modifs back. - %
git push <repo-addr>
: send to the distant repository (needs ssh clone and write permissions) - %
git push origin <local-branch>[:<dist-branch>]
: push a local branch into a new distant branch - %
git push origin <commit-hash>[:<dist-branch>]
: push until this commit in the given branch - %
git branch <local-branch> origin/<dist-branch>
orgit checkout -b <local-branch> -t origin/<dist-branch>
: create a local branch to track a distant branch (so that you can pull/push with the distant branch) - %
git push -f origin <commit-hash>:<dist-branch>
(after setting temporarily denyNonFastforwards to false in distant git config file) : cancel a previous push, if no one pulled meanwhile
Info
- %
git status
: show the status of the repository and the index - %
git log [–stat|-p] [<branch-name>]
: show the history of modifications - %
git diff [-w]
: show differences between working files and index (-w ignores whitespace changes) - %
git diff –cached
: show differences between index and repository - %
git diff <commit-hash> <commit-hash>
: show differences between two arbitrary commits - %
git info <commit-hash>
: show the diff and message of the commit - %
git blame <file>
: show what revision and author last modified each line of the file - %
git diff [options] > <file-name>
: save the patch to a file - %
git apply <patch> [–index]
: apply a patch to the working tree, and optionally add the changes to the index - %
git format-patch -M origin/master
: create git patches for each of your commits not yet pushed - %
git format-patch -M <first-commit-hash> [<last-commit-hash>]
: create git patches between two arbitrary commits - %
git am <patch>
: apply a commit created with “git format-patch”
Stats:
.mailmap
file: to unify same authors with different name spelling or email address.- %
git shortlog -s -n –no-merges
: number of commits by author. - gitstats project: generates stats in html.
- git-rank-contributors script: number of lines of diff by author. You can add
-w –pretty=format:“commit %H%nAuthor: %aN%nDate: %ad”
options to the git log command, in order to ignore blank changes and use .mailmap file.
Undoing
git –reset
:git reset HEAD@{1}
Howtos
Development method
When you are working on a public project, here is a comfortable method to experiment and publish only what you want:
- clone the repo
- create a local branch named “work”
- commit as often as you can, particularly try to separate functional changes with debug changes
- reorganize and merge your commits to have pretty commits (see editing_commits)
- when you want to push, go back to master, cherry pick the commits you want (or pull if you want all of them), and push them
If you need to fix a past commit, just create a new commit with only the fix, then use “git rebase -i” as explained below, move the fix commit just below the commit to be fixed, and change its status to “fixup”.
Finding a broken commit
git bisect helps you find the commit that broke your code.
- Init:
git bisect start git bisect bad <first-bad-commit-you-know> git bisect good <last-good-commit-you-know>
- Now repeat:
<test-your-code> git bisect bad|good [git bisect visualize]
- At the end the first bad commit is displayed. If you want more information about the process:
git bisect log gitk
- To end the process:
git bisect reset
Creating a remote repository
Create the remote repository (on the server):
cd <repo-location> mkdir <repo-name> && cd <repo-name> chgrp <group> . && chmod a+s . # optional, if you need to change the group git --bare init [--shared=false|group|all|0xxx] echo "Project-Title\nExtensive description" > description
If you want to send emails after each commit, check this section.
- First case, you already have a local repository, then you need to associate it to the remote repository and push (in local repository):
git remote add origin ssh://<username>@<server>/home/<username>/<repo-location>/<repo-name> git fetch origin git config branch.master.remote origin git config branch.master.merge refs/heads/master git push origin master
- Second case, if you don't have a local repository yet you just have to clone it:
git clone ssh://<username>@<server>/home/<username>/<repo-location>/<repo-name> ... git push origin master
You're done, you can now do whatever you want with the distant and the local repositories (clone, push, pull…)
Editing commits
Edit the latest commit (change message and include modifications of given files):
git commit --amend [<file1> <file2> ...]
Collapse the latest commits:
git reset --mixed <base-commit> git commit -a
Edit/Reorganize any past (not yet pushed!) commits:
git rebase -i <latest-commit-to-keep-unchanged> # set "r" (reword) if you want to change message # set "e" (edit) if you want to amend the commit (git commit --amend; git rebase --continue) # set "s" (squash) if you want to merge with the previous commit and merging or editing the commit message # set "f" (fixup) if you want to merge with the previous commit without interaction # you can even reorder the commits!
Tips with rebase -i
:
- If you have a bunch of fixup commits, first move them one by one (i.e. move one, apply, rebase again, move another one, apply, etc), so that if you prefer to abort due to conflicts you don't lose the ones before, and then really mark them “f” (nothing can go wrong afterwards)
- If you are just moving and merging some fixup commits, you may want to check that the end result is identical, by making a copy and then performing a diff.
- If you move a fixup commit up and keep getting conflicts after its initial position, it means that you made a mistake in the conflict resolution
Change author or date: use rebase -i
, chose “edit”, and commit with:
git commit --amend --author "Name <email-address>" --date "$(date -R)"
To split a commit: use rebase -i
, chose “edit”, and reset the index to the commit before, and commit:
git reset --mixed @~ git add -p . git commit
Archive generation
Create a tag and generate the corresponding archive for a release, for instance:
git tag -m "release 0.3.2" 0.3.2 git archive --format=tar --prefix=liboro-0.3.2/ 0.3.2 | gzip > liboro-0.3.2.tar.gz
Setting up email hooks
If you want an email to be sent every time something is pushed on the server, then do on the server:
cd <repo-location> wget http://crteknologies.fr/wiki/lib/exe/fetch.php/software:git:post-receive.txt -O hooks/post-receive chmod a+x hooks/post-receive git config --add hooks.mailinglist "<email1> [<email2>...]" git config --add hooks.emailprefix "[git]"
Removing Sensitive Data
http://help.github.com/removing-sensitive-data/
Then people must pull with git pull –rebase
the first time.
Switching master branch
Recovery
For finding a lost commit you can use “git reflog”.
For finding a lost stash (eg “git stash drop”) or file (eg “git rm”), you can try “git fsck –full”, and then use “git show” with the hash to see the content of the objects.
https://github.com/blog/2019-how-to-undo-almost-anything-with-git