Git Basics
Git Basics
GIT
THE BASICS
This courseware is both the product of the author and of freely available opensource and/or public
domain materials. Wherever external material has been shown, it's source and ownership have been
clearly attributed. We acknowledge all copyrights and trademarks of the respective owners.
The contents of the courseware PDFs are considered proprietary and thus cannot be copied or
reproduced in any form whatsoever without the explicit written consent of the author.
Only the programs - source code and binaries (where applicable) - that form part of this
courseware, and that are made available to the participant, are released under the terms of the
permissive MIT license.
Under the terms of the MIT License, you can certainly use the source code provided here; you must
just attribute the original source (author of this courseware and/or other copyright/trademark
holders).
VERY IMPORTANT :: Before using this source(s) in your project(s), you *MUST* check with your
organization's legal staff that it is appropriate to do so.
The courseware PDFs are *not* under the MIT License, they are to be kept confidential, non-
distributable without consent, for your private internal use only.
The duration, contents, content matter, programs, etc. contained in this courseware and companion
participant VM are subject to change at any point in time without prior notice to individual
participants.
Care has been taken in the preparation of this material, but there is no warranty, expressed or
implied of any kind, and we can assume no responsibility for any errors or omisions. No liability is
assumed for incidental or consequential damages in connection with or arising out of the use of the
information or programs contained herein.
Git – the SCM system created by Linus Torvalds – is of course the SCM used to track and manage
the (enormous) Linux kernel project.
“Git is a free and open source distributed version control system designed to handle everything
from small to very large projects with speed and efficiency.
Git is easy to learn and has a tiny footprint with lightning fast performance. ...”
https://lab.github.com/
Become a Git pro in just one blog. A thorough guide to Git architecture and command line interface
Think Like a Git [read once you're familiar with the basics]
git Documentation
GitHub Help
New project:
cd folder
git init
Tip:
Want a GUI git client?
Have a look at available gui clients for various platforms here!
[
- create/edit your project files
git log
]
[Tip: Please see http://githowto.com - “a guided tour that walks through the fundamentals of Git,
inspired by the premise that to know a thing is to do it.” ]
[
Source: "Git Magic", by Ben Lynn
About to attempt something drastic? Before you do, take a snapshot of all files in the current
directory with:
$ git init
$ git add .
$ git commit -m "My first backup"
Imagine we've begun work on an existing project and decided we'd like to setup git as the SCM.
$ cd git_fifo/
$ ls
bkp/ fifo_common.h Makefile reader_fifo* reader_fifo.c
restart_lib.h test_fifo.sh* writer_fifo* writer_fifo.c
$
Here's the project's “root” soure folder, where we'd like to setup git
One-time username/email configuration; all your commits will appear under this
name/email id..
$ git init
Initialized empty Git repository in </...>/git_fifo/.git/
$
$ git add .
Hey, don't add anything that can be re-generated; typically, this includes binary executables,
backup files and folders, etc. So lets tell git to ignore them with 'git rm'
How're we doing?
$ git log
fatal: bad default revision 'HEAD'
$
Initial commit
$
Okay!
Do commit often; as a thumb-rule, any change requiring more than one line to describe it requires
a commit!
- see log
git log
$ git remote -v
$
$ git remote -v
misc https://github.com/userme/misc.git (fetch)
misc https://github.com/userme/misc.git (push)
$
We'll also assume you've done some work and have a file or two ready to push upstream.
<< Since Git 2.0, Git defaults to the more conservative 'simple'
behavior, which only pushes the current branch to the corresponding
remote branch that 'git pull' uses to update the current branch. >>
Syntax:
git pull <git-url>
<git-url> : https://github.com/<username>/<git-repo-name>.git
To https://github.com/userme/misc.git
9b2dedf..be464f5 master -> master
Branch master set up to track remote branch master from misc.
$
Success!
Both from the cmd-line as well as git-gui I get the failure message:
"fatal: remote error: Invalid username/password.
You may need to use your generated googlecode.com password; see
https://code.google.com/hosting/settings"
We make a change in a source file; here, as an example, we change an '#if 0' to an '#if 1' (effectively
compiling in that code).
$ git diff
diff --git a/reader_fifo.c b/reader_fifo.c
index 6c3f24d..20e4c0b 100644
--- a/reader_fifo.c
+++ b/reader_fifo.c
@@ -45,7 +45,7 @@ int main(int argc, char **argv)
-#if 0
+#if 1
unlink(FIFO_FILE);
if (mkfifo(FIFO_FILE, FIFO_FILE_MODE) < 0)
err_exit(argv[0], "mkfifo failed", FAILURE);
$
We commit the change; notice that this changes the HEAD; also notice that every commit has an
associated SHA1_HASH associated with it (here it's the number
826ad70fa217d3e06baec10b0946c0750dfc995a ! ).
When specifying the commit by hask key, just using the first few numerals is (usually) sufficient to
guarantee uniqueness.
commit 992fce30d53f93dc11fa12dc17aa76862ebfb7ca
Author: Joey Joejoe <[email protected]>
Date: Thu Mar 14 08:41:45 2013 +0530
commit 4712d45b53e489273a01cf910a100e56ac459ec3
Author: Joey Joejoe <[email protected]>
Date: Thu Mar 14 08:34:27 2013 +0530
commit 67dc82282667112034962419f4ccd1918d46398f
Author: Joey Joejoe <[email protected]>
Date: Wed Mar 13 20:03:25 2013 +0530
Initial commit
$
$ git revert 826a <-- it's enough to supply just the first few numerals of the commit's
SHA1_HASH key
<< git launches vi so that the 'Revert' commit message can be edited if required ... >>
$ git log
commit 5ee6e9bb07705f1afcc20b7b3cd54631c3b17a9e <-- current HEAD
Author: Joey Joejoe <[email protected]>
Date: Thu Mar 14 08:44:29 2013 +0530
commit 826ad70fa217d3e06baec10b0946c0750dfc995a
Author: Joey Joejoe <[email protected]>
Date: Thu Mar 14 08:42:48 2013 +0530
--snip--
<< Also:
Look up section 2.2 “Advanced Undo/Redo” in the “Git Magic” book.
>>
Miscellaneous
Remove the --graph to get rid of the “graph tree” ASCII art.
Very useful!
Look for a particular feature commit, for example, GRO (Generic Receive Offload – a hardware/OS
offload technique used for better network performance):
$ git --no-pager log --pretty=format:"%h %ad | %s%d [%an]" --date=short
|egrep \
--color=auto "net.*Generic Receive| +GRO " << the regex “ +GRO ” looks
to match >= 1 spaces followed by 'GRO ' >>
45c9b3c 2015-03-23 | bgmac: implement GRO and use build_skb [Felix
Fietkau]
1037ebb 2015-03-02 | net/mlx4_en: Disbale GRO for incoming
loopback/selftest packets [Ido Shamay]
6db93ea 2015-02-10 | udp: Set SKB_GSO_UDP_TUNNEL* in UDP GRO path [Tom
Herbert]
26c4f7d 2015-02-10 | net: Fix remcsum in GRO path to not change packet
[Tom Herbert]
a4c9ea5 2014-12-30 | geneve: Add Geneve GRO support [Joe Stringer]
9b174d8 2014-12-30 | net: Add Transparent Ethernet Bridging GRO support.
[Jesse Gross]
...
...
This patch adds the top-level GRO (Generic Receive Offload) infrastructure.
This is pretty similar to LRO except that this is protocol-independent.
[...]
Eg.
Made a change in malloc's argument in a source file and committed the same. Look up the change
with:
$ git log
commit f3d68b5e5f8fb25d621d6b51e8542e82796cdab7 <-- current
HEAD
Author: Joey Joejoe <[email protected]>
Date: Thu Mar 14 09:02:49 2013 +0530
malloc sz
commit 5ee6e9bb07705f1afcc20b7b3cd54631c3b17a9e
Author: Joey Joejoe <[email protected]>
Date: Thu Mar 14 08:44:29 2013 +0530
--snip--
- buf = malloc(sz-10000);
+ buf = malloc(sz);
if (!buf)
err_exit(argv[0], "malloc failed", FAILURE);
memset(buf, 'x', sz);
$
commit 2d1cec592e0ea57281a570ba637f4268085cf393
Author: Joey Joejoe <[email protected]>
Date: Thu Mar 14 09:07:04 2013 +0530
<<
Find out what changes you’ve made since the last commit with:
$ git diff
Or since yesterday:
$ git diff "@{yesterday}"
<<
Or, what changed last with:
$ git diff master~1 master
>>
In each case the output is a patch that can be applied with git apply. Try also:
Often I’ll browse history with qgit (http://sourceforge.net/projects/qgit) instead, due to its slick
photogenic interface, or tig (http://jonas.nitro.dk/tig/), a text-mode interface that works well over
slow connections. Alternatively, install a web server, run git instaweb and fire up any web browser.
>>
<<
Say you’re working on some feature, and for some reason, you need to go back to an old version
and temporarily put in a few print statements to see how something works. Then:
$ git commit -a
$ git checkout SHA1_HASH
<< OR
also does the trick; we now have a new “branch” called “dirty” !
$ git branch
* master
dirty
$
>>
Now you can add ugly temporary code all over the place. You can even commit these changes.
When you’re done,
$ git checkout master << the meaning of the 'checkout' command in git is very different from
what it means in subversion (svn). In git, checkout implies switching
to another branch & working within that branch. >>
to return to your original work. Observe that any uncommitted changes are carried over.
What if you wanted to save the temporary changes after all? Easy:
and commit before switching back to the master branch. Whenever you want to return to the dirty
changes, simply type
We touched upon this command in an earlier chapter, when discussing loading old states. At last we
can tell the whole story: the files change to the requested state, but we must leave the master branch.
Any commits made from now on take your files down a different road, which can be named later.
In other words, after checking out an old state, Git automatically puts you in a new, unnamed
branch, which can be named and saved with git checkout -b.
You’re in the middle of something when you are told to drop everything and fix a newly discovered
bug:
$ git commit -a
$ git checkout -b fixes SHA1_HASH
Often in hardware projects, the second step of a plan must wait for the first step to be completed
before it can begin. A car undergoing repairs might sit idly in a garage until a particular part arrives
from the factory. A prototype might wait for a chip to be fabricated before construction can
continue.
Software projects can be similar. The second part of a new feature may have to wait until the first
part has been released and tested. Some projects require your code to be reviewed before accepting
it, so you might wait until the first part is approved before starting the second part.
In Git, thanks to painless branching and merging, we can bend the rules and work on Part II before
Part I is officially ready. Suppose you have committed Part I and sent it for review. Let’s say you’re
in the master branch. Then branch off:
Next, work on Part II, committing your changes along the way. To err is human, and often you’ll
want to go back and fix something in Part I. If you’re lucky, or very good, you can skip these lines.
Now you’re in the master branch again, with Part II in the working directory.
It’s easy to extend this trick for any number of parts. It’s also easy to branch off retroactively:
suppose you belatedly realize you should have created a branch several commits ago. Then type:
The master branch now contains just Part I, and the part2 branch contains the rest.
$ git branch
* master
$
<< Not happy with the current state; want to try something different...
Branch off!
>>
...
<< edit files, do your stuff, then commit >>
...
$ git commit -a
[poll4fifo d0a2691] Poll for the presence of the FIFO before attempting
to open it. This way, we don't race with the writer that creates the
FIFO object..
1 file changed, 9 insertions(+), 12 deletions(-)
$
<<
Now we're back in the 'master' branch.
If you WANT to keep the changes you've just made while in the newly created branch, use the
command.
If you do NOT want to keep the changes you just made while in the newly created branch, do Not
merge in the new branch.
>>
$ git log
commit d0a2691eb1382161f1072651d6ea701e5d6a80aa
Author: Joey Joejoe <[email protected]>
Date: Thu Mar 14 11:49:26 2013 +0530
Poll for the presence of the FIFO before attempting to open it.
This way, we don't race with the writer that creates the FIFO
object..
commit 27271779a8b2d7ea3e56582ffa1fd00a6a2f0322
Author: Joey Joejoe <[email protected]>
Date: Thu Mar 14 09:53:12 2013 +0530
have the reader retry the FIFO open thrice before reporting failure
(due to a poss race w/ the writer not having cr8 the FIFO yet). RELOOK?
--snip--
Method 1
Viewing the detailed history of a source file (line-by-line) is easily achieved with the 'git blame'
command.
Eg.
$ git blame shm_read.c
...
^9751d63 (Kaiwan Billimoria 2013-08-02 21:06:53 +0530 99) if
(verbose) {
0e407dd3 (Kaiwan Billimoria 2013-08-02 21:39:31 +0530 100)
printf("%s [%d] : loop #%3d buf read, %d bytes (from 0x%08x)\n",
0e407dd3 (Kaiwan Billimoria 2013-08-02 21:39:31 +0530 101)
argv[0], pid, i, sz, (unsigned int)shm_vaddr);
0e407dd3 (Kaiwan Billimoria 2013-08-02 21:39:31 +0530 102)
//printf(" :: \"%.*s\"\n", sz, buf);
^9751d63 (Kaiwan Billimoria 2013-08-02 21:06:53 +0530 103) }
0e407dd3 (Kaiwan Billimoria 2013-08-02 21:39:31 +0530 104)
shm_vaddr += sz;
...
$
How does one figure the kernel version given only the patch (SHA1) id?
Ref: Given a git patch id, how to find out which kernel release contains it?
Short Ans:
Use 'git describe' like so (on the local repo of course; it can take a while!):
BTW, 3aa551c9 is the (first 8 digits) of the unique SHA1 id of the "Add support for threaded interrupt
handlers - V3" by Thomas Gleixner !
Method 2
USEFUL! Get the complete commit history of a particular line(s) of a given file
Sometimes, we’d like to figure out the complete history of a full, or a range of lines, within a file.
Git can do this with:
Example:
u64);
};
commit 6192269444ebfbfb42e23c7a6a93c76ffe4b5e51
Author: Al Viro <[email protected]>
[...]
commit 54dbc15172375641ef03399e8f911d7165eb90fb
Author: Darrick J. Wong <[email protected]>
+ u64);
};
commit 04b38d601239b4d9be641b412cf4b7456a041c67
Author: Christoph Hellwig <[email protected]>
[...]
[...]
commit 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2
Linux-2.6.12-rc2
Ref [SO]: Retrieve the commit log for a specific line in a file?
Method 3
GUI
Lets say you'd like to view the detailed history of the kernel source file kernel/fork.c .
Pre-requisites:
• Clone the Linux kernel git repository onto your box with:
$ git clone
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-
stable.git
(this can take a while!)
• Ensure you have installed gitk and git-gui applications
Steps:
1. cd to the git kernel root source tree folder
2. Run gitk
3. Within gitk select the menu item: File / Start git gui
The git-gui program runs
4. Within git-gui select the menu item: File Repository / Browse master's Files
5. A “File Browser” dialog comes up, displaying the contents of master:
6. Double-click the folder/file you'd like to browse
7. A “File Viewer” dialog now displays the source file contents, and annotates it (with all it's
associated commits!)
Browse through.
[
The commit highlighted above happened in which kernel version?
$ git describe --contains a24efe62
v2.6.24-rc1~144
]
Miscellaneous
Sometimes, we’ll have a codebase with some file(s) modified, but intentionally not staged for
commit. Then, if we attempt to ‘pull’ deltas or switch a branch, we’ll get this error:
Eg.
$ git status
On branch memsanit4
Changes not staged for commit:
modified: init/main.c
modified: mm/Kconfig.debug
modified: mm/page_poison.c
modified: mm/slub.c
...
Ref: http://stackoverflow.com/questions/15745045/how-do-i-resolve-git-saying-commit-your-changes-or-
stash-them-before-you-can-me
$ git stash
Saved working directory and index state WIP on memsanit4: 421cf05 Add
linux-next specific files for 20170203
HEAD is now at 421cf05 Add linux-next specific files for 20170203
$
$ git checkout -b memsanit5 next-20170223 << now succeeds >>
Checking out files: 100% (4900/4900), done.
Switched to a new branch 'memsanit5'
$
modified: init/main.c
modified: mm/Kconfig.debug
modified: mm/page_poison.c
modified: mm/slub.c
...
no changes added to commit (use "git add" and/or "git commit -a")
$
<<
You can use the github tree but it’s not recommended by Linus; also, you cannot fetch
“subversions” (ver x.y.z – major.minor.sublevel) with the github tree:
$ git clone https://github.com/torvalds/linux.git
>>
Tutorials:
KernelBuild on kernelnewbies
Kernel Hackers' Guide to git
REGULAR_TREE=0
LINUX_NEXT_TREE=1 # linux-next: working with the bleeding edge?
GITURL=https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.gi
t
echo "${name}: cloning 'regular' linux kernel now ..."
time git clone ${GITURL}
}
# For 'regular': to update to latest:
# git pull ${GITURL}
# or just
# git pull
cd linux-next || exit 1
echo " Running: git checkout master"
git checkout master
echo " Running: git remote update"
git remote update
LATEST_TAG=$(git tag -l next-* | tail -n1)
echo " Latest tag: ${LATEST_TAG}"
echo " Running: git checkout -b ${NEW_BRANCH} ${LATEST_TAG}"
git checkout -b ${NEW_BRANCH} ${LATEST_TAG}
}
A quick example (applying the S.A.R.A. security LSM patch on the v4.14-rc1 kernel source):
Documentation/admin-guide/LSM/index.rst | 1
Documentation/admin-guide/kernel-parameters.txt | 24 +
include/linux/lsm_hooks.h | 5
security/Kconfig | 1
security/Makefile | 2
security/sara/Kconfig | 43 +
security/sara/Makefile | 3
security/sara/include/sara.h | 29 +
security/sara/include/securityfs.h | 59 ++
security/sara/include/utils.h | 69 ++
security/sara/main.c | 105 ++++
security/sara/securityfs.c | 560 ++++++++++++++++
+++
security/sara/utils.c | 151 +++++
security/security.c | 1
include/linux/lsm_hooks.h | 7
include/linux/security.h | 6
mm/mmap.c | 13
security/security.c | 5
include/linux/cred.h | 3
security/sara/Makefile | 2
security/sara/include/sara_data.h | 47 ++
security/sara/main.c | 6
security/sara/sara_data.c | 79 +++
security/sara/Kconfig | 75 +++
security/sara/Makefile | 1
security/sara/include/utils.h | 11
security/sara/include/wxprot.h | 27 +
security/sara/main.c | 6
security/sara/wxprot.c | 683 ++++++++++++++++
+++++++
arch/Kconfig | 6
arch/x86/Kconfig | 1
[...]
Done.
...
To remove the last commit from git, you can simply run
If you are removing multiple commits from the top, you can run
to remove the last two commits. You can increase the number to remove even
more commits.
...
Generate Patch