Last active
December 18, 2015 12:39
-
-
Save patriques82/5783846 to your computer and use it in GitHub Desktop.
Git workflow and a summary of how git works
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
GIT internals and workflows | |
Contents | |
THEORY AND SETUP | |
Installing and Configuration | |
Intializing | |
Object types and References | |
Remotes | |
How it works | |
.gitignore file | |
BASICS | |
Adding and Committing | |
Log and Status | |
Resetting, reverting, removing and renaming | |
Simple workflow (example) | |
BRANCHES | |
Branching | |
Undoing changes workflow (example) | |
Merging | |
Stashing | |
Conflicts | |
Fast-Forward merges | |
Solving conflicts (example) | |
Remote Branches | |
Cloning a remote repo | |
Creating a Github repo | |
Fetching, pulling and pushing | |
Working with multiple remotes | |
Rebasing (special) | |
GOODIES | |
THEORY AND SETUP | |
Installing and Configuration | |
To install simply run the command (debian based distro) | |
apt-get install git | |
or (if fedora based distro) | |
yum install git | |
Your configurations will first be loaded from | |
1. .git/config | |
and it keeps your project specific Git options, such as your remotes, push configurations, tracking | |
branches and more. Secondly it will be | |
loaded from your user specific Git options that are located in your | |
2. ~/.gitconfig | |
file in your user directory and thirdly from a system specific Git options located in a | |
3. /etc/gitconfig | |
file in your rootdirectory, if they exist. | |
To see git configurations | |
$ git config --list¨ | |
There is two additional flags for the config settings --system and --global that are specific for | |
the system respectively for the user. | |
To change any of the configurations, to change the name and email for example | |
$ git config --global user.name "John Doe" | |
$ git config --global user.email "[email protected]" | |
This configuration is a necessary step when having Git installed. This information is used to give | |
you credits when committing to a shared repository. | |
To have nice coloring ui on the command line | |
$ git config --global color.ui true | |
Initializing | |
For starting a git repo cd to the root of project directory and: | |
$ git init | |
This creates a git repo and starts tracking all the files in the folder. This command creates | |
a hidden Git Directory in your project with this structure: | |
.git | |
|-- branches | |
|-- COMMIT_EDITMSG | |
|-- config | |
|-- description | |
|-- FETCH_HEAD | |
|-- HEAD | |
|-- hooks | |
| |-- post-commit | |
| |-- pre-commit | |
|-- index | |
|-- info | |
|-- logs | |
| `--- HEAD | |
| |-- refs | |
| | |-- heads | |
| | `--- master | |
| | |-- remotes | |
| | |-- origin | |
|-- objects | |
| |-- 05 | |
| | `-- 76fac355dd17e39fd2671b010e36299f713b4d | |
| |-- 0c | |
| | `-- 819c497e4eca8e08422e61adec781cc91d125d | |
| |-- 1a | |
| | `-- 738da87a85f2b1c49c1421041cf41d1d90d434 | |
| |-- 47 | |
| | `-- c6340d6459e05787f644c2447d2595f5d3a54b | |
| |-- 99 | |
| | `-- f1a6d12cb4b6f19c8655fca46c3ecf317074e0 | |
| |-- a0 | |
| | `-- a60ae62dd2244a68d78151331067c5fb5d6b3e | |
| |-- a1 | |
| | `-- 1bef06a3f659402fe7563abf99ad00de2209e6 | |
| |-- a8 | |
| | `-- 74b732e12a5c04b5a73d7f1123c249997b0b2d | |
| |-- a9 | |
| | `-- 06cb2a4a904a152e80877d4088654daad0c859 | |
| |-- e1 | |
| | `-- b3ececb0cbaf2320ca3eebb8aa2beb1bb45c66 | |
| |-- fe | |
| | `-- 897108953cc224f417551031beacc396b11fb0 | |
| |-- info | |
| `-- pac | |
|-- ORIG_HEAD | |
|-- packed-refs | |
`-- refs | |
|-- heads | |
| `--- master | |
|-- remotes | |
| |-- origin | |
| `---HEAD | |
| `---master | |
|-- tags | |
`---v0.1 | |
(this structure is actually from a older git repo. As you can see there are objects already in the | |
folder. This is to show the idea behind the structure.) | |
Object types and References | |
Git objects are the actual data of Git, the main thing that the repository is made up of. | |
There are four main object types in Git (Blobs, Trees, Commits, and Tags). | |
1. Blob: The content of files in Git are stored in Blobs, these blobs are listed in Trees that | |
correspond to directories. | |
2. Tree: Treeobject looks more like a list than a Tree. The list contains entries with mode, type, | |
name and SHA-1 value, the mapping of name and SHA is especially important. | |
3. Commit: The Commit is the history milestone of the development process, while Blobs and Trees | |
addresses content of the project, the commit addresses the state of the project in a | |
specific time and simply points to a tree, with a message, author and any parent that | |
preceded it. | |
4. Tag: The Tag provides a permanent shorthand name for a particular commit. It contains an object, | |
type, tag, tagger and a message. | |
All of these types of objects are stored in the Git Object Database, which is kept in the Git | |
Directory (see the Git Directory structure above). Each object is compressed with Zlib and is | |
referenced with its SHA-1 value that is 40 characters long. | |
In addition to the Git objects, which are immutable – that is, they cannot ever be changed, there | |
are references also stored in Git. Unlike the objects, references can constantly change. They are | |
simple pointers to a particular commit. Examples of references are branches and remotes. A branch | |
in Git is nothing more than a file in the .git/refs/heads/ directory that contains the SHA-1 of the | |
most recent commit of that branch. To branch that line of development, all Git does is create a new | |
file in that directory that points to the same SHA-1. As you continue to commit, one of the | |
branches will keep changing to point to the new commit SHA-1s, while the other one can stay where | |
it was. The HEAD file in the Git directory keeps track of what branch you are currently on. | |
Remotes | |
A remote is basically a pointer to a shared branch, often copied from another computer, this means a | |
repo was not initialized but cloned. (To read more about remotes see Remote Branches) | |
How it works | |
The Git object data is a directed acyclic graph. That is, starting at any commit you can traverse | |
its parents in one direction and there is no chain that begins and ends with the same object. | |
If you have a directory under versionconrol under git and the file structure looks like this: | |
|-- .git (this is a hidden directory, created when initializing the git repo (see below)) | |
|-- init.rb | |
`-- lib | |
|-- base | |
`-- base_include.rb | |
` -- my_plugin.rb | |
Then the Git data model will look something like this: | |
HEAD | |
| | |
Remote BRANCH Tag | |
\ | / | |
COMMIT | |
| | |
Tree | |
/ \ | |
Blob Tree | |
/ \ | |
Tree Blob | |
| | |
Blob | |
We have three trees, three blobs and a single commit that points to the top of the tree. | |
The current branch points to the last commit and the HEAD file points to the branch you’re | |
currently on. This lets Git know which commit will be the parent for the next commit. | |
This way the branch keeps track of the commits being done during its lifetime and what | |
changes has been done since the last commit. The blobs are just compressed content, and when | |
a file is not changed from a commit to another the new commit continues referencing the last | |
commits reference to the blob, or filecontent. Its just when changes occur in a file that a | |
new blob is created in the git repo. | |
So, what do all the arrows in these illustrations really mean? How does Git actually retrieve | |
these objects in practice? Well, it gets the initial SHA-1 of the starting commit object by | |
looking in the .git/refs directory for the branch, tag or remote you specify. Then it | |
traverses the objects by walking the trees one by one, checking out the blobs individually. | |
(I made the 40 characters of the SHA-1 name 7 chars for simplicity) | |
1. $ git checkout v0.1 | |
2. .git/refs/tags/v0.1 ---> 74bt36h (Tag) | |
3. tag: 74bt36h ---> 653dhh7 (Commit) | |
4. Commit: 653dhh7 ---> 7hhcs69 (Tree) | |
5. Tree: 7hhcs69 ---> 7hfqvt8 (a Blob), u76bvc9 (and a Tree) | |
.gitignore file | |
If you have files you dont want to track you can simply add them to a .gitignore file in the | |
root of the project dir Example of a .gitignore file for a rails project on a mac: | |
# Ignore bundler config | |
/.bundle | |
# Ignore the default SQLite database. | |
/db/*.sqlite3 | |
# Ignore all logfiles and tempfiles. | |
/log/*.log | |
/tmp | |
# Ignore other unneeded files. | |
doc/ | |
*.swp | |
*~ | |
.project | |
.DS_Store | |
BASICS | |
Adding and Committing | |
Git has two places that content states are stored. The working directory stores one state at a | |
time in a human-editable format. In this state though nothing is permanent to git since when in | |
this state the project is at work. When committed, that state becomes permanent and repeatable by | |
being stored in the object database. However, how do you determine what changes in your working | |
directory will go into your next commit? Perhaps you have edited three files and you want two to | |
go into the first commit (because they are related changes) and the other file into a second | |
commit. This is where the index file comes in. | |
The Index is a staging area for changes that are made to files or trees that are not committed to | |
your repository yet. It acts as sort of a middle ground between your working directory and your | |
repository. The Index keeps track of the state of all the files in your working directory so you | |
can quickly see what has been modified since the last commit. The resulting tree and commit | |
object will be built based on the contents of the Index. | |
For simplicity you can see the Commit as a camera taking snapshot of your working directroy, and | |
where you choose what files on your project that needs to be snapshot by adding them to the | |
Index or staging area. | |
Working directory ---> Staging area (new/modified files) ---> Object Database (repo) | |
Adding to staging area | |
To stage all modified and new files (but not deleted) to the staging area or Index | |
$ git add . | |
To stage all modified and deleted files (but not new, i.e only tracked files) | |
$ git add -u | |
To stage All files (same as doing both git add . and git add -u) | |
$ git add -A | |
To add specific file or folder or both | |
$ git add folder/* file.txt | |
Committing to repository | |
$ git commit -m "First commit, this commit becomes HEAD and the parent commit of all other | |
commits" | |
To both add and commit (only changes to tracked files) | |
$ git commit -am "The description of changes you made" | |
You should commit every time you make a change in the project and generally its good to | |
commit when you can name that change, for example when some changes to a class are made that | |
makes it behave a certain way. This way everytime you feel you want to go back or forward | |
between commits you can do so, and when you feel you want to change the current branch you | |
push the HEAD commit (the latest commit). | |
Log and Status | |
To show a log of all commits starting from HEAD back to the initial parent commit (there is | |
more... --help). | |
$ git log | |
To quit the log type "q". | |
To show which files have changed between the current project state and HEAD (new, modified, | |
and added files to be committed). | |
$ git status | |
To get a shorter summary | |
$ git status -s | |
There are ways to limit and format this output differently. —pretty is a useful option for | |
formatting the output in different ways. For example, we can list the commit SHA-1s and the first | |
line of the message with —pretty=oneline: | |
$ git log --pretty=oneline | |
Output: | |
cf25cc3bfb0ece7dc3609b8dc0c committing all changes | |
0c8a9ec46029a4e92a428cb98c9 changed the verison number | |
0576fac355dd17e39fd2671b010 my second commit, which is.. | |
a11bef06a3f659402fe7563abf9 first commit | |
With —pretty, you can choose between oneline, short, medium, full, fuller, email, raw | |
To see a summary of all commits | |
$ git log --stat | |
To show the diff between HEAD and the current project state. | |
$ git diff HEAD^ | |
Or for only one or more files (only files not added to staging area) | |
$ git diff HEAD^ <file> | |
If you want to see what words have changed in the file | |
$ git diff HEAD^ <file> --word-diff | |
To compare added files in staging area against HEAD. | |
$ git diff HEAD^ --cached | |
If you don't want the full diff output, but more than the git status output. | |
$ git diff HEAD^ --stat | |
Or | |
$ git diff HEAD^ --cached --stat | |
Resetting, removing and renaming | |
To undo the last commit, unstage files | |
$ git reset HEAD | |
or a specific file | |
$ git reset HEAD <filename> | |
To unstage files from staging area (but actually undos the last commit for the file which is | |
the same thing) | |
$ git reset HEAD -- <file> | |
To undo the last commit but leaving changed files added to staging area | |
$ git reset --soft HEAD~ | |
To undo the last commit, unstage files AND undo any changes in the working directory | |
(dangerous, Uh-oh!) | |
$ git reset --hard | |
If you try a merge with a old branch that is so old that it will be impossible to resolve all | |
conflicts you probably want tu undo the merge. To reset your working directory and index back to | |
what it was before you tried the merge, simply run: | |
$ git reset --hard HEAD | |
The —hard makes sure both your index file and working directory are changed to match what it used | |
to be. By default it will only reset your index, leaving the partially merged files in your | |
working directory. | |
Sometimes instead of removing the commit from the project history, you want only to undo the | |
changes introduced by the commit. In those cases you can use the revert command. This command does | |
not take away the commit but only the actual modifications to the files. This could be handy for | |
when you want see when a bug was introduced into the codebase by trying to revert certain commits. | |
$ git revert <commit> | |
This creates a new commit that has deleted the content introduced by the commit. Therefore you can | |
safely continue reverting more and more commits until you have found the bug, then you can undo | |
these bugtracking commits if you want. In comparison to reset, revert lets you target a single | |
commit, while reset forces you to remove all the commits after the reset commit. Therefore to get | |
the same effect, you will need to recommit the subsequent commits after the reset commit. | |
To simply remove entries from the staging area and from your harddrive (means also deleting | |
files) | |
$ git rm | |
Or | |
$ git rm <file> | |
To remove only from staging area | |
$ git rm --cached <file> | |
This could be a better alternative in a collaborative environment. | |
$ git update-index --assume-unchanged <file> | |
To rename a file | |
$ git mv <old-file-name> <new-file-name> | |
Simple workflow example: | |
1. Do some programming | |
2. git status to see what files changed. | |
3. git diff <file> to see exactly what was modified. | |
4. git commit -am [message] to commit. | |
BRANCHES | |
The terms “branch” and “head” are nearly synonymous in Git. Every branch is represented by | |
one head, and every head represents one branch. A head is simply a reference to a commit | |
object. Each head has a name. By default, there is a head in every repository called master. | |
HEAD on the other side is a pointer to the local branch you’re currently on. In this case, | |
we’re still on master branch. | |
(A) -- (B) -- (C) (commits) | |
| | |
master (head) | |
| | |
HEAD (pointer) | |
Branching | |
To create a new branch for example | |
$ git branch <new-head-name> | |
(A) -- (B) ------- (C) | |
/ \ | |
master new-head-name | |
| | |
HEAD | |
Or to create a branch from other commit | |
$ git branch <new-head-name> <reference-to-(B)> | |
Because HEAD^ means the parent of the HEAD commit you could also write this to have the same | |
result | |
$ git branch <new-head-name> HEAD^ | |
(A) -- (B) ------- (C) | |
| | | |
new-head-name master | |
| | |
HEAD | |
To see all current branches | |
$ git branch | |
To switch between branches | |
$ git checkout <new-head-name> | |
This effectively rewrites all the files in the directory to match the files stored in the new | |
HEAD commit. Before that it goes through the Index file so the procedure is like a reversed | |
commit. Before doing this make sure you have committed your last changes on the last | |
change, becouse if not, git will behave strangely (Uh-oh!). | |
If you check out a different branch, git will make your working directory look like that branch, | |
removing any checked in content that is currently in your working directory that is not in the new | |
tree. This is why git will only let you checkout another branch if everything is checked in – there | |
are no uncommitted modified files. The reason for this is that git will remove files that are not | |
necessary in the branch you are checking out – it needs to make sure that you can get them back | |
again. | |
(A) -- (B) ------- (C) | |
| | | |
new-head-name master | |
| | |
HEAD | |
If you make new changes on branch (B) and commit these changes the new tree will look like | |
this, so as you see the head-name is not a name attached to the commit but to the current | |
branch. | |
+ -------------(D) | |
/ | | |
(A) -- (B) -- (C) | | |
| | | |
master new-head-name | |
| | |
HEAD | |
To create and switch to branch in one command | |
$ git checkout -b emergency-branch | |
Undoing changes | |
An example: | |
0. Some commits from before. | |
1. Do some mistaken programming without staging any files. | |
2. git status to see what files changed. | |
3. git checkout -f to return to force overwriting the current changes and returning to last | |
commit | |
If you want to temporarily go back to a commit, fool around, then come back to where you are | |
$ git checkout 0d1d7fc32 | |
If you want to make commits while you're there, go ahead and make a new branch | |
$ git checkout -b old-state 0d1d7fc32 | |
If, on the other hand, you want to really get rid of everything you've done since then | |
$ git reset --hard 0d1d7fc32 | |
If you regret your last commit, forgot to add a file or simply want to rename the commit run | |
$ git commit -m 'initial commit' | |
$ git add forgotten_file | |
$ git commit --amend (this fires up your editor to pass a new message) | |
After these three commands, you end up with a single commit — the second commit replaces the | |
results of the first. | |
If you want to undo something else run the 'status' command and it will tell you what you need | |
$ git status | |
(Output) | |
# On branch master | |
# | |
# Changes not staged for commit: | |
# (use "git add <file>..." to update what will be committed) | |
# (use "git checkout -- <file>..." to discard changes in working directory) | |
# | |
# modified: a_new_file_to_commit.txt | |
# | |
# Untracked files: | |
# (use "git add <file>..." to include in what will be committed) | |
# | |
# log/log_file.txt | |
If you have committed already and forgot to add something small to that commit you can use | |
$ git commit --amend | |
This way you don´t need to have horrible commit messages with text like "changed class name" | |
or something unnecessary like that. | |
Merging | |
After you have finished implementing a new feature on a branch to merge it with the master | |
branch | |
$ git merge <new-head-name> | |
Before doing this you should have moved your HEAD pointer to the master branch or whatever | |
branch you want to merge the features into | |
+---------- (D) | |
/ | | |
(A) -- (B) -- (C) -------------- (E) | |
| | | |
new-head-name master | |
| | |
HEAD | |
After the merge the new tree will look like this | |
+---------- (D) -------------+ | |
/ | \ | |
(A) -- (B) -- (C) -------------- (E) -- (F) | |
| | | |
new-head-name master | |
| | |
HEAD | |
To delete a branch after you have merged the branch | |
$ git branch -d new-head-name | |
To delete a branch before merging it when you want to abandon it (make sure your on another | |
branch before) | |
$ git branch -D new-head-name | |
Stashing | |
If you are working on your code and you need to switch to another branch for some reason and don’t | |
want to commit your current state because it is only partially completed, you can run: | |
$ git stash | |
It will basically take the changes from your last commit to the current state of your working | |
directory and store it temporarily. And now your working directory is clean as if you had | |
committed. If you made many stashes on many branches you can see them by running: | |
$ git stash list¨ | |
(Output) | |
stash@{0}: WIP on experiment: 89e6d12... trying a experiment | |
stash@{1}: WIP on master: c110d7f... added some new content on something | |
stash@{2}: WIP on master: c110d7f... added some new content on something | |
Here you can see you have two stashes on the ‘master’ branch, both saved off of working from the | |
same commit, and you have one stashed change off the ‘experiment’ branch. If you still dont | |
remember what files on the master branch you need to unstash to keep working, run: | |
$ git stash show stash@{0} | |
(Output) | |
lib/simplegit.rb | 4 ++++ | |
1 files changed, 4 insertions(+), 0 deletions(-) | |
Yes, this was the one! You can also if it still unclear use any normal git tools that will take a | |
tree on it, for instance, ‘git diff’: | |
$ git diff stash@{0} | |
If you now know what stash you want to continue on for example: | |
stash@{0}: WIP on experiment: 89e6d12... trying a experiment | |
Then just switch to the experiment branch and apply the stash by running: | |
$ git stash apply stash@{0} | |
(Output) | |
# On branch master | |
# Changed but not updated: | |
# (use “git add <file>...” to update what will be committed) | |
# | |
# modified: lib/simplegit.rb | |
# | |
no changes added to commit (use “git add” and/or “git commit -a”) | |
Now we can see that our working directory is back to where it was, with one file in an unstaged | |
state. | |
Conflicts | |
To resolve the commit, edit the files to fix the conflicting changes. Then run git add to add | |
the resolved files, and run git commit to commit the repaired merge. Git remembers that you | |
were in the middle of a merge, so it sets the parents of the commit correctly. To avoid | |
conflicts you can use fast-forward merges. | |
Fast-Forward Merges | |
If your state looks like the following | |
+-- (D) -- (E) | |
/ | | |
(A) -- (B) -- (C) | | |
| | | |
current to-merge | |
| | |
HEAD | |
Then you can easely merge your branches and actually not a merge as HEAD will only change | |
pointer to the <to-merge> head | |
Solving conflicts | |
If you want to see which files are unmerged at any point after a merge conflict, you can run | |
$ git status | |
index.html: needs merge # For example | |
Anything that has merge conflicts and hasn’t been resolved is listed as unmerged. Git adds | |
standard conflict-resolution markers to the files that have conflicts, so you can open them | |
manually and resolve those conflicts. Your file contains a section that looks something like | |
this: | |
<<<<<<< HEAD:index.html | |
<div id="footer">contact : [email protected]</div> | |
======= | |
<div id="footer"> | |
please contact us at [email protected] | |
</div> | |
>>>>>>> iss53:index.html | |
This means the version in HEAD (your master branch, what you had checked out fore merging) | |
is the top part of that block (everything above the =======), while the version in your | |
iss53 branch looks like everything in the bottom part. In order to resolve the conflict, you | |
have to either choose one side or the other. For example by replacing the entire block with | |
this: | |
<div id="footer"> | |
please contact us at [email protected] | |
</div> | |
After you’ve resolved each of these sections in each conflicted file, run git add on each | |
file to mark it as resolved. Staging the file marks it as resolved in Git. | |
Remote Branches | |
A Remote is a repository stored on another computer. Remote branches are references to the | |
state of branches on your remote repositories. Remote branches act as bookmarks to remind you | |
where the branches on your remote repositories were the last time you connected to them. They | |
take the form (remote)/(branch). For instance, if you wanted to see what the master branch on | |
your origin remote looked like as of the last time you communicated with it, you would check | |
the origin/master branch. | |
If you were working on an issue with a partner and they pushed up an iss53 branch, you might | |
have your own local iss53 branch; but the branch on the server would point to the commit at | |
origin/iss53. | |
Cloning a remote repo | |
Let’s say you have a Git server on your network at git.ourcompany.com. If you clone from | |
this, Git automatically names it origin for you, pulls down all its data, creates a pointer | |
to where its master branch is, and names it origin/master locally; and you can’t move it. | |
Git also gives you your own master branch starting at the same place as origin’s master | |
branch, so you have something to work from. | |
git.ourcompany.com | |
(A) -- (B) -- (C) (commits) | |
| | |
master (remote branch) | |
$ git clone [email protected]:project.git | |
your computer | |
master (head) | |
| | |
(A) -- (B) -- (C) (commits) | |
| | |
origin/master | |
Now enter the project | |
$ cd ticgit | |
When a repository is cloned, it has a default remote called origin that points to the cloned | |
repo and to contrinute to the remote repo simply | |
$ git commit -a | |
$ git push | |
Creating a Github repo | |
First you create a repo in Github according to their instructions. Take care not to | |
initialize the repository with a README. Then push up your local project with initialized | |
local git repository | |
$ cd /path/to/project | |
touch README.md | |
git init | |
git add README.md | |
git commit -m "first commit" | |
git remote add origin https://github.com/githubname/reponame.git | |
git push -u origin master | |
git remote add origin tells that the original remote repository is on the url | |
https://github.com/githubname/reponame.git. | |
-u is a upstream which means that you are telling git that the current branch is tracking | |
the master branch on the remote repository origin, from where you pull from and push to. You | |
need only specify it once. Next time you pull or push it will know what branch on what | |
remote repo you are talking about. | |
To list all the shortnames of each remote handle you’ve specified. If you’ve cloned your repository, you should at least see | |
origin — that is the default name Git gives to the server you cloned from | |
$ git remote | |
origin | |
Now if someone pushes to the master branch on remote repository, and you make changes to your | |
local repository the tree should look like this | |
git.ourcompany.com | |
(A) -- (B) -- (C) -- (D) -- (E) (commits) | |
| | |
master (remote branch) | |
your computer | |
master (head) | |
| | |
(A) -- (B) -- (C) -- (F) -- (G) (commits) | |
| | |
origin/master | |
Suppose we fetch from the repository that we originally cloned from and they had been doing some | |
work. They have now committed a few times on their master branch, but they also branched off at one | |
point to try an idea, and they named the branch idea locally, then pushed that branch. We now have | |
access to those changes as origin/idea. | |
Fetching, pulling and pushing | |
To synchronize your work | |
$ git fetch origin | |
Now your local database and moves the origin/master pointer to the more up-to-date position | |
your computer | |
master (head) | |
| | |
(F) -- (G) | |
/ | |
(A) -- (B) -- (C) | |
\ | |
(D) -- (E) | |
| | |
origin/master (up-to-date!) | |
If you want to merge the files you can now do it | |
$ git merge origin/master | |
To fetch and merging in one step you can instead do | |
$ git pull origin | |
your computer | |
(F) -- (G) | |
/ \ | |
(A) -- (B) -- (C) (H) - (new head) | |
\ / | |
(D) -- (E) | |
| | |
origin/master (up-to-date!) | |
In Git the opposite of ‘push’ is not ‘pull’, but ‘fetch’. A ‘pull’ is a ‘fetch’ and then a | |
‘merge’. | |
When instead you want to share your changes with the collaborators you run the command | |
git push (remote) (branch): | |
$ git push origin <branch-name> | |
By default the pushed branch is the HEAD branch and the last commit in this branch. On most | |
systems you can omit origin master, if that is the branch you are pushing to | |
$ git push | |
if you’ve used a different name for your remote or you are trying to push one of your other | |
branches, you can do that, too. | |
$ git push my-public-server not-master-branch | |
To see all remote branches | |
$ git branch -r | |
Working with multiple remotes | |
Pushing to and pulling from multiple sources is easy and straightforward. You simply add remotes | |
$ git remote add mycap [email protected]:patriques/someproj.git | |
$ git remote add official git://github.com/otherdude/someproj.git | |
Then, if the the project is updated, I can pull in the changes from one remote, merge them | |
locally, and then push to another remote. | |
$ git fetch official | |
$ git merge official/master | |
$ git push mycap master | |
To view useful information about a remote branch | |
$ git remote show origin | |
You can also remove remotes at any time, which simply removes the lines that contain the URL in | |
your .git/config file and the references to their remote branches in | |
.git/refs/[remote_name] directory, but it will not remove any of the git objects. | |
Rebasing (Special) | |
Rebasing is especially good when the upstream branch has changed and you need your branch to | |
merge with the latest changed and works as an alternative to merging and requirs less | |
commands. If your repository looks like the following | |
+-------------- (D) | |
/ | | |
(A) -- (B) -- (C) | | |
| | | |
master new-branch | |
| | |
HEAD | |
you can rebase as an alternative to merging with | |
$ git rebase master | |
and your new repo will look like | |
+------ (E) | |
/ | | |
(A) -- (B) -- (C) | | |
| | | |
master new-branch | |
| | |
HEAD | |
GOODIES | |
To search for a commit with a certain searchword | |
$ git show :/<search term> | |
Statistics for all branches (nr of commits per user) | |
$ git shortlog -s -n --all | |
Statistics on total lines of code for secific author | |
$ git log --author="<authorname>" --oneline --shortstat | |
or more advanced | |
$ git log --author="Patrik Nygren" --pretty=tformat: --numstat | \ | |
awk '{ add += $1; subs += $2; loc += $1 - $2 } END \ | |
{ printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' - | |
If you want to switch to the branch you where currently on | |
$ git checkout - | |
In git it is very hard to delete content. It is often the case that it is | |
stashed away before its garbaged collected and you can still find content | |
like this. If you have deleted a branch or commit you can run | |
$ git fsck --lost-found | |
and then you can pull in the commit or branch after this. | |
If you want to see who did commit the Lines 40-60 in file foo.txt and when | |
they where committed you can use git blame. | |
$ git blame -L 40,60 foo.txt | |
If you are only interested in changed done to the file the last 3 weeks | |
$ git blame --since=3.weeks -- foo.txt | |
If you want a small summary of all people working on the git repo | |
$ git shortlog -sn | |
To learn about git, branches, commits and repositories in a conceptual way | |
Basics: http://gitref.org/basic/ (very good with examples, all in one file, long though, but still | |
One) | |
Videos: http://git-scm.com/videos | |
Thorough book: http://git-scm.com/book | |
All these sources have been used and I have simply summarized, and many time copy-pasted whats in | |
these sources. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment