Skip to content

Latest commit

 

History

History
827 lines (579 loc) · 40.7 KB

git.org

File metadata and controls

827 lines (579 loc) · 40.7 KB

Pro Git

The Three States

Git has three main states that your files can reside in: modified, staged, and committed:

Modified
you have changed the file but have not committed it to your database yet.
Staged
you have marked a modified file in its current version to go into your next commit snapshot.
Committed
the data is safely stored in your local database.

This leads us to the three main sections of a Git project: the working tree, the staging area, and the Git directory.

 Working                       Staging                 .git directory
Directory                       Area                   (Repository)

<----------------- checkout the project-----------------------

Stage Fixes --------------------->

                              Commit ------------------------>

The working tree
is a single checkout of one version of the project. These files are pulled out of the compressed database in the Git directory and placed on disk for you to use or modify.
The staging area
is a file, generally contained in your Git directory, that stores information about what will go into your next commit. Its technical name in Git parlance is the “index”.
The Git directory
is where Git stores the metadata and object database for your project. This is the most important part of Git, and it is what is copied when you clone a repository from another computer.

Recording Changes to the Repository

Tracked files
are files that were in the last snapshot, as well as any newly staged files; they can be unmodified, modified, or staged. In short, tracked files are files that Git knows about.
Untracked files
are everything else — any files in your working directory that were not in your last snapshot and are not in your staging area.

The lifecycle of the status of your files:

Untracked        ¦-------------------- Tracked ----------------------¦
                  Unmodified           Modified                Staged

Add the file ---------------------------------------------------->

                    Edit the file -------->

                                            Stage the file ------>

<---------- Remove the file

                   <------------------------------------------Commit

Branches in a Nutshell

Branching

Branch

Branching means you diverge from the main line of development and continue to do work without messing with that main line.

When you make a commit, Git stores a commit object that contains a pointer to the snapshot of the content you staged. This object also contains the author’s name and email address, the message that you typed, and pointers to the commit or commits that directly came before this commit (its parent or parents): zero parents for the initial commit, one parent for a normal commit, and multiple parents for a commit that results from a merge of two or more branches.

Let’s assume that you have a directory containing three files, and you stage them all and commit. Staging the files computes a checksum for each one, stores that version of the file in the Git repository (Git refers to them as blobs), and adds that checksum to the staging area.

When you create the commit by running git commit, Git checksums each subdirectory (in this case, just the root project directory) and stores them as a tree object in the Git repository. Git then creates a commit object that has the metadata and a pointer to the root project tree so it can re-create that snapshot when needed.

Git repository now contains five objects: three blobs (each representing the contents of one of the three files), one tree that lists the contents of the directory and specifies which file names are stored as which blobs, and one commit with the pointer to that root tree and all the commit metadata.

                                                        5b1d3
                                                    +-----------+
                                                    | blob size |
                                                    |           |
                                                    | License   |
                                                    +-----------+
                                                   /
                                                  /
       98ca9                       92ec2         /        911e7
+--------------------+     +--------------------+     +-----------+
| commit    size     |     | tree size          |     | blob size |
| tree      92ec2    |     | blob 5b1d3 README  |     |           |
| author    Scott    | --> | blob 911e7 LICENSE | --> |           |
| commiter  Scott    |     | blob cba0a test.rb |     |           |
| The initial commit |     |                    |     | Library   |
+--------------------+     +--------------------+     +-----------+
                                                 \
                                                  \
                                                   \    cba0a
                                                    +-----------+
                                                    | blob size |
                                                    |           |
                                                    | test      |
                                                    +-----------+

If you make some changes and commit again, the next commit stores a pointer to the commit that came immediately before it.

         98ca9                    34ac2                   f30ab
+--------------------+     +-----------------+     +-----------------+
| commit    size     |     | commit    size  |     | commit    size  |
| tree      92ec2    |     | tree      184ca |     | tree      0de24 |
| parent             |     | parent    98ca9 |     | parent    34ac2 |
| author    Scott    | <-- | author    Scott | <-- | author    Scott |
| commiter  Scott    |     | commiter  Scott |     | commiter  Scott |
| The initial commit |     | Fixed bug #32   |     | ass feature #4  |
+--------------------+     +-----------------+     +-----------------+
           ¦                        ¦                       ¦
    +------------+           +------------+           +------------+
    | Snapshot A |           | Snapshot B |           | Snapshot C |
    +------------+           +------------+           +------------+

