Table of Contents
List of common Git problems and solutions in a concise format.
Init
git-config
Note: Config files are plain text files and can be edited manually.
Options can be stored:
- per repository (project/.git/config),
- globally for user (~/.gitconfig) – use –global parameter
- globally for all (/etc/gitconfig) – use –system parameter
Local settings override global, which override system wide options.
# List all config values including local: git config -l # List only global options: git config --global -l # set user name for the current repository: git config user.name 'Ludovico Zamenhof' # set email for the current repository: git config user.email my@email.com # set editor globally: git config --global core.editor emacsclient # pass traffic through *HTTP Proxy*: git config http.proxy https://127.0.0.1:3128 # or add the following to the .gitconfig file: # [http] # proxy = https://127.0.0.1:3128
Create a new repository for project:
mkdir myproject cd myproject git init
Clone existing repository:
# myDir is optional target directory name git clone <path-to-my-git-repository>/myproject.git [myDir]
Doing changes
Adding files:
# Start tracking new file: git add new-file-name # Add tracked file to the current changeset: git add tracked-file # Add all files (including tracked) from the current # dir or below to the current changeset: git add . # Show every chunk and ask for adding it: git add --patch
Removing files:
# Remove specified file: git rm file-name # Remove all files from the current dir or below: git rm -r .
Reverting changes
# remove from the current changeset if it has been added: git reset HEAD filename # Undo last commit, preserving local changes: git reset --soft HEAD^ # HEAD~1 in Windows # Undo last commit, deleting local modifications: git reset --hard HEAD^ # checkout the last committed version, when not in changeset: git checkout filename
Good description is the 2nd answer here.
Committing changes
# commit staged changes: git commit -m 'message' #commit all changes (omitting staging area): git commit -a -m 'message' # the same: git commit -am 'message'
Correcting commits
Correct the most recent commit:
- Save your work. :-)
- Commit the changes in “amend” mode:
git commit --all --amend
Recommits with added all changes since last commit.
Note: If there were no changes allows to reedit commit message. - The new changes are added to the old commit.
git log # and/or: git diff HEAD^
Correcting any previous commits:
- Use git status at any stage to see what is happening!
- Save and stash changes.
- Copy from git log ID of the commit you want to correct.
- Start the interactive rebase:
git rebase --interactive ID^ # ^ refers to the parent of selected commit. # Or just use the following to rebase last 3 commits: git rebase -i HEAD^3 # HEAD~3 for Windows
- Editor will come up with several lines like:
pick 19cdb76 commit message
With one line for each commit since the oldest one. - Change pick to edit for commits you want to change.
- Save and quit.
- Edit files you want and then run:
git commit --all --amend
- To move to the next commit run:
git rebase --continue
Git will move to the next commit you would like to fix, stop for resolving conflicts (follow Git’s instructions then), or will finish the rebase.
Branches
Note: A branch in Git is simply a pointer to one of commits.
Showing branches:
git branch # list local branches git branch -v # like above, but with the last commit git branch -a # all (including remote/SVN and tags) git branch --merged # show merged branches git branch --no-merged # show not merged branches git tag -l # show all tags
Creating branches:
git branch newBranchName [master]
- master is the branch you are forking from
- no need to add parent name, when forking from the current branch
Create and open new branch in one step:
git checkout -b new_branch_name [old_branch_name] # Creates local branch newLocalBranch, connected to remote branch remoteBranch git checkout -b newLocalBranch remoteBranch
Open existing local branch:
git checkout newBranchName
Connect local repository to a remote branch
You can do the following (assuming you are checked out on master and want to push to a remote branch master):
# Set up the 'remote' if you don't have it already: git remote add origin ssh://repo.url # Now configure master to know to track: git config branch.master.remote origin git config branch.master.merge refs/heads/master # And push: git push origin master
Merge branch (back to master):
# Switches back to master: git checkout master # Merges branch-name to the current branch, which is # master in this case. In case of conflicts, you will # be prompted to fix them in your editor. Add fixed # conflicts with "git add" and commit. git merge branch-name # Or to always create commit merge: git merge branch-name --no-ff # Or to merge branch's commits as one large commit: git merge --squash branch-name # Show conflicting changes. Staging them will automatically # mark them resolved: git status # Then just commit merge and delete branch if needed. # Abort the merge process and try to reconstruct # the pre-merge state: git merge --abort
Rebasing – integrating changes with linear history
It takes patch of the change introduced in a branch and reapplies it on top of another branch. Rebasing replays changes from one line of work onto another in the order they were introduced, whereas merging takes the endpoints and merges them together.
# Rebase changes from the current branch onto target-branch: git rebase target-branch # Rebase changes from the from-branch onto the target-branch: git rebase [target-branch] [from-branch] # Check out the client branch, figure out the patches from # the common ancestor of the client and server branches, # and then replay them onto master: git rebase --onto master server client
After rebase fast-forward the target branch to include the latest changes:
git checkout target-branch git merge topic-branch git branch -d topic-branch
To turn on rebasing on pull (very useful):
git config --global pull.rebase true
Delete branch
# Delete branch: git branch -d branch_name # Delete branch even having changes: git branch -D branch_name # Deleting remote branch: git push origin :branch_name # Removing local ref to deleted remote branch # (by default "fetch" preserves them): git fetch -p origin
Renaming branches
# Create a branch from a commit (e.g. master~10^2) git checkout -b new-master
Fixing remote master branch
Especially useful for teams that start with git ;-).
# Rename the new branch to master dropping changes # on old master: git branch -M new-master master # Force pushing my master as the new origin/master # (without fast-forward and using changes on # origin/master): git push -f origin master:master # Getting new master on other machines: get fetch git reset --hard origin/master
Ignoring changes
Add to .gitignore files you don’t want to track
cd myproject cat .gitignore # a comment :-) /target pom.xml *.jar
Stop tracking file, but keep its local copy:
git rm --cached <file>
Ignoring local modifications to tracked files:
#Ignore local changes: git update-index --assume-unchanged <file> #Stop ignoring local changes: git update-index --no-assume-unchanged <file> #Stop ignoring local changes on all files: git update-index --really-refresh
Finding things
git diff git diff --word-diff # by word git diff --word-diff=color # by word colored git diff <commit> -- <path> # diff a file with specific commit # Find commits for file: git log -- <path> # Show unpushed commits between remote master and local HEAD: git log origin/master..HEAD # Show commits between remote branch and local version: git log refs/remotes/myremotebranch..HEAD # List all files modified in given commit: git show --name-only <commit> # Show number of commits per user on all branches: git shortlog -s -n --all # Find commits that contain a string: git log -S 'aoeu' --source --all
Remotes
Importing local repository to other server
cd local-repo git push --mirror https://github.com/ghuser/repo.git cd .. rm -rf local-repo git clone https://github.com/ghuser/repo.git
Pushing tags to remote
git push --tags -v
Configure a remote for a fork
# Add remote repo: git remote add upstream <remote-repo> # List all remotes: git remote -v
Syncing a fork
# Fetch all from configured upstream: git fetch upstream # Change to local master: git checkout master # Merge changes from upstream (if there were no local # commits, then it does Fast Forward): git merge upstream/master
Reflog
Reflog keeps lost commits until next Garbage Collection (2 weeks by default)
git log --walk-reflogs mybranch
Turn reflogs on server
git config core.logAllRefUpdates true # Configure it system wide: git config --system core.logAllRefUpdates true
Aliases
# Ignore local changes temporarily: git config --global alias.ignore-temporarily 'update-index --assume-unchanged' # Display history nicely: git config --global alias.hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short # Show nicely fetched changes: git config --global alias.news = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short HEAD..origin/master
Working with SVN (git-svn plugin)
Checking out project from SVN:
git svn clone -s repo.url/mysvnproject myproj
- “-s” tells to git-svn that SVN repository has a standard layout (trunk/branches/tags). If it doesn’t, you can leave that off
- it creates git repo in “myproj” directory and maps it to trunk
- empty directories are not tracked in git, so not shown
- files ingored is SVN are not ignored automatically
Getting changes from SVN:
# Download all new changesets from SVN, apply them to # the last checkout from SVN, and then re-apply your # local changes on top of that: git svn rebase # Downloads all changes (including new branches) # from remote repository. git svn fetch # Like above, but skips tags: git svn fetch --ignore-paths="^tags" git svn fetch --ignore-paths=".*tags.*"
Ignore svn:ignored files:
git svn show-ignore > .gitignore
Commit back to Subversion:
Enable pushing with merge info
# set svn:mergeinfo when pushing merge commits # (pushmergeinfo = true in gitconfig): git config --global svn.pushmergeinfo true
Pushing to SVN repository
# Push all commits from the current branch to tracked remote: git svn dcommit # Like above, but also remove empty dirs: git svn dcommit --rmdir # It can be done also with config param: svn.rmdir git config --global svn.rmdir true
Moving SVN repository to Git (using svn2git program):
mkdir repo cd repo svn2git https://svn.repo.url git remote add origin https://git.repo.url git push origin master git push --tags
Resources:
- Git documentation
- Git Guys – great descriptions of how git works
- A Visual Git Reference
- Oliver Steele – My Git Workflow
- GitReady – learn git one commit at a time
- Git – SVN Crash Course
- Understanding Git Conceptually
- Git clients for Windows
- Git best practices
- A successful Git branching model
- Git SHA-1 collision handling