[TOC]
Stash and Reset
Before git pull it is probably smart to stash (hide and protect) your local changes.
Or conversely you may need to undo a commit you have made locally (the changes remain in the filesystem but are not recorded in git)...
git reset --soft HEAD^
remove a single commit before it was pushed, the brute force way of not having to use git rebase to quickly fix something before git push
git stash
hide your local changes (this will ignore new files which might still collide after a git pull (shrug)) this has the useful side effect of undoing "git add"
git stash list
stash@{0}: WIP on master: 9fb7df8 parent commit message here
list the number of cached local changes in the stack
git stash pop
pop off the local stack the most recent cached local changes this may create conflicts that must be resolved - and after resolving the changes you may have to git stash drop
git stash drop
Dropped refs/stash@{0} (95915fd57ff7734c370e8587ca1e97457c013043)
delete a cached local change (be careful!)
Branches
Create a new branch
git branch NAME
git checkout NAME
git add --all .
git commit -m "JIRA number"
git push --set-upstream origin NAME
sometimes it is faster to type git push and copy paste the error message with the branch name (badpokerface)
Some older notes :
git remote add new-branch-name git://user@bitbucket.org/user/myproject.git
touch .gitignore
git commit -a -m "added an empty .gitignore"
git push --set-upstream origin new-branch-name
git status
On branch new-branch-name, othing to commit, working directory clean
Create a git branch from a previous commit
git branch NAME <commitsha>
git checkout NAME
this creates the new local branch starting with the commit, the second command actually uses the new local branch
Merge master into your branch
Merging is the big reason to use distributed version control. Changes from different "parents" can be "auto-merged" and the end result is more productivity.
A few things to remember:
- Never rebase a branch that someone else is using (since rewriting history essentially forces everyone to git clone again and try and re-apply their changes by hand)
- master is just a branch name
- auto merge is just software trying its best, you should always double check the result (i.e. sometimes extra lines can be added which in dynamic languages won't even cause data corruption or crashes until runtime)
- merge master into your branch first to minimize the conflicts
-
git pull is really git fetch and git merge in one step, so git fetch provides more control over how the merge occurs
git checkout master git pull git checkout new-branch-name git pull git merge master Merge branch 'master' into new-branch-name # preserves all commit history and messages
git push # push master + new-branch into new-branch repo on remote Counting objects: 1, done. Delta compression using up to 24 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 362 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) To git@bitbucket.org:username/myproject.git 008d6c4..e2cbf40 new-branch-name -> new-branch-name
git branch -v master 26572a7 add some random feature * new-branch-name e2cbf40 Merge branch 'master' into new-branch-name
git clone user@repository.domain.com:projectname.git # --recursive? git remote show origin (discover the url, name, and branches)
(or git remote -v)
git pull; git submodule update --init --recursive; # update including submodules
Delete a branch
git push origin --delete <branchName>
Deleted a remote branch
git branch -D <branchName>
Deleted the local branch
Remove Changes and Cherry Pick Commits
Remove changes before a push
git rm --cached mylogfile.log # remove a single file from git repo (without deleting the local copy)
git rm -r --cached .idea # remove folder with pycharm project files from git repo without deleting the local copy
# removing from git stuff that's already been deleted on the LOCAL system
git add -u # update
git rm $(git ls-files --deleted) # OR this alternative
git push = "! [rejected] master -> master (fetch first)" # push failed so now fixing it...
git status # we have a commit saved
git log # view commits history
git reset --soft HEAD^ # keep the index around just in case
git status # see we've "uncommitted"
git stash # save local changes
git status # verify master clean
git pull # get the new stuff
git log # verify the new stuff
git stash pop # retrieve local changes
git add . # add local changes (preparing a commit)
git commit -m # commit message
git push # finally!
git tag -a 1.3.2 -m "product version 1.3.2 release"
git push --tags
git tag -a 1.3.2 1fd2f84fbfafc5fa998bfbb4f776058f116062f1 -m "product version 1.3.2 release"
to pin the tag to a specific commit (i.e. not HEAD)
git tag -d 1.0
git push origin :refs/tags/1.0
Delete a tag
Git Cherry Pick a specific commit
git cherry-pick afd3be516abf90e3d22c26fa01a560ae70510247
use a commit from a branch to merge into master
git reset --merge
abort a cherry pick (i.e. too much manual conflict resolution required)
squashing commits locally is safe squashing commits after pushing to remote is DANGEROUS since it involves rebase IF anyone else has pulled (which in a large enough team definitely happens) - master is just a branch so two people on the same branch = no rebase!
git log
commit afd3be516abf90e3d22c26fa01a560ae70510247
Author: John Pfeiffer <user@example.com>
Date: Thu Aug 29 09:22:46 2013 -0700
remove the old commented line
commit 08b93ed3ccc6496fd0e2bc0ce0fbff8c637cb72b
Author: John Pfeiffer <user@example.com>
Date: Thu Aug 29 09:16:19 2013 -0700
modify name to more descriptive cdn_prefix
commit 766674af64c41d72a4430b228802d0c45e20f0bf
Author: John Pfeiffer <user@example.com>
Date: Thu Aug 29 09:14:28 2013 -0700
add https prefix to cdn config
git rebase -i HEAD~3
CHANGE FROM pick pick pick
TO pick squash squash
:x (save and exit)
This is a combination of 3 commits. The first commit's message is:
add https prefix to cdn config, modify variable name to more descriptive cdn_prefix, remove the old commented line
git log # verify the new squashed commit
git push -f # force the push , similar to git push origin +master
Git Logs and Stats
git help
git status
git whatchanged --all --committer="pfeiffer@"
list all entries by a specific string in committer https://git-scm.com/docs/git-log
git shortlog -s -n
a sorted list of the number of commits by each "author" (so if you commit with different names it will be split) https://git-scm.com/docs/git-shortlog
git log --author="John"
git log --after="2014-7-1" --before="2014-7-4"
git log -p -2
diff of the last two commits
git log --stat
commit history (reverse chronological order)
git show <hash of some commit>
e.g. de3513f4f740934d0a97da8c97a58b35968b03ac , this will show you the actual diff
git log -- filename.txt
see the history for a single file
git log --pretty=oneline # shows commits on one line each
git log --pretty=format:"%h - %an, %ar : %s"
git reflog # shows when tip of branches are updated
https://www.atlassian.com/git/tutorials/git-log/filtering-the-commit-history
gitk # GUI for git commit history
git blame setup_s3.sh # shows the last commit each line was modified, e.g. 6d4134f4...
git blame -L8,+3 "6d4134f4^" -- setup_s3.sh # check Line 8 (the 3 lines around it) but starting FROM 6d4134f4...
continue until you've tracked it down
git whatchanged --stat # slightly different way of viewing most recent commits
git whatchanged since until -- filename.txt
git diff new-branch-name # all of the changes
git diff --name-status new-branch-name #just the file names
M folder/filename.py
git diff new-branch-name folder/filename.py # just the one file
GIT_PAGER='' git diff
allows line wrapping
git diff Example.java
shows the changes between the local file and the committed repo file
git blame Example.java
shows who last modified each line of code (not including deletions)
git add *.java
git commit -m "initialize repo"
git status
git ls-files
git ls-files file_name --error-unmatch
git ls-files | wc -l
git ls-tree -r --name-only HEAD
git ls-tree -r --name-only MASTER | wc -l
Merge a repository into another and maintain file history
git clone A
git clone B
cd A
git config --list
cd ../B
git config --list
git remote add git@bitbucket.org:USERNAME/A.git
git config --list
git fetch A
git merge A/master # or whichever branch you prefer
git remote remove A
Import a history from one repo to another
git remote add other /path/to/XXX
git fetch other
git checkout -b ZZZ other/master
mkdir ZZZ
git mv stuff ZZZ/stuff # as necessary
git commit -m "Moved stuff to ZZZ"
git checkout master
git merge ZZZ # should add ZZZ/ to master
git commit -m "merging in other repo history"
git push
git branch -D ZZZ # to get rid of the extra branch before pushing
Forking a subset of a repository
REMOVE ANY REFERENCE TO THE ORIGINAL REMOTE REPOSITORY SERVER
git config --list
git remote rm origin
REMOVE ALL TAGS (because often they are abused and useless)
git tag | xargs git tag -d
KEEP ONLY N DIRECTORIES FROM AN EXISTING REPO
git filter-branch --index-filter 'git rm --cached -qr -- . && git reset -q $GIT_COMMIT -- first/directory second/directroy' --prune-empty -- --all
CLEAN UP ALL OLD ARTIFACTS FROM GIT HISTORY
git reset --hard
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
git reflog expire --expire=now --all
git gc --aggressive --prune=now
CONFIGURE THE PRUNED/REFACTORED REPOSITORY TO BE A NEW REMOTE REPOSITORY
git remote add origin git@bitbucket.org:myproject/myreponame.git
git config --list
SEND YOUR NEW
git push --set-upstream origin master
Install Git on Ubuntu
sudo apt-get install git-core
which git
/usr/bin/git
git --version
Git from source
wget http://kernel.org/pub/software/scm/git/git-1.7.2.3.tar.gz
tar -xvf git-1.7.2.3.tar.gz
cd git-1.7.2.3/
sudo apt-get install libcurl4-gnutls-dev libexpat1-dev gettext libz-dev libssl-dev
make prefix=/usr/local all
sudo make prefix=/usr/local install
which git
/usr/local/bin/git
Git from git
git clone git://git.kernel.org/pub/scm/git/git.git # GIT FROM GIT
cd git
git tag
v1.7.2.3
v1.7.3-rc0
v1.7.3-rc1
v1.7.3-rc2
git checkout v1.7.3-rc2
make prefix=/usr/local all
sudo make prefix=/usr/local install
which git
/usr/local/bin/git
SETUP GIT ON A LOCAL MACHINE
sudo apt-get install git
git config --global color.ui true
git config --global user.name "John Pfeiffer"
git config --global user.email "jpfeiffer@example.com"
git config --list
git config user.email "another@example.com"
a config, i.e. email, can be set per repository too
git config user.email
another@example.com displays the current configuration
git config -e
edit the config file (same as vi .git/config)
ssh -T git@bitbucket.org # verify git can connect with an ssh key, if not make sure it is created and
ssh-keygen -f ~/.ssh/identity_name -C "identity_name" # creates identity_name and identity_name.pub (the second is for github/bitbucket)
# your fingerprint is: ...
# The key's randomart image is:
# +--[ RSA 2048]----+
vi /home/ubuntu/.ssh/config # Port allows for a non standard port
Host remoteserver.net
HostName remoteserver.net
PreferredAuthentications publickey # this will prompt the first time to add the remote host
Port 22
User git
IdentityFile ~/.ssh/github_rsa
# ensure the key is added with ssh-add -l (should display 2048 8a:1a:ac:6... identity_name (RSA) )
# when connecting troubleshoot using ssh -vT git@github.com (or ssh -vT username@bitbucket.org)
~/.ssh is where you keep your ssh keys
ssh-add -l
list what the ssh agent knows about
ssh-add -D
delete all the current identities
vi ~/.ssh/config
IdentityFile ~/.ssh/id_rsa
Host my.example.com
ForwardAgent yes
do not forward your agent to everyone as every server you log into might be able to leverage your session while you're logged in
ssh-add ~/.ssh/id_rsa
vi ~/.ssh/config
# ensure ~/.ssh/config contains the following, allows the target server (jumpbox) to re-use ssh-agent (/bin/sh ssh-add)
IdentityFile ~/.ssh/id_rsa
Host first.gitserver.com
HostName first.gitserver.com
User git
IdentityFile ~/.ssh/id_rsa_privateserve
ForwardAgent yes
Host github.com-personal
HostName github.com
User git
IdentityFile ~/.ssh/github_rsa
git clone git@bitbucket.org:username/reponame
requires ssh-agent, ssh-add and your ssh keys all correctly configured
git clone https://username@bitbucket.org/username/reponame.git
prompted for username and password unless it's a public repo
FIX GIT PROMPTING FOR PASSWORD (USE SSH INSTEAD OF HTTPS)
git config -l # list the configs, note:
remote.origin.url=https://foupfeiffer@bitbucket.org/foupfeiffer/xmpp.git
CHANGE PROTOCOL
git config --unset remote.origin.url git config --add remote.origin.url git@bitbucket.org:foupfeiffer/xmpp.git
git config --add remote.origin.url https://foupfeiffer@bitbucket.org/foupfeiffer/xmpp.git
ps -e | grep [s]sh-agent # if ssh-agent is not running: ssh-agent /bin/bash ssh-add -l # list the keys the agent is managing ssh-add ~/.ssh/id_rsa # may be password prompted
to ensure it's permanently added, vi ~/.ssh/config IdentityFile ~/.ssh/id_rsa
note that /etc/ssh/ssh_config would apply to all users on the system
make sure the ~/.ssh/id_rsa.pub key has been added to your remote repo (bitbucket)
Lubuntu and LXDE: vi /etc/xdg/autostart/gnome-keyring-pkcs11.desktop
Exec=/usr/bin/gnome-keyring-daemon --start --components=pkcs11 OnlyShowIn=GNOME;Unity;MATE;LXDE;XFCE;
vi /etc/xdg/autostart/gnome-keyring-ssh.desktop
Exec=/usr/bin/gnome-keyring-daemon --start --components=ssh OnlyShowIn=GNOME;Unity;MATE;LXDE;XFCE;
cd /home/ubuntu/myproject (download a base .gitignore for your language from github) git init git add .gitignore git commit -m "initial .gitignore" git remote add origin git@remoteserver.net:/home/git/GITREPOS/project.git git push origin master # Perhaps you should specify a branch such as 'master'
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 581 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
to fix error beginning: "You asked me to pull without telling me which branch you want to merge with, and 'branch.master.merge'"
git branch --set-upstream master origin/master
git pull --rebase # apparently rebase is cleaner than merge (which is pull's default) EXCEPT if someone depends on those commits
optionally investigate with
git remote show origin git remote -v
every commit is identified by a SHA (40 characters)
clone only a branch
git clone -b mybranch --single-branch git://user@bitbucket.org/user/myproject.git vi somefile git commit -a -m "somefile" git push origin mybranch # you MUST indicate what branch to update
probably better to just use git checkout or track but...
git pull git branch git checkout mybranch # Already on 'mybranch'
CLONE THE WHOLE REPO AND THEN SET IT TO A SPECIFIC COMMIT, DELETING A BRANCH, CREATING A NEW BRANCH
git clone https://user@bitbucket.org/project
git reset --hard 93b149c0bb0800e81467028f170a99adac587c82 ( a specific commit against master)
.gititgnore SAMPLES
!.java # The easy way (just java files)
The hard way... at the root of the git repo create a text file .gitignore
*.class
Package Files
.jar .war *.ear
maven build artifacts
target/
/target/
THE BEST WAY TO MERGE (when git pull gives you the unfortunate news...)
Updating 7052d46..9c531c7 error: Your local changes to the following files would be overwritten by merge: project/src/main/java/com/Example.java
Please, commit your changes or stash them before you can merge. Aborting
git stash # now your current local stuff is saved git pull # now your local repo reflects the remote git stash pop # auto merge your changes back into your local repo
Now look for any errors where a merge must be fixed/handled manually
to remove previous mistakes
git rm *.class -f
forces the removal, then do a git commit and push
OR
git stash
git reset --hard HEAD
REMOVING LOCAL COPIES BEFORE DOING A GIT PULL
1) git checkout -- .
checkout the latest version and overwrite old files not affect deleted, renamed, or new files
2a) git stash save --keep-index 2b) git stash drop
stash uncommitted files, then drops them entirely. Good if there are committed changes to keep and uncommitted/unstaged changes to discard
3)git reset --hard
Wipes out everything since the last commit, including file renames, deletions, and additions
4) git clean ?
git mv is merely a convenience method. git does not "track" renames (that is, it can detect them, but they are not recorded as an operation like an add or remove)
instead just use "git add" and "git rm" (and git log --follow if you want to see history)
CREATE, INITIALIZE, AND PUSH TO ORIGIN MASTER A NEW REPO
mkdir /workspace/TEMP (master) cd /workspace/TEMP git init touch empty-file-initialize-repo.txt git add empty-file-initialize-repo.txt git commit -m "empty-file-initialize-repo" [master (root-commit) 0df7d96] starting the repo 0 files changed create mode 100644 temp.txt
git remote add origin git@server.com:projectname-common.git git push origin master Initialized empty Git repository in /ebs/data/gitosis/projectname-common.git/ Counting objects: 3, done. Writing objects: 100% (3/3), 224 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To git@server.com:projectname-common.git * [new branch] master -> master
//NOW THE "MAIN" server has the new repo
cd /workspace
git clone git@server.com:projectname-common.git Cloning into 'projectname-common'... Receiving objects: 100% (3/3), done. remote: Counting objects: 3, done. remote: Total 3 (delta 0), reused 0 (delta 0)
//CLEANUP THE TEMPORARY BOOTSTRAP REPO rm -rf /workspace/TEMP
SETUP GIT: REMOTE SERVER ssh ubuntu@remoteserver.net
apt-get update apt-get install git-core
sudo adduser git su git cd ~ mkdir .ssh
mkdir -p /home/ubuntu/.ssh/
vi /home/ubuntu/.ssh/authorized_keys
cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys cat /tmp/id_rsa.john_github.pub >> ~/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAtl0zMQSXCVUg4kNZV3LtlyLBaUg9fTtDybzq3YTYxuzR4ZO+JlAFj1bLobdh2/6zgfe5cd9mDdWCAJXif7aaYRHqUBej4TTbdvWoCednjhaB4V06ddkof+3SuZKDt5/lYNAcEidzj+sLkEmDsaH126AZIe93btYq/lraDxfdlUr3m1Q2WaqzNeoPmvZW8o/VdrYlR8hWEETZ4Bg+8ZSpuqKO7nWU1q82w== John@HPDV7
chown git:git ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys
cd /opt/git mkdir project.git cd project.git git --bare init
MORE INFO: git-shell to restrict users shell access
PREREQUISITE
Window -> Preferences -> General -> Network Connections -> SSH2
Key Management (tab) -> Generate RSA Key
"You can paste this public key into the remote authorized_keys file"
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCBOKhzHKQMdxZxf5d4qpazvt/CGxERmRain0c7rLJBYI4wcVk0nUpKFH/d3Tj9L1f+CjsScHXBK9LI77YAlYOVX9gfEZskwEdJats1Cup7VN4NLbzlxP0gGB9HTf1B+ZKC8VRG+Z8DxAok70IESpWV9RKLehHlpQsEieitq7zyaw== RSA-1024
Save Private Key! (e.g. becomes ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub)
GIT REPO SIZE MANAGEMENT
git verify-pack -v .git/objects/pack/pack-*.idx | sort -k 3 -n | tail -5
git rev-list --objects --all | grep
UNFORTUNATELY permanently removing commits (and then the objects) from the history (and pack) is very difficult
Submodules: http://git-scm.com/book/en/Git-Tools-Submodules
after a clone (recursive) the submodule will appear under a directory submodules, also at the top level there will be .gitmodules
git clone --recursive git@bitbucket.org:myuser/myproject.git
if there is a change upstream to the submodule git status will show "changes not staged for commit"
cd myrepo
git pull
cd myrepo/submodule/foo
git pull
cd myrepo
git submodule update Submodule path 'submodules/myupstreamproject': checked out '84518ee287ee1eb1a40210d339665a85a02461e6'
after a "git pull" on the main repo you must also run a "git submodule update" (to get changes made to the submodule upstream)
IF you have a branch you have to do the same thing twice (once on master and once on the branch) SO AVOID having multiple branches in a submodule
IF you have accidentally modified your submodule directly it's highly recommended to "git checkout -- submodule" (i.e. use a two lane road, modify your upstream projects directly and just use git submodule update to pull down new changes)
IF you're unable to see the changes to submodule:
cd myrepo/symlink-to-submodule-subdir git branch git checkout master git pull cd myrepo git submodule update