A branch in Git is simply a lightweight movable pointer to one of these commits. The default branch name in Git is master. As you start making commits, you’re given a master branch that points to the last commit you made. Every time you commit, the master branch pointer moves forward automatically.

New Branch When you create a new branch, this creates a new pointer to the same commit you’re currently on.

Merge Branch When you try to merge one commit with a commit that can be reached by following the first commit’s history, Git simplifies things by moving the pointer forward because there is no divergent work to merge together — this is called a “fast-forward.”

Remote Branches

Remote reference
are reference (pointers) in your remote repositories, including branches, tags, and so on.
Remote-tracking branches
are references to the state of remote branches. They’re local references that you can’t move; Git moves them for you whenever you do any network communication, to make sure they accurately represent the state of the remote repository. Think of them as bookmarks, to remind you where the branches in your remote repositories were the last time you connected to them.
Tracking Branches
are local branches that have a direct relationship to a remote branch. If you’re on a tracking branch and type git pull , Git automatically knows which server to fetch from and which branch to merge in.

Merge Conflicts

Anything that has merge conflicts and hasn’t been resolved is listed as unmerged when this command is used git status . 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, because that was what you had checked out when you ran your merge command) is the top part of that block (everything above the =======), while the version in your other branch looks like everything in the bottom part. In order to resolve the conflict, you have to either choose one side or the other or merge the contents yourself.

Once solved, the resolution has a little of each section, and the <<<<<<<, =======, and >>>>>>> lines have been completely removed. 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.

Tracking Branches

Checking out a local branch from a remote-tracking branch automatically creates what is called a “tracking branch” (and the branch it tracks is called an “upstream branch”). Tracking branches are local branches that have a direct relationship to a remote branch. If you’re on a tracking branch and type git pull, Git automatically knows which server to fetch from and which branch to merge in.

When you clone a repository, it generally automatically creates a master branch that tracks origin/master. However, you can set up other tracking branches if you wish — ones that track branches on other remotes, or don’t track the master branch. The simple case is the example you just saw, running git checkout -b <branch> <remote>/<branch>.

Rebasing

Rebasing different branches

                             experiment
                              +----+
                              | C4 |
                              +----+
                            /
                          L
+----+    +----+    +----+    +----+
| C0 |<-- | C1 |<-- | C2 |<-- | C3 |
+----+    +----+    +----+    +----+
                              master

The easiest way to integrate the branches, is the merge command. It performs a three-way merge between the two latest branch snapshots (C3 and C4) and the most recent common ancestor of the two (C2), creating a new snapshot (and commit).

 MERGE
                            experiment
                              +----+
                              |*C4*|
                              +----+
                             /      ^
                           L          \
+----+    +----+    +----+    +----+   +----+
| C0 |<-- | C1 |<-- |*C2*|<-- |*C3*|<--| C5 |
+----+    +----+    +----+    +----+   +----+
                                       master

However, there is another way: you can take the patch of the change that was introduced in C4 and reapply it on top of C3. In Git, this is called rebasing. With the rebase command, you can take all the changes that were committed on one branch and replay them on a different branch.

For this example, you would switch the experiment branch, and then rebase it onto the master branch.

This operation works by going to the common ancestor of the two branches (the one you’re on and the one you’re rebasing onto), getting the diff introduced by each commit of the branch you’re on, saving those diffs to temporary files, resetting the current branch to the same commit as the branch you are rebasing onto, and finally applying each change in turn.

Rebasing the change introduced in C4 onto C3 .

                               + - -+
                               |+C4+|
                               +- - +

                                       experiment
+----+    +----+    +----+    +----+    +-----+
| C0 |<-- | C1 |<-- | C2 |<-- | C3 |<-- | C4' |
+----+    +----+    +----+    +----+    +-----+
                              master


Fast-forwarding the master branch applying git checkout master ; git merge experiment command:

                                       experiment
+----+    +----+    +----+    +----+    +-----+
| C0 |<-- | C1 |<-- | C2 |<-- | C3 |<-- | C4' |
+----+    +----+    +----+    +----+    +-----+
                              master


Now, the snapshot pointed to by C4' is exactly the same as the one that was pointed to by C5 in the merge example. There is no difference in the end product of the integration, but rebasing makes for a cleaner history. If you examine the log of a rebased branch, it looks like a linear history: it appears that all the work happened in series, even when it originally happened in parallel.

More Interesting Rebases

                              master
+----+    +----+    +----+    +----+
| C1 |<-- | C2 |<-- | C5 |<-- | C6 |
+----+    +----+    +----+    +----+
                ^
                 \
                    +----+    +----+    +-----+
                    | C3 |<-- | C4 |<-- | C10 |
                    +----+    +----+    +-----+
                          ^              server
                           \
                              +----+    +-----+
                              | C8 |<-- | C9  |
                              +----+    +-----+
                                         client

You want to merge your client-side changes into your mainline for a release, but you want to hold off on the server-side changes until it’s tested further. You can take the changes on client that aren’t on server (C8 and C9) and replay them on your master branch by using the --onto option of git rebase:

git rebase --onto master server client

                              master                client
+----+    +----+    +----+    +----+    +-----+    +-----+
| C1 |<-- | C2 |<-- | C5 |<-- | C6 |<-- | C8' |<-- | C9' |
+----+    +----+    +----+    +----+    +-----+    +-----+
                ^
                 \
                    +----+    +----+    +-----+
                    | C3 |<-- | C4 |<-- | C10 |
                    +----+    +----+    +-----+
                                        server

                              + - -+    +- - +
                              |+C8+|<-- |+C9+|
                              +- - +    + - -+

warning: Do not rebase commits that exist outside your repository and that people may have based work on.

Rebase vs. Merge: You can get the best of both worlds: rebase local changes before pushing to clean up your work, but never rebase anything that you’ve pushed somewhere.

Remote repositories

About remote repositories

A remote URL is Git’s fancy way of saying ”the place where your code is stored.” That URL could be your repository on GitHub, or another user’s fork, or even on a completely different server.

You can only push to two types of URL addresses:

  • An HTTPS URL like https://github.com/user/repo.git
  • An SSH URL, like [email protected]:user/repo.git

Git associates a remote URL with a name, and your default remote is usually called origin.

Creating remote repositories

You can use the git remote add command to match a remote URL with a name. For example, you’d type the following in the command line:

git remote add origin <REMOTE_URL>

This associates the name origin with the REMOTE_URL.

You can use the command git remote set-url to change a remote’s URL.

About git push

The git push command takes two arguments:

A remote name, for example, origin A branch name, for example, main

For example:

git push REMOTE-NAME BRANCH-NAME

As an example, you usually run git push origin main to push your local changes to your online repository.

Distributed Git

Contributing to a Project

Private Small Team

The simplest setup you’re likely to encounter is a private project with one or two other developers. “Private,” in this context, means closed-source — not accessible to the outside world. You and the other developers all have push access to the repository.

That is one of the simplest workflows. You work for a while (generally in a topic branch), and merge that work into your master branch when it’s ready to be integrated. When you want to share that work, you fetch and merge your master from origin/master if it has changed, and finally push to the master branch on the server.

Private Managed Team

In this next scenario, you’ll look at contributor roles in a larger private group. You’ll learn how to work in an environment where small groups collaborate on features, after which those team-based contributions are integrated by another party.

Let’s say that John and Jessica are working together on one feature (call this “featureA”), while Jessica and a third developer, Josie, are working on a second (say, “featureB”). In this case, the company is using a type of integration-manager workflow where the work of the individual groups is integrated only by certain engineers, and the master branch of the main repo can be updated only by those engineers. In this scenario, all work is done in team-based branches and pulled together by the integrators later.

Forked Public Project

You’ll probably want to clone the main repository, create a topic branch for the patch or patch series you’re planning to contribute, and do your work there. The sequence looks basically like this:

git clone <url>
cd project
git checkout -b featureA
#... work ...
git commit
#... work ...
git commit

When your branch work is finished and you’re ready to contribute it back to the maintainers, go to the original project page and click the “Fork” button, creating your own writable fork of the project. You then need to add this repository URL as a new remote of your local repository.

git remote add myfork <url>

You then need to push your new work to this repository. In any event, you can push your work with:

git push -u myfork featureA

Once your work has been pushed to your fork of the repository, you need to notify the maintainers of the original project that you have work you’d like them to merge. You can run the git request-pull command and email the subsequent output to the project maintainer manually.

The git request-pull command takes the base branch into which you want your topic branch pulled and the Git repository URL you want them to pull from, and produces a summary of all the changes you’re asking to be pulled.

git request-pull origin/master myfork

If you want to submit a second topic of work to the project, don’t continue working on the topic branch you just pushed up — start over from the main repository’s master branch:

git checkout -b featureB origin/master

Public Project over Email

You create topic branches for each patch series you work on. You generate email versions of each commit series and email them to the developer mailing list:

git checkout -b topicA
#... work ...
git commit
#... work ...
git commit

Now you have two commits that you want to send to the mailing list. You use git format-patch to generate the mbox-formatted files that you can email to the list:

git format-patch -M origin/master (prints out the names of the patch files it creates)

To email this to a mailing list

You can either paste the file into your email program or send it via a command-line program. We’ll demonstrate how to send a patch via Gmail. First, you need to set up the imap section in your ~~/.gitconfig~ file.You can set each value separately with a series of git config commands, or you can add them manually, but in the end your config file

[imap]
  folder = "[Gmail]/Drafts"
  host = imaps://imap.gmail.com #if IMAP server doesn’t use SSL use imap://
  user = [email protected]
  pass = YX8g76G_2^sFbd
  port = 993 #if IMAP server doesn’t use SSL, probably aren’t necessary
  sslverify = false #if IMAP server doesn’t use SSL, probably aren’t necessary

When that is set up, you can use git imap-send to place the patch series in the Drafts folder of the specified IMAP server:

cat *.patch |git imap-send

Send the patches through an SMTP server.

As before, you can set each value separately with a series of git config commands, or you can add them manually in the sendemail section in your ~~/.gitconfig~ file:

[sendemail]
  smtpencryption = tls
  smtpserver = smtp.gmail.com
  smtpuser = [email protected]
  smtpserverport = 587

After this is done, you can use git send-email to send your patches:

git send-email *.patch

Commit Guidelines

First, your submissions should not contain any whitespace errors. Run git diff --check .

Next, try to make each commit a logically separate changeset. If some of the changes modify the same file, try to use git add --patch to partially stage files.

As a general rule, your messages should start with a single line that’s no more than about 50 characters and that describes the changeset concisely, followed by a blank line, followed by a more detailed explanation. Write your commit message in the imperative: “Fix bug” and not “Fixed bug” or “Fixes bug.” Here is a template:

Capitalized, short (50 chars or less) summary

More detailed explanatory text, if necessary.  Wrap it to about 72
characters or so.  In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body.  The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase will confuse you if you run the
two together.

Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
or "Fixes bug."  This convention matches up with commit messages generated
by commands like git merge and git revert.

Further paragraphs come after blank lines.

- Bullet points are okay, too

- Typically a hyphen or asterisk is used for the bullet, followed by a
  single space, with blank lines in between, but conventions vary here

- Use a hanging indent

The Git project has well-formatted commit messages — try running git log --no-merges there to see what a nicely-formatted project-commit history looks like.

Note: Regarding the “summary” line (the 50 in your formula), the Linux kernel documentation has this to say:

For these reasons, the "summary" must be no more than 70-75
characters, and it must describe both what the patch changes, as well
as why the patch might be necessary.  It is challenging to be both
succinct and descriptive, but that is what a well-written summary
should do.

Distributed Workflow

Centralized Workflow

One central hub, or repository, can accept code, and everyone synchronizes their work with it. A number of developers are nodes — consumers of that hub — and synchronize with that centralized location.

This means that if two developers clone from the hub and both make changes, the first developer to push their changes back up can do so with no problems. The second developer must merge in the first one’s work before pushing changes up, so as not to overwrite the first developer’s changes.

Integration-Manager Workflow

Because Git allows you to have multiple remote repositories, it’s possible to have a workflow where each developer has write access to their own public repository and read access to everyone else’s. This scenario often includes a canonical repository that represents the “official” project.

  1. The project maintainer pushes to their public repository.
  2. A contributor clones that repository and makes changes.
  3. The contributor pushes to their own public copy.
  4. The contributor sends the maintainer an email asking them to pull changes.
  5. The maintainer adds the contributor’s repository as a remote and merges locally.
  6. The maintainer pushes merged changes to the main repository.

    One of the main advantages of this approach is that you can continue to work, and the maintainer of the main repository can pull in your changes at any time.

Dictator and Lieutenants Workflow

