📜 ⬆️ ⬇️

Git on fingers (for transferring from SVN)

A year ago, the team and I decided to switch from SVN to Git. Why it was necessary - I will not write, because This topic has already been written a lot. And I want to describe typical work algorithms that are understandable to a person who has used SVN for a long time. Below is a memo written for the team a year ago to make it easier to migrate. I hope someone will come in handy.

A little about the Git device (simplified).


Git is a distributed VCS. This means that we are not working with one repository on the server, but each has a local copy of the repository. Accordingly, operations such as checkout and commit are performed with a local repository. With each other (or with the fact that on the server) repositories are synchronized by specially designed commands pull (fetch) and push.

It's comfortable. This allows you to commit as often as you like, even if there is currently no connection to the server.
')
An important advantage of Git is a clear work with branches and a convenient merge mechanism. In SVN, we usually worked with one branch of the trunk (in git, the branch with which we work by default is called master). The same branch was poured on the production. The main inconvenience here is that if we make any changes, or develop a new functionality, we have to either sit and not commit until the task is completed until the end, or (if we need the help of a colleague), commit the unfinished the functionality is as it is, making the trunk thus unsuitable for casting to production. This is especially unpleasant if the new functionality is being done for more than one day, and at this time there is a need to fix something urgently in the working system.

It should be noted that in SVN, of course, there are branches, but they are made, apparently, for another, and therefore are not well adapted to be merged into the trunk. In git, the merge operation is done elegantly and conveniently, which allows us to significantly change the workflow to a more optimal one.
Another difference in git is that it does not store changes, but the current state of the project at any given time.

The main thing.


  1. master is the branch that should always, at any (!) moment, be ready for deployment to production.
  2. Therefore, we never make new features and bugfixes immediately in master, we use branches for this.
  3. It will be useful to study the articles 1 2 3 4 and, perhaps, even the Git book . In article number 2 oleganza formulated a very important principle: one feature - one branch. One bugfix (if it is supposed longer than two kommit) - one branch. One experiment - one branch. One feature inside the experiment is a branch from a branch.
  4. Always write intelligible comments to commits.
  5. After the feature (bugfix) is written, tested and ready for production, we merge the master branch.

When can we commit directly to master? Only when we are sure that our small change will definitely solve the problem and not create new ones. When you are sure that you will not need to do bugfix for bugfix later. At the same time, the changes should be minimal.

Therefore, a good rule would be, nevertheless, the creation of a separate branch (except for very simple cases).

Customization.


$ git config --global user.name "First Last"
$ git config --global user.email "email@example.com"
$ git config --global color.diff "auto"
$ git config --global color.status "auto"
$ git config --global color.branch "auto"

Additionally, you can configure the shell-alias as described in article 2.

Standard workflow.


Step 1. Getting started - repository cloning.

It is assumed that you already have and configured gitosis, on which the project lies.

git clone gitosis@git.yourserver.com:yourproject.git - this step is done once.

The result will be yourproject folder with the project on your hard drive. The clone command does the following: clones the remote repository into a new folder (yourproject in this case), creates remote-tracking branches for all branches of the remote repository in the local repository, creates a local copy of the currently active remote branch and makes a checkout of it.

Step 2a. Writing a new code or bugfix.

1. git branch - see which branches we currently have in the repository. Immediately after cloning, you will only see one active branch in the current repository, a branch (in our case, this is the default master, since the remote repository is located on the server and nobody switches branches in it). If there are other branches in the repository, you can see them by adding the -a key (the active branch is indicated with an asterisk):

$ git branch -a
* master
origin/HEAD
origin/master
origin/feature


2. Suppose we want to implement a feature. Create a locally new branch using the branch command. With the checkout command you can switch between branches:

$ git branch feature
$ git checkout feature
Switched to branch "feature"


Or, which is the same, only shorter:

$ git checkout -b feature
Switched to a new branch "feature"


3. In git there is such a thing as an index. For example, the commit command adds to the repository only those files that are currently in the index. Therefore, during the work we do not forget to add (git add) or delete (git rm) files to / from the repository index. Note that, unlike SVN, if you change a file, you need to re-add it to the index with the git add command.

For example:

$ git add file1 file2
$ $ git commit -m "adding file1 & file2"
Created initial commit 8985f44: adding file1 & file2
2 files changed, 2 insertions(+), 0 deletions(-)
create mode 100644 file1
create mode 100644 file2


There is a utility here: the git add command. adds all untracked files to the index (recursively), and the commit command’s -a option allows you to automatically add all modified (but not new!) files.

The current state of the index can be viewed with the git status command:

$ git status
# On branch feature
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: file1
# new file: file2
#


The commits in the repository are viewed with the git log command.

4. If we want to develop a new functionality together, we need to publish our branch on the server so that others can work with it. Here is how it is done (before this, all changes in this thread must be committed):

$ git push origin feature:refs/heads/feature
Counting objects: 4, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 273 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To gitosis@git.yourserver.com:yourproject.git
* [new branch] feature -> feature


(in new versions of git, you can simply git push origin feature: feature)

The push command sends changes to the remote repository (origin) from the local branch of feature to the remote branch of the feature, having first created it there (refs / heads / feature is needed just to create the branch). In the future, you can use the git push origin feature (by default, git push publishes changes from all branches).

But with this method of publishing, the link between the local version of the branch and the published one is not established. Those. if someone commits changes to this remote branch and you do git pull, then there will be an error:

$ git pull
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 2 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (2/2), done.
From gitosis@git.yourproject.com:yourproject
d23a39c..b0a86e0 feature -> origin/feature
You asked me to pull without telling me which branch you
want to merge with, and 'branch.feature.merge' in
your configuration file does not tell me either. Please
name which branch you want to merge on the command line and
try again (eg 'git pull <repository> <refspec>').
See git-pull(1) for details on the refspec.

If you often merge with the same branch, you may want to
configure the following variables in your configuration
file:

branch.feature.remote = <nickname>
branch.feature.merge = <remote-ref>
remote.<nickname>.url = <url>
remote.<nickname>.fetch = <refspec>

See git-config(1) for details.


Those. git doesn’t know which branch to use to him. Therefore, you can either point it out with your hands:

git pull origin feature

Or register in the config:

git config branch.feature.remote origin
git config branch.feature.merge refs/heads/feature


In addition, you can use the William Morgan script and do the git publish-branch feature instead of everything else.

Step 2b. How to join the work on the branch.

It is assumed that you have already cloned your repository.
The main thing here is to connect the remote branch correctly. This can be done with the --track option of the git checkout command. The command below creates a local feature branch and connects it to the remote origin / feature branch, and then switches to that branch.

$ git checkout --track -b feature origin/feature
Branch feature set up to track remote branch refs/remotes/origin/feature.
Switched to a new branch "feature"


This is important at this stage, because simply the pull command will send a remote branch to us in the master, and this is not what we need.

Next, you can work as described in step 2a, synchronizing the repository in each branch with the git pull and git push commands.

Step 2c. How to switch to another branch when there are changes in the current and commit them early.


Sometimes it is necessary to urgently switch to another branch, for example, for bugfixes. But the full commit in this thread is still not enough. There is a git stash command for this:

$ git status
# On branch feature
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: somefile
#
$ git stash
Saved working directory and index state "WIP on feature: b0a86e0... blabla"
HEAD is now at b0a86e0 blabla
(To restore them type "git stash apply")
$ git status
# On branch feature
nothing to commit (working directory clean)


Now you can safely switch to another branch and work there.

Upon returning to this thread, you need to do git stash apply:

$ git stash apply
# On branch feature
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: somefile
#


Step 3. merge and rebase.

You will need to use any of these commands in 2 cases:
  1. You want to add the latest changes from master to your branch;
  2. You want to merge your branch in master.

The general rule is: if we work with a branch on our own and do not plan to publish it on the server, then it is more profitable to use rebase. If we publish a branch with the push command, then it is NOT possible to use the rebase, otherwise we automatically disable the work of our colleagues. The difference between merge and rebase is well illustrated in the Git book illustrations: merge and rebase . Briefly: rebase remembers commits from a branch in the form of patches, "rewinds" the current branch (as if there was no branch) and applies patches, making them in the form of commits. Unlike rebase, merge merges two branches into one.

Examples:

We add changes from master to the work branch feature, we do not publish the feature branch anywhere, we work with it only locally:

$ git checkout feature
Switched to branch "feature"
$ git rebase master
First, rewinding head to replay your work on top of it...
HEAD is now at 89f6a20 file2
Applying feature1


We merge changes from the work branch feature in master, the feature branch has never been published anywhere, none of our colleagues have worked with it:

$ git checkout master
Switched to branch "master"
$ git rebase feature
First, rewinding head to replay your work on top of it...
HEAD is now at 9bfac0a feature1
Applying file2


We add changes from master to the work branch feature, the feature branch is published on a remote repository, and our colleagues also work with it:

$ git checkout feature
Switched to branch "feature"
$ git merge master
Merge made by recursive.
file2 | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 file2


Merge changes from the work branch of feature to master, the branch feature was published on a remote repository for collaboration:

$ git checkout master
Switched to branch "master"
$ git merge feature
Merge made by recursive.
feature1 | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 feature1


Step 4. Deleting a branch.

After we finished working with the branch and merged the changes into master (or into another branch), we can delete the branch.

To delete a local branch:

$ git branch -d feature
Deleted branch feature.


To remove the remote tracking branch:

$ git push origin :feature
- [deleted] feature


That seems to be all. This should be enough for the first time when migrating from SVN to Git.

Special thanks to habraiser mironov_anton for all sorts of additions and improvements to this text.

Source: https://habr.com/ru/post/68341/


All Articles