Skip to content

Issue workflow policy with GIT

pgagarinov edited this page Feb 24, 2015 · 5 revisions

General information about GIT

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

An algorithmic issue workflow in GIT

A standard issue workflow looks like this:

  1. 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
  2. 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.
  3. If Code Review is not required – go to step 8.
  4. 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.
  5. 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"
  6. 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.
  7. If the source code is good the reviewer marks the pull request as "status:readyForCommit". The reviewer’s copy of the branch is deleted.
  8. The developer extracts the latest changes from the central repository and performs rebasing against remotes/origin/master.
  9. 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.
  10. 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).

An algorithmic issue workflow in GIT commands

All the commands work only with clean repositories – WITHOUT any uncommitted changes.

  1. Creating a new branch
  2. git checkout master - switch to the “master” branch (i.e. changing your current branch to “master”)**
  3. git pull - download the latest changes
  4. git branch <my_branch_name> - create a new branch
  5. git checkout <my_branch_name> - switch to the new branch
  6. Doing development, committing changes, finishing work.
  7. 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>
    1. git fetch --verbose "origin" master:remotes/origin/master - update master
    2. git rebase remotes/origin/master - rebasing against the remote “master” branch
    3. If case there are conflicts – resolve, commit and repeat everything again.
    4. If everything is good – push the branch to the server
    5. git push "origin" <my_branch_name>:<my_branch_name> - send the branch to the server
  8. 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>
  9. git fetch --verbose "origin" master:remotes/origin/master - download the latest changes
  10. git rebase remotes/origin/master - rebase the current branch (development branch) against the fresh master branch.
  11. If case there are conflicts – resolve, commit and repeat everything again.
  12. 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.
  13. 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.*
  14. REVIEW our changes in the master branch – there should be only your changes and NOTHING ELSE.
  15. git push "origin" master:master – push the changes in the local master to the server
  16. If everything is good – remove the development branch
  17. git branch -D <my_branch_name> - remove the local branch
  18. git push "origin" :<my_branch_name> - pushing the deletion to the server for deleting the branch on the server**

The rules of clean commits

All the commits that end up in the central repository should comply with the following rules:

  1. A developer should be registered as a commit author - see a section about initial configuration.

  2. 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>
    
  3. 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.

  4. 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”

  5. Source code structure should be complied with Smart Indent-based style.

  6. 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.

  7. Never commit the commented-out code. Just remote it.

Working under Windows

The most convenient way of working with Git under Windows is using TortoiseGit.

Setting up GIT software

  1. 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.

  2. Install the latest version of TortoiseGit from http://code.google.com/p/tortoisegit/

  3. 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 useremail@alliedtesting.com
    >git config --global core.autocrlf false
    >git config merge.mergeoptions "--no-ff"
    

Cloning the repository

In the folder where all the projects will reside

  1. Peform Right click→TortoiseGit→Clone enter a central repository address http://username@SERVER:PORT/REPOSITORY.git
  2. Switch to the master branch.

Basic Git operations with TortoiseGit

  1. 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.

  2. 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

  3. 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.

  4. 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.

  5. 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, then right click → Delete Remote Branch For local branch, correspondingly, Delete Branch.

  6. 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.

  7. 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.

Standard issue workflow with TortoiseGIT

  1. 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
    
  2. 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.
    
  3. Sending a branch to a central repository This step needs to be performed in one of the following cases:

    1. the task is seemingly completed
    2. At the end of each day (to have a backup on a server)
    3. To show the changes to a reviewer
      1. Menu → TortoiseGit → Push
      2. Choose master and then current branch name in “local” field.
      3. Remote is filled automatically.
      4. 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.
  4. 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
    
  5. 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
  1. 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