It’s generally used by huge projects with hundreds of collaborators; one famous example is the Linux kernel.

  1. Regular developers work on their topic branch and rebase their work on top of master. The master branch is that of the reference repository to which the dictator pushes.
  2. Lieutenants merge the developers’ topic branches into their master branch.
  3. The dictator merges the lieutenants’ master branches into the dictator’s master branch.
  4. Finally, the dictator pushes that master branch to the reference repository so the other developers can rebase on it.

Github

The GitHub Flow

Generally works

  1. Fork the project.
  2. Create a topic branch from master.
  3. Make some commits to improve the project.
  4. Push this branch to your GitHub project.
  5. Open a Pull Request on GitHub.
  6. Discuss, and optionally continue committing.
  7. The project owner merges or closes the Pull Request.
  8. Sync the updated master back to your fork.

Example

  1. Clone our fork of the project locally.
  2. Create a descriptive topic branch.
  3. Make our change to the code.
  4. Check that the change is good.
  5. Commit our change to the topic branch.
  6. Push our new topic branch back up to our GitHub fork.
$ git clone https://github.com/tonychacon/blink # (1)
# Cloning into 'blink'...

$ cd blink
$ git checkout -b slow-blink # (2)
#Switched to a new branch 'slow-blink'

$ sed -i 's/1000/3000/' blink.ino # (3)

$ git diff --word-diff # (4)
# diff --git a/blink.ino b/blink.ino
# index 15b9911..a6cc5a5 100644
# --- a/blink.ino
# +++ b/blink.ino
# @@ -18,7 +18,7 @@ void setup() {
# // the loop routine runs over and over again forever:
# void loop() {
#   digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
#   [-delay(1000);-]{+delay(3000);+}               // wait for a second
#   digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
#   [-delay(1000);-]{+delay(3000);+}               // wait for a second
# }

$ git commit -a -m 'Change delay to 3 seconds' # (5)
# [slow-blink 5ca509d] Change delay to 3 seconds
#  1 file changed, 2 insertions(+), 2 deletions(-)

$ git push origin slow-blink # (6)
# Username for 'https://github.com': tonychacon
# Password for 'https://[email protected]':
# Counting objects: 5, done.
# Delta compression using up to 8 threads.
# Compressing objects: 100% (3/3), done.
# Writing objects: 100% (3/3), 340 bytes | 0 bytes/s, done.
# Total 3 (delta 1), reused 0 (delta 0)
# To https://github.com/tonychacon/blink
#  * [new branch]      slow-blink -> slow-blink

Keep your GitHub public repository up-to-date

If you forked from https://github.com/progit/progit2.git, you can keep your master branch up-to-date like this:

git checkout master # (1)
git pull https://github.com/progit/progit2.git # (2)
git push origin master # (3)
  1. If you were on another branch, return to master.
  2. Fetch changes from https://github.com/progit/progit2.git and merge them into master.
  3. Push your master branch to origin.

This works, but it is a little tedious having to spell out the fetch URL every time. You can automate this work with a bit of configuration:

git remote add progit https://github.com/progit/progit2.git # (1)
git fetch progit # (2)
git branch --set-upstream-to=progit/master master # (3)
git config --local remote.pushDefault origin # (4)
  1. Add the source repository and give it a name. Here, I have chosen to call it progit.
  2. Get a reference on progit’s branches, in particular master.
  3. Set your master branch to fetch from the progit remote.
  4. Define the default push repository to origin.

Once this is done, the workflow becomes much simpler:

git checkout master # (1)
git pull # (2)
git push # (3)
  1. If you were on another branch, return to master.
  2. Fetch changes from progit and merge changes into master.
  3. Push your master branch to origin.

This approach can be useful, but it’s not without downsides. Git will happily do this work for you silently, but it won’t warn you if you make a commit to master, pull from progit, then push to origin~ — all of those operations are valid with this setup. So you’ll have to take care never to commit directly to ~master, since that branch effectively belongs to the upstream repository.

Special Files

README

Can be of nearly any format that GitHub recognizes as prose. For example, it could be README, README.md, README.asciidoc, etc. If GitHub sees a README file in your source, it will render it on the landing page of the project.

Many teams use this file to hold all the relevant project information for someone who might be new to the repository or project. This generally includes things like:

  • What the project is for
  • How to configure and install it
  • An example of how to use it or get it running
  • The license that the project is offered under
  • How to contribute to it

