Skip to content

Instantly share code, notes, and snippets.

@patriques82
Last active December 18, 2015 12:39
Show Gist options
  • Save patriques82/5783846 to your computer and use it in GitHub Desktop.
Save patriques82/5783846 to your computer and use it in GitHub Desktop.
Git workflow and a summary of how git works
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