Issue workflow policy with GIT - SystemAnalysisDpt-CMC-MSU/ellipsoids GitHub Wiki
You can always read about GIT in details at http://book.git-scm.com/ or http://git-scm.com/book/ru
Git is DVCS (Distributed Version Control System) which means that every working copy contains all commits, history, branches and every other information necessary for development without any connectivity to a remote server(s). For synchronization between different copies of a repository a developer would need to use “pull” command for copying remote changes to a local repository and “push” for copying local changes to a remote repository. In GIT every commit has a unique ID in a form of hash string linked to all the files changed (not changes in the files but actual files) in a commit.
Every commit has a single parent commit and possibly – merge source commit. Thus all the commits form a tree of file sets while a “branch” is just a pointer to a specific commit in this tree. This means that creating a branch is just a giving a name to a certain commit. Also this means that merging of two branches one of which starts at the end of the other requires just moving a pointer to a new commit (such operation is called “Fast-Forward’).
Keeping a structure of main branch (master) flat requires a special technique based on rebasing of branches before merge and then merging with no fast-forward.
Rebasing assumes changing a branch’s parent to the new origin. All the changes introduced in a branch are reverted, then stored as the changes introduced in each of the commits; after that the branch’s point is moved to a new origin (commit) in a commit tree and the stored changes are applied on the top of this commit. Assuming there are no conflicts the branch after rebasing is a set of changes based on the new origin.
An attempt to merge the rebased branch against the original branch would cause just moving the head pointer of the original branch to a new place and we would loose the information that our branch ever existed. This is the exact reason why merging with no fast-forward should be used after rebasing. No fast-forward ensures that even if a new branch starts where a previous branch ends a special merge-commit is created. This commit points to a place which corresponds to merging our current branch with a different branch.
You can find more information about rebasing here: http://git-scm.com/book/en/Git-Branching-Rebasing
A standard issue workflow looks like this:
- Create a new branch based on last copy of master branch. A new branch’s name should contain a commit name and issue number in github. Example:
issue_14_pgagarinov
- All the changes are made inside this branch. Every atomic change (adding a new function, changing API of a single class in all the places) should be committed separately. This allows for separating the logically unrelated changes, simplifies reading and making sure that development is done in a correct way.
- If Code Review is not required – go to step 8.
- Once source code in the branch is changed, covered with tests and all the changes are committed the branch is rebased against master and is pushed into a central repository.
- GitHub pull request for the branch is created. The pull request should be assigned to the reviewer. Status of the pull request should be "status:readyForReview"
- The reviewer takes the branch from the central repository, reads the source code and makes sure that it works properly. If the source code requires fixing – the pull request in GitHub is marked as "status:reviewFailed". The developer repeats steps 4 and 5.
- If the source code is good the reviewer marks the pull request as "status:readyForCommit". The reviewer’s copy of the branch is deleted.
- The developer extracts the latest changes from the central repository and performs rebasing against remotes/origin/master.
- The developer switches to the “master” branch and merges the changes from the developer’s branch. When this is done “no-fast-forward” flag has to be switched on.
- After merging with master the developer pushes the updated master into the central repository, deletes a local copy of his/her branch and also deletes the branch remotely (pushes the deletion of the branch into the central repository).
All the commands work only with clean repositories – WITHOUT any uncommitted changes.
- Creating a new branch
-
git checkout master
- switch to the “master” branch (i.e. changing your current branch to “master”)** -
git pull
- download the latest changes -
git branch <my_branch_name>
- create a new branch -
git checkout <my_branch_name>
- switch to the new branch - Doing development, committing changes, finishing work.
- If a source code review is required – rebase and push the branch to the server. All commands are executed from the development branch <my_branch_name>
-
git fetch --verbose "origin" master:remotes/origin/master
- update master -
git rebase remotes/origin/master
- rebasing against the remote “master” branch - If case there are conflicts – resolve, commit and repeat everything again.
- If everything is good – push the branch to the server
-
git push "origin" <my_branch_name>:<my_branch_name>
- send the branch to the server
-
- If source code is recognized as good by the reviewer - update the master branch, rebase, merge into the master, push. All the commands are executed from the development branch <my_branch_name>
-
git fetch --verbose "origin" master:remotes/origin/master
- download the latest changes -
git rebase remotes/origin/master
- rebase the current branch (development branch) against the fresh master branch. - If case there are conflicts – resolve, commit and repeat everything again.
-
git checkout --force --track -B master remotes/origin/master
- rewrite the local master branch with the remote master branch and make the master current branch. -
git merge --no-ff <my_branch_name>
- merge the changes from the branch into the master. If everything is done correctly there should be no conflicts at this stage with 100% guarantee.* - REVIEW our changes in the master branch – there should be only your changes and NOTHING ELSE.
-
git push "origin" master:master
– push the changes in the local master to the server - If everything is good – remove the development branch
-
git branch -D <my_branch_name>
- remove the local branch -
git push "origin" :<my_branch_name>
- pushing the deletion to the server for deleting the branch on the server**
All the commits that end up in the central repository should comply with the following rules:
-
A developer should be registered as a commit author - see a section about initial configuration.
-
Commit message should contain a short description of the change and an issue number in GitHub:
Issue # BugFix: <description> BugFix: <description> Enhancement: <description> Enhancement: <description>
-
Commit should not contain the changes not related to the issue. If your IDE, OS or some library creates technical files just either add them to .gitignore or manually make sure that they are not made a part of the commit.
-
Commit should not add/remove empty strings, change blank space to tabs or vice versa – change a number of spaces etc. nowhere except for the cases when this is directly related to the issue. All these changes are normal as part of intential refactoring but it is not ok to introduce such changes in other cases with one exception: internal file format doesn’t correspond to the standard introduced by “Smart Indent”. To apply Smart Indent just select all the code by pressing “Ctrl+A” and then press “Ctrl+I”
-
Source code structure should be complied with Smart Indent-based style.
-
Minimize potential conflicts. A newly added source code should be formatted in a such way that doesn’t lead to a lot of conflicts if this code is modified later.
-
Never commit the commented-out code. Just remote it.
The most convenient way of working with Git under Windows is using TortoiseGit.
-
Install the latest version of msysGit from http://msysgit.github.io/. Make sure to have “Git Bash here” and “Run Git from the Windows Command Prompt” options checked.
-
Install the latest version of TortoiseGit from http://code.google.com/p/tortoisegit/
-
Execute the following command from Git Bash:
>git config --global core.editor notepad.exe >git config --global user.name “Name Familyname” >git config --global user.email [email protected] >git config --global core.autocrlf false >git config merge.mergeoptions "--no-ff"
In the folder where all the projects will reside
- Peform
Right click→TortoiseGit→Clone
enter a central repository addresshttp://username@SERVER:PORT/REPOSITORY.git
- Switch to the master branch.
-
Update the current branch from the central repository:
ContextMenu->Pull
Please do not forget to specify which branch you want to update because GIT always updates only a single branch at a time. -
Sending the current branch into the central repository:
Menu→Push
Then in “local” field choose master and then a branch name you want to push. Name of the remote is filled automatically. Name of the remote branch should be identical to the name specified in “local” field -
Switching to a different branch:
Menu→Switch/Checkout
In “Branch” choose <required_branch> «Create new branch» - allows to create a new branch and do the switch as a single step. -
Creating a new branch
Context menu→TortoiseGit→Create Branch
In Name are in Branch field enter a new branch name If you want the new branch to base on the current branch - in Base On choose HEAD If you want to base the new branch on master – choose Branch and then – master from the drop down list. Check [v] Switch to new branch to switch to the new branch momentarily. -
Deleting a branch
Menu with Shift button pressed → TortoiseGit → Browse Reference
In heads section you’ll see local branches and in remotes\origin section – remote branches. Choose the branch you want to delete, thenright click → Delete Remote Branch
For local branch, correspondingly, Delete Branch. -
Merging a branch with the current branch
Context menu → TortoiseGit → Merge
Choose Branch which needs to be merged with the current branch Check «No fast forward» option – it is MUST, Merge message should not be edited. -
Reviewing and saving changes Modified files are marked in red with exclamation signs. To get a general picture of changes use,
Menu→TortoiseGit -> Diff
You’ll see a list of changes at the bottom of the window. You should always check «View patch» option and make sure that all the changes comply with “The rules of clean commits” – see above.
-
Start working on a new issue. The following steps needs to be done before you start working on a new issue. The tree should not contain any local changes.
Menu → TortoiseGit → Switch/Checkout, Branch: master Menu → TortoiseGit → Pull Menu → TortoiseGit → Create Branch Name Branch: name of the new branch Base On: HEAD (master) [x] Switch to new branch
-
Commit a next piece of work This step needs to be done after each logically self-contained set of changes.
Menu → Git commit -> “branch name” Select the files required for the commit It is necessary to select «View Patch» and make sure that all the changes comply with “The rules of clean commits” In message field describe the changes following the format defined by the rules.
-
Sending a branch to a central repository This step needs to be performed in one of the following cases:
- the task is seemingly completed
- At the end of each day (to have a backup on a server)
- To show the changes to a reviewer
Menu → TortoiseGit → Push
- Choose master and then current branch name in “local” field.
- Remote is filled automatically.
- The remote branch name should be identical to the name specified in “local” field Please do not push after each commit as this requires access to a remote server and thus spends your time for nothing.
-
Rebasing against master This step is performed prior to sending the seemingly finished task to the server when all the commits are done.
Menu → Git Sync Local branch: master Remote branch: master Right arrow next to the first button (Pull by default), Fetch Меню → TortoiseGit → *Rebase Branch: current branch name UpStream: remotes/origin/master If there are conflicts – have them resolved using «Conflict File» section Upon clicking on a conflicted file the following choices are available Edit Conflicts – for each conflicting part of the file you can choose which part version of the change is to use Resolve Conflicts Using theirs – use a version from master mine – use a version from the current branch Open – open in an editor and resolve manually After resolving the conflict Resolve button needs to be pressed. Once all the conflicts are resolved press Commit button. Once rebasing is done press Done
-
Saving temporary changes This step is needed if you want to stop working on a current task for a short period of time (to review changes in a different branch for 2 minutes for instance).
Menu → TortoiseGit → Stash Save
Once this is done the tree is clean and you can switch to a different branch or master, do some work, and load the changes after switching back to the initial branch
Menu → TortoiseGit → Stash Pop
This command restores a previous state of your branch. 6. «Saving changes for a longer period of time» Needed either at the end of day to back up intermediate changes OR when switching to a different task is required (assume the task takes more than 5-10 minutes to complete).
Menu → Git Commit -> “branch”
Select absolutely all the changes (Select/Deselect All)
In the commit message write «Partial commit»
Later for reverting exactly to the same state you need to switch working branch and do the following
Menu → TortoiseGit → Show Log
Select a commit that precedes the commit marked as «Partial commit»
Right click → Reset <branch> to this
Reset type: Mixed
-
Reviewing the branch This step is performed on a clear tree (save changes temporarily according to step 5 if needed)
Menu → TortoiseGit → Switch/Checkout Branch: master Menu → TortoiseGit → Pull Menu → TortoiseGit → Switch/Checkout Branch: remotes/origin/<needed branch> [x] Create new branch: <needed branch> [x] Force [x] Track [x] Override branch if exists Menu → TortoiseGit → *Rebase Branch: <needed branch> UpStream: master The branch should be «up to date» or should be rebased without any conflicts. == Analyze the changes by looking at the log Menu → TortoiseGit → Show log and look through all the changes from master up to the last one == See the overall difference against master Menu → TortoiseGit → Diff with previous version Version 1: HEAD Version 2: master