Since GitHub will render this file, you can embed images or links in it for added ease of understanding.

CONTRIBUTING

If you have a file named CONTRIBUTING with any file extension, GitHub will show Opening a Pull Request when a CONTRIBUTING file exists when anyone starts opening a Pull Request.

The idea here is that you can specify specific things you want or don’t want in a Pull Request sent to your project. This way people may actually read the guidelines before opening the Pull Request.

Miscellaneus

Set configuration variables

  • /etc/gitconfig Contains values applied to every user on the system and all their repositories.
  • ~~/.gitconfig~ or ~~/.config/git/config~ Values specific personally to you, the user.
  • config file in the Git directory (that is, .git/config) of whatever repository you’re currently using: Specific to that single repository.

File .gitignore

Create a file to add a list of patterns to match the files to be ignored.

The rules for the patterns you can put in the .gitignore file are as follows:

  • Blank lines or lines starting with # are ignored.
  • Standard glob patterns work, and will be applied recursively throughout the entire working tree.
  • You can start patterns with a forward slash (/) to avoid recursivity.
  • You can end patterns with a forward slash (/) to specify a directory.
  • You can negate a pattern by starting it with an exclamation point (!).
  • You can also use two asterisks to match nested directories; a/**/z would match a/z, a/b/z, a/b/c/z.

In the simple case, a repository might have a single .gitignore file in its root directory, which applies recursively to the entire repository. However, it is also possible to have additional .gitignore files in subdirectories. The rules in these nested .gitignore files apply only to the files under the directory where they are located.

man gitignore show more details.

# ignore any files ending in “.o” or “.a”
*.[oa]

# but do track lib.a, even though you're ignoring .a files above
!lib.a

# only ignore the TODO file in the current directory, not subdir/TODO
/TODO

# ignore all files in any directory named build
build/

# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt

# ignore all .pdf files in the doc/ directory and any of its subdirectories
doc/**/*.pdf

Tags

Lightweight

Is very much like a branch that doesn’t change — it’s just a pointer to a specific commit.

Annotated

Are stored as full objects in the Git database. They’re checksummed; contain the tagger name, email, and date; have a tagging message; and can be signed and verified with GNU Privacy Guard (GPG). It’s generally recommended that you create annotated tags so you can have all this information; but if you want a temporary tag or for some reason don’t want to keep the other information, lightweight tags are available too.

Git on the Server

Bare repository

A remote repository is generally a *bare repository* — a Git repository that has no working directory. In the simplest terms, a bare repository is the contents of project’s .git directory and nothing else. It’s just the Git data.

The Protocols

Local Protocol
The most basic protocol is the Local protocol, in which the remote repository is in another directory on the same host. If you have a shared mounted filesystem, then you can clone, push to, and pull from a local file-based repository. To clone a repository like this, or to add one as a remote to an existing project, use the path to the repository as the URL.
The HTTP Protocols
Smart HTTP
Smart HTTP operates very similarly to the SSH or Git protocols but runs over standard HTTPS ports and can use various HTTP authentication mechanisms, meaning it’s often easier on the user than something like SSH, since you can use things like username/password authentication rather than having to set up SSH keys.
Dumb HTTP
The Dumb protocol expects the bare Git repository to be served like normal files from the web server. The beauty of Dumb HTTP is the simplicity of setting it up. Basically, all you have to do is put a bare Git repository under your HTTP document root and set up a specific post-update hook, and you’re done.
The SSH Protocol
A common transport protocol for Git when self-hosting is over SSH. This is because SSH access to servers is already set up in most places — and if it isn’t, it’s easy to do.
The Git Protocol
This is a special daemon that comes packaged with Git; it listens on a dedicated port (9418) that provides a service similar to the SSH protocol, but with absolutely no authentication. In order for a repository to be served over the Git protocol, you must create a git-daemon-export-ok file — the daemon won’t serve a repository without that file in it — but, other than that, there is no security.

Getting Git on a Server

In order to initially set up any Git server, you have to export an existing repository into a new bare repository — a repository that doesn’t contain a working directory. Now that you have a bare copy of your repository, all you need to do is put it on a server and set up your protocols.

Commands

The Protocols

Local Protocol
git clone /srv/git/project.git

To clone a local repository. Git tries to use hardlinks or directly copy the files it needs.

