1. Introduction
In my
last post I tried to highlight the style of working with
distributed git version control system and point out the differences from
classic centralized SLE. The goal was primarily a summary of the experience.
work with the system without mentioning the subtleties of the syntax of individual commands.
This topic was conceived as a direct introduction to working with git, something
mean between tutorial and generalized help, which is still recommended
read the above introduction. Technical deliberately avoided
the details of the git work, only common terms for SLE are used and
limited to a list of referenced commands.
')
2 Working with a local repository
The power of any distributed systems is available to every local developer.
repository in which it is possible to organize an arbitrary personal scheme
development. Git has a few basic commands for doing work on site and
many auxiliary.
2.1 Basic commands
Basic commands - those without which it is impossible to do in the development.
2.1.1 git init - creating a repository
The git init command creates an empty repository in the directory as a directory.
.git, where all information about the history of commits will be stored in the future,
tags - project development:
mkdir project-dir
cd project-dir
git init
Another way to create a repository is with the git clone command, but more about that later.
2.1.2 git add and git rm - indexing changes
The next thing you need to know is the git add command. It allows you to make changes to the index - temporary storage - which will then be included in the commit. Examples
use:
git add EDITEDFILE - indexing the modified file, or a notification about
creating a new one.
git add. - make the index all changes, including new files.
From the index and tree of the project at the same time, you can delete the file with the git rm command:
git rm FILE1 FILE2 - individual files
git rm Documentation / \ *. txt is a good example of removing from git documentation,
all txt files from the folder are deleted at once.
You can reset the entire index or remove changes from a specific file from it.
with the git reset command:
git reset - reset nafig entire index.
git reset - EDITEDFILE - remove a specific file from the index.
The git reset command is not only used for dropping an index
she will be given much more attention.
2.1.3 git status - project status, modified and not added files, indexed files
The git status command can perhaps be considered the most frequently used along with
commit and index commands. It displays information about all changes,
the project directories listed in the tree compared to the last working commit
branches; separately indexed and non-indexed
files. Using it is extremely simple:
git status
In addition, git status indicates files with unresolved merge conflicts and
files ignored by git.
2.1.4 git commit - commit commit
Commits are a basic concept in all version control systems, therefore they are committed
he should easily and whenever possible quickly. In its simplest form, enough
after indexing dial:
git commit
If the index is not empty, then a commit will be made on its basis, after which
user will be asked to comment on the changes made by calling the command
edit (for example, in Ubuntu a simple text editor nano is usually called,
me - emacs). Save, and veil! Commit ready.
There are several keys that simplify git commit:
git commit -a - commit, automatically indexing changes to files
project. New files
will not be indexed! Delete the same files
will be taken into account.
git commit -m "commit comment" - we comment on commit directly from the command line
instead of a text editor.
git commit FILENAME - will index and create commit based on changes
single file.
2.1.5 git reset - return to a specific commit, rollback changes, “hard” or “soft”
In addition to working with the index (see above), git reset allows you to reset the state
project before any commit in history. In git, this action can be two
types: "soft" (soft reset) and "hard" (hard reset).
"Soft" (with the key "--soft") cuts will leave your index and the whole tree intact
files and project directories, will return to work with the specified commit. Other
in words, if you find an error in a commit you just made or
comments to it, it is easy to rectify the situation:
- git commit ... - incorrect commit;
- git reset --soft HEAD ^ - go to work on an already committed commit,
saving all project status and indexed files
- edit WRONGFILE
- edit ANOTHERWRONGFILE
- add.
6.1. git commit -c ORIG_HEAD - return to the last commit, will be prompted
edit his message. If the message remains the same,
just change the case of the key -c:
6.2. git commit -C ORIG_HEAD
Pay attention to the designation HEAD ^, it means "contact ancestor
last commit. The syntax for this relative addressing is described in more detail.
will be lower in the section “Hashes, tags, relative addressing”. Respectively,
HEAD - link to the last commit. Reference ORIG_HEAD after a soft reset
points to the original commit.
Naturally, you can return to a great depth of commits,
"Hard" rezet (key --hard) is the command that should be used with
caution. Git reset --hard will return the project tree and index to the state
corresponding to the specified commit, deleting changes to subsequent commits:
git add.
git commit -m "destined to death"
git reset --hard HEAD ~ 1 - no one will ever see this shameful commit.
git reset --hard HEAD ~ 3 - or rather, the last three commit. No one. Never.
If the command reaches the branch point, the commit will not be deleted.
For commands to merge or siphon recent changes from a remote repository
examples of the rezet will be given in the relevant sections.
2.1.6 git revert - cancellation of changes made in the past by a separate commit
There may be a situation in which you want to undo the changes made by an individual
by commit Git revert creates a new commit that applies inverse changes:
git revert config-modify-tag - cancel a commit marked with a tag.
git revert 12abacd - cancel a commit using its hash.
To use the command, it is necessary that the project status does not differ from
the state recorded by the last commit.
2.1.7 git log - a variety of information about commits in general, for individual files and different depths of immersion in history
Sometimes you need to get information about the history of commits, commits that changed
separate file; commits for a certain period of time and so on. For these
The git log command is used for targets.
The simplest example of use is a short reference for all
commits that have touched the currently active branch (about branches and branching
You can find out more in detail in the section Branching and Merging):
git log
Get detailed information about each in the form of patches on the files from commits
by adding the -p (or -u) switch:
git log -p
Statistics of file changes, such as the number of changed files entered into them
lines, deleted files is called by key --stat:
git log --stat
For information on creating, renaming, and file access rights, the key is responsible.
--summary:
git log --smary
To study the history of a single file, it is enough to specify as a parameter
his name (by the way, in my old version of git, this method does not work,
Be sure to add "-" before the "README"):
git log README
or, if the git version is not quite fresh:
git log - README
Further, only the more modern version of the syntax will be given. maybe
indicate the time starting at a specific moment (“weeks”, “days”, “hours”, “s”
and so on):
git log --since = "1 day 2 hours" README
git log --since = "2 hours" README
git log --since = "2 hours" dir / - changes regarding a separate folder.
You can build on the tags:
git log v1 ... - all commits, starting with the tag v1.
git log v1 ... README - all commits, including changes to the README file, starting with
v1 tag
git log v1..v2 README - all commits, including changes to the README file, starting with
tag v1 and ending tag v2.
Creating, listing, assigning tags will be given in the appropriate
section below.
Interesting features on the format of the output command provides key - pretty:
git log --pretty = oneline - will output a hash to each of the commits.
(here - the unique identifier of each commit, more details below).
git log --pretty = short - concise information about commits, are given only
author and comment
git log --pretty = full / fuller - more complete information about commits named
author, comment, date of creation and making commit
In principle, the output format can be determined independently:
git log - pretty = format: 'FORMAT'
Format definitions can be found in the git log section of the Git Community Book.
or help. A handsome ASCII graph of commits is output using the key.
--graph.
2.1.8 git diff - differences between project trees; commits; state index and any commit.
A kind of subset of the git log command can be considered the git diff command,
defining changes between objects in a project: trees (files and
directories):
git diff will show changes not made to the index.
git diff --cached - changes made to the index.
git diff HEAD - changes in the project compared to the latest commit
git diff HEAD ^ - last but one commit
You can compare the "heads" of the branches:
git diff master..experimental
Well, or an active branch with any:
git diff experimental
2.1.9 git show - show changes made by a separate commit
You can see the changes made by any commit in history using the git command.
show:
git show COMMIT_TAG
2.1.10 git blame and git annotate are helper commands that help track file changes
When working in a team, it is often required to find out exactly who wrote the specific
code. It is convenient to use the git blame command, which displays line-by-line information about
Last commit, touching the line, author name and commit hash:
git blame README
You can also specify specific lines to display:
git blame -L 2, + 3 README - displays information on three lines, starting with the second.
The git annotate command works similarly, displaying both strings and information about
kommitah, their touched:
git annotate README
2.1.11 git grep - search for words by project, project status in the past
git grep, in general, simply duplicates the functionality of the famous Unix
teams. However, it allows words and their combinations to search in the past of the project, that
It is very useful:
git grep tst - search for the word tst in the project.
git grep -c tst - count the number of references to tst in the project.
git grep tst v1 - search in the old version of the project.
The command allows to use logical AND and OR:
git grep -e 'first' --and -e 'another' - find the lines where the first is also mentioned
the word and the second.
git grep - all-match -e 'first' -e 'second' - find the lines where it occurs though
would be one of the words.
2.2 Branching
The branching and merging operations are the heart and soul of git, it is these capabilities that make such
convenient work with the system.
2.2.1 git branch - creating, listing and deleting branches
Working with branches is a very easy procedure in git, all the necessary mechanisms.
concentrated in one team:
git branch will simply list existing branches, marking the active one.
git branch new-branch - will create a new branch new-branch.
git branch -d new-branch - will remove a branch if it
was flooded (merged) with
resolution of possible conflicts in the current.
git branch -D new-branch will remove the branch
anyway .
git branch -m new-name-branch - rename the branch.
git branch - contains v1.2 - will show those branches among which there are ancestors
certain commit.
2.2.2 git checkout - switching between branches, extracting individual files from the commit history
The git checkout command allows you to switch between the latest commits (if
simplified) branches:
checkout some-other-branch
checkout -b some-other-new-branch - will create a branch in which it will happen
switching.
If there were any changes in the current branch compared to the last commit in
branch (HEAD), the command will refuse to switch in order not to lose
produced work. Ignore this fact allows the -f switch:
checkout -f some-other-branch
In the case when the changes must still be saved, use the -m switch. Then the team
before switching, will try to upload changes to the current branch and, after
resolve possible conflicts, switch to new:
checkout -m some-other-branch
To return the file (or just pull it out from the past commit) allows a command like this:
git checkout somefile - return somefile to the state of the last commit
git checkout HEAD ~ 2 somefile — return somefile to the state two commits back along the branch.
2.2.3 git merge - merge branches (resolution of possible conflicts).
Merging branches, as opposed to the usual practice of centralized systems, in git
happens almost every day. Naturally, there is a convenient interface to
popular surgery:
git merge new-feature - will try to merge the current branch and the new-feature branch.
In the event of a conflict, commit does not occur, but on problem files
special labels are placed a la svn; the files themselves are marked in the index as
"Unmerged". Until the problems are resolved, commit
will be impossible.
For example, a conflict occurred in the TROUBLE file, which can be seen in git status:
git merge experiment - a failed merge attempt occurred.
git status - we look at problem places.
edit TROUBLE - solve problems.
git add. - we index our changes, thereby removing tags.
git commit - commit commit merge.
That's all, nothing complicated. If during the resolution process you decide not to allow
conflict, just dial:
git reset --hard HEAD - this will return both branches to their original states.
If the merge commit was done, use the command:
git reset --hard ORIG_HEAD
2.2.4 git rebase - building a flat line of commits
Suppose the developer started an additional branch to develop a separate
possibilities and made several commits in it. At the same time for any
The reason for this was that commits were also made in the main branch: for example, there were
flooded with changes from a remote server; or the developer himself committed in it
commits.
In principle, you can do the usual
git merge . But then the line itself becomes more complicated.
development, which is undesirable in too large projects where
a lot of developers.
Suppose there are two branches, master and topic, each of which had quite a few commits since the moment of branching.
The git rebase command takes commits from the topic branch and overlays them on the last commit of the branch.
master:
- git-rebase master topic - a variant that explicitly states what and where
is applied.
- git-rebase master - currently superimposed on master
branch.
After using the command, the story becomes linear. In the event of
concurrency overlapping commits
the work of the team will stop, and in problem areas of the files will appear
corresponding tags. After editing - conflict resolution - files
should be indexed with git add and continue overlaying the following
commits with git rebase --continue. Alternative outputs are commands.
git rebase --skip (skip the commit overlay and go to the next) or git
rebase --abort (cancellation of the command and all changes made).
With the -i (--interactive) switch, the command will work interactively.
mode. The user will be given the opportunity to determine the order of
changes will automatically cause the editor to resolve conflicts and so
Further.
2.2.5 git cherry-pick - applying changes made by a separate commit to the project tree
If you have a difficult development history, with several long branches
developments, it may be necessary to apply changes made
a separate commit of one branch, to a tree of another (currently active).
git cherry-pick BUG_FIX_TAG - changes made by the specified commit will be
applied to the tree, automatically indexed and become a commit in the active
branch.
git cherry-pick BUG_FIX_TAG -n - the key "-n" indicates that changes are necessary
just apply to the project tree without indexing and creating a commit.
2.3 Other commands and capabilities
For the convenience of working with git, an additional concept was introduced: a tag. Besides
further will be explained the need for hashes, and its application; shows the way
access commits using relative addressing.
2.3.1 Hash - unique identification of objects
In git, to identify any objects, a unique one is used (that is, with
tremendous probability of a unique) 40-character hash, which is determined by
a hashing function based on the contents of the object. Objects are everything: commits,
files, tags, trees. Because the hash is unique to the content, such as the file,
it is very easy to compare such files - it’s enough just to compare two lines
in forty characters.
What interests us most is the fact that hashes identify commits. In that
sense hash is an advanced analogue of Subversion revisions. A few examples
using hashes as an addressing method:
git diff f292ef5d2b2f6312bc45ae49c2dc14588eef8da2 - find the difference of the current
project status and commit by number ... Well, you can see how.
git diff f292ef5 is the same, but we leave only the first six characters. Git
understand which commit is in question if there is no other commit with such
start hash.
git diff f292 - sometimes four characters are enough.
git log febc32 ... f292 - we read the log from the commit by commit.
Of course, it’s not as convenient for a person to use hashes as a machine, which is why
entered other objects - tags.
2.3.2 git tag - tags as a way to mark a unique commit
A tag is an object associated with a commit; storing a link to the commit itself, name
author, own name and some comment. In addition, the developer can
leave on such tags own digital signature.
In addition, the git presents the so-called "lightweight tags" ("lightweight
tags "), consisting only of the name and the link to the commit. Such tags are usually
used to simplify navigation through the history tree; it's very easy to create them:
git tag stable-1 - create a “lightweight” tag associated with the latter
by commit If the tag is already there, another one will not be created.
git tag stable-2 f292ef5 - mark a specific commit.
git tag -d stable-2 - remove the tag.
git tag -l - list tags.
git tag -f stable-1.1 - create a tag for the last commit, replace
existing, if any.
After creating a tag, its name can be used instead of a hash in any commands.
like git diff, git log and so on:
git diff stable-1.1 ... stable-1
It makes sense to use regular tags to attach to a commit
information like version number and commentary to it. In other words, if in
comments to the commit write “fixed such and such a bug”, then in the comment to the tag by
The name "v1.0" will be something like "stable version, ready to use":
git tag -a stable - create a regular tag for the last commit; will be called
text editor to write a comment.
git tag -a stable -m "production version" - create a regular tag, immediately specifying
comment argument.
Commands for enumeration, deletion, rewriting for ordinary tags do not differ from
commands for lightweight tags.
2.3.3 Relative Addressing
Instead of revisions and tags, you can rely on another commit name.
the mechanism is relative addressing. For example, you can refer directly to the ancestor
the last commit of the master branch:
git diff master ^
If after the "bird" put a figure, then you can be addressed by several ancestors
merge commits:
git diff HEAD ^ 2 - find changes compared to the second ancestor of the latter
commit in master. HEAD here is a pointer to the last commit of the active branch.
Similarly, a tilde can simply indicate how deep into the history of a branch
need to dive:
git diff master ^^ - what the grandfather of the current commit introduced.
git diff master ~ 2 is the same.
Notation can be combined to get to the desired commit:
git diff master ~ 3 ^ ~ 2
git diff master ~ 6
2.3.4 .gitignore file - we explain git which files should be ignored
Sometimes there are files in the project directories that you don’t want all the time.
see in the git status summary. For example, auxiliary text files
editors, temporary files and other garbage.
Making git status can be ignored by creating at the root or deeper in the tree
(if restrictions should be only in certain directories) file
.gitignore. Ignore file patterns can be described in these files.
specific format.
An example of the contents of such a file:
>>>>>>> Start File
# comments to the .gitignore file
# ignore myself .gitignore
.gitignore
# all html files ...
* .html
# ... except for a certain
! special.html
# do not need objectaries and archives
*. [ao]
>>>>>>>> End of File
There are other ways to specify ignored files that you can learn about.
from git help gitignore help.
3 "Together we are power", or the basics of working with a remote repository
Naturally, most projects still involve work in at least
at least two developers who need to share code. Next will be
lists the commands required for collaborative — possibly remote — work.
3.1 Remote tracking branches
New concept here - remote branches. Deleted branches correspond to any
branch (more often master) on a remote server. One such is created automatically when
create a copy of the remote repository; all commands related to the remote
work, by default they will use this remote branch (usually
called "origin").
Consider these commands.
3.2 git clone - creating a copy of the (remote) repository
To get started with the central repository, you should create a copy
the original project with all its history locally:
git clone / home / username / project myrepo - we clone the repository from the same machine
to the myrepo directory.
git clone ssh: // user @ somehost: port / ~ user / repository - we clone the repository,
using the secure ssh protocol (for which you want to start on your machine
ssh account).
git clone git: // user @ somehost: port / ~ user / repository / project.git / - git has
and own protocol.
3.3 git fetch and git pull - pick up changes from the central repository (from a remote branch)
To synchronize the current branch with the repository, use the git fetch and
git pull.
git fetch - pick changes to a remote branch from the default repository,
main branch; the one that was used in cloning
repository Changes will update the remote branch (remote tracking branch), after
which will need to be merged with the local branch with the git merge command.
git fetch / home / username / project - pick up changes from a specific
repository
It is also possible to use aliases for addresses created by the git remote command:
git remote add username-project / home / username / project
git fetch username-project - pick changes to the address specified
synonym for
Naturally, after evaluating changes, for example, using the git diff command,
create a merge commit with the main:
git merge username-project / master
The git pull command immediately takes away the changes and merges with the active branch:
git pull - pick up from the repository for which remote branches were created by
default
git pull username-project - pick changes from a specific repository.
As a rule, the git pull command is used immediately.
3.4 git push - make changes to the remote repository (remote branch)
After working in the experimental branch, merging with the main,
It is necessary to update the remote repository (remote branch). For this
use the git push command:
git push - send your changes to the remote branch created by
cloning by default.
git push ssh: //yourserver.com/~you/proj.git master: experimental - send changes
from the master branch to the experimental branch of the remote repository.
git push origin: experimental — in the remote repository origin, delete the experimental branch.
git push origin master: master - to the remote master branch of the origin repository (synonym
default repository) local branch branches master.
4 git-o-day
In this section several normal and slightly
less unusual for working with git situations.
4.1 Normal workflow when working with a local repository
Git has extraordinary ease of use, not only as distributed
version control system, but also in working with local projects. Let's break it down
the usual cycle - starting with creating a repository - the git developer’s work on
own personal project:
- mkdir git-demo
- cd git-demo
- git init
- git add.
- git commit -m "initial commit"
- git branch new-feature
- git checkout new-feature
- git add.
- git commit -m "Done with the new feature"
- git checkout master
- git diff HEAD new-feature
- git merge new-feature
- git branch -d new-feature
- git log --since = "1 day"
Let us examine each of the actions.
1-2 - just create a working directory of theproject. 3 - create a repository in the directory. 4 - we index all existingproject files (if, of course, they were in general). 5 - we create the initializingcommit. 6 - new branch, 7 - switching to it (can be done in one stepwith the git checkout -b new-feature command). Next, after working directly with thecode, we index the changes made (8), commit (9). Switch to themain branch (10), look at the differences between the last commit of the active branch and thelast commit of the experimental branch (11). We merge (12) and, if there wereno conflicts, delete the branch that is no longer needed (13). Well, just in case,we estimate the work done for the last day (14).Why exactly? Why abandon the linear model? Even if only becausethe programmer has additional flexibility: he can switchbetween tasks (branches); there is always a “pure pig” at hand - themaster branch ; commits become smaller and more accurate.4.2 Workflow when working with a remote repository
Suppose you and a few of your partners have created a publicrepository to do some kind of common project. What does the mostcommon git model of common work look like ?- git clone http://yourserver.com/~you/proj.git
... it may have been some time.
- git pull
- git diff HEAD ^
- git checkout -b bad-feature
... working for a while.
- git commit -a -m "Created a bad feature"
- git checkout master
- git pull
- git merge bad-feature
- git commit -a
- git diff HEAD^
… , , - . Oops.
- git reset --hard ORIG_HEAD
- git checkout bad-feature
… .
- git -m bad-feature good-feature
- git commit -a -m «Better feature»
- git checkout master
- git pull
- git merge good-feature
- git push
- git branch -d good-feature
So, first of all we create (1) create a copy of the remote repository (bydefault, commands like git pull and git push will work with it). "Pulling" thelatest updates (2); see what has changed (3); create a new branch andswitch to it (4); we index all changes and at the same time create acommit from them (5); switch to the main branch (6), update it (7); wemerge with the bad-feature branch (8) and, after finding and resolving the conflict, we commit themerge (9).After committing a commit, we track changes (10), run, for example,unit tests and with horror find that after a merger, the project collapses on mostof the tests.In principle, tests could be run before the commit, at the time of themerger (between points 8 and 9); then a soft cut would suffice.Thus, it is necessary to make a “hard” (11) reset of the occurred merger, thebranches returned to their original state. Then we switch to the unsuccessfulbranch (12), make the necessary changes and rename the branch (13). Make acommit (14); go to the main branch (15), again we update it (16). This timewithout confrontation, we merge (17), throw changes into the remote repository(18) and delete the branch that is now unnecessary (19). We close the laptop, get dressed and gohome in the morning.5 Conclusion
The topic does not address several important issues, such as the administration of apublic repository, integration with text editors or IDE, theuse of SSH under Linux and Windows; comments are welcome, and especiallyadditions to the git-o-day section.UPD: a note on working with a remote repository. When working with git in terms of administration, creating public repositories, managing access, using encrypted connections, and so on, certain questions may arise; and in this article they are not covered in any way. For example, the above described work with a ready-made remote repository; its deployment is not covered in any way.This is all I am now collecting in a separate topic, which I will throw out here in a week and a half.