git clone file:///srv/git/project.git

To clone a local repository. Git fires up the processes that it normally uses to transfer data over a network, which is generally much less efficient (clean copy of the repository with extraneous references or objects left out).

git remote add local_proj / srv/git/project.git

To add a local repository to an existing Git project. (you can push to and pull from that remote via your new remote name local_proj as though you were doing so over a network)

Dumb HTTP
To allow read access to your repository over HTTP, do something like this:

The Dumb protocol expects the bare Git repository to be served like normal files from the web server. The beauty of Dumb HTTP is the simplicity of setting it up. Basically, all you have to do is put a bare Git repository under your HTTP document root and set up a specific post-update hook, and you’re done.

cd /var/www/htdocs/
git clone --bare /path/to/git_project gitproject.git
cd gitproject.git
mv hooks/post-update.sample hooks/post-update
chmod a+x hooks/post-update

# In this particular case, we’re using the /var/www/htdocs path that is
# common for Apache setups, but you can use any static web server — just
# put the bare repository in its path.

The post-update hook that comes with Git by default runs the appropriate command (git update-server-info) to make HTTP fetching and cloning work properly.

To clone repository.

SSH Protocol
git clone ssh://[user@]server/project.git

To clone a Git repository over SSH. (if don’t specify the optional username, Git assumes the user is currently logged in as)

git clone [user@]server:project.git

To clone a Git repository with shorter scp-like syntax for the SSH protocol. (if don’t specify the optional username, Git assumes the user is currently logged in as)

Getting Git on a Server

git clone –bare my_project my_project.git

Clone your repository to create a new bare repository. With this you have a copy of the Git directory data in your my_project.git directory. ( cp -Rf my_project/.git my_project.git equivalent command* )

scp -r my_project.git [email protected]:/srv/git

Set up new repository by copying bare repository over. Assuming that //srv/git/ exists on the server git.example.com .

git clone [email protected]:/srv/git/my_project.git

Clone repository by users who have SSH-based read access to the //srv/git/ directory on that server. ( if a user SSHs into a server and has write access to the //srv/git/my_project.git/ directory, they will also automatically have push access)

git init –bare –shared

Will automatically add group write permissions to a repository. (this command, you will not destroy any commits, refs, etc. in the process)

ssh [email protected]
cd /srv/git/my_project.git
git init --bare --shared

Git Daemon

git daemon –reuseaddr –base-path=/srv/git/ / srv/git/

Set up Git daemon serving repositories using the “Git” protocol. (If you’re running a firewall, you’ll also need to punch a hole in it at port 9418 on the box you’re setting this up on) [ –reuseaddr allows the server to restart without waiting for old connections to time out –base-path allows people to clone projects without specifying the entire path //srv/git// at the end tells the Git daemon where to look for repositories to export ]

# Place a file in /etc/systemd/system/git-daemon.service

[Unit]
Description=Start Git Daemon

[Service]
ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/srv/git/ /srv/git/

Restart=always
RestartSec=500ms

StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=git-daemon

User=git
Group=git

[Install]
WantedBy=multi-user.target

# run systemctl enable git-daemon to automatically start the service on
# boot, and can start and stop the service with, respectively, systemctl
# start git-daemon and systemctl stop git-daemon.
# You to have to tell Git which repositories to allow unauthenticated
# Git server-based access to. You can do this in each repository by
# creating a file named git-daemon-export-ok.

cd /path/to/project.git
touch git-daemon-export-ok

# The presence of that file tells Git that it’s OK to serve this project
# without authentication.

Git log

Specifier and description

SpecifierDescription of Output
%HCommit hash
%hAbbreviated commit hash
%TTree hash
%tAbbreviated tree hash
%PParent hashes
%pAbbreviated parent hashes
%anAuthor name
%aeAuthor email
%adAuthor date(format respect the –date=option)
%arAuthor date, relative
%cnCommitter name
%ceCommitter email
%cdCommitter date
%crCommitter date, relative
%sSubject

Limit the output

OptionDescription
-<n>Show only the last n commits
–since, –afterLimit commits after the specified date
–until, –beforeLimit commits before the specified date
–authorOnly show commits in which the author
entry matches the specified string
–committerOnly show commits in which the committer
entry matches the specified string
–grepOnly s commits with commit msg containing str
-SOnly s commits adding or rm code matching str

References