Git

Review your changes in the code before the commit

2017-03-26 DSP2017, Git 2 comments

Most of the people use git as follows.

  1. they create a feature branch
  2. they make some changes
  3. they add all the changes: git add -A
  4. they commit changes: git commit -m "I've done changes"
  5. they push it: git push

There’s a problem with such approach. When we created a lot of changes, it may happen that we forgot to delete something and we pushed some garbage to the remote repository.

It’s better to review our own changes before the commit.

When we’ve done some changes, instead of typing git add -A, we can type git add -p. It will allow us to review our own changes and approve or disapprove them with typing y (yes) or n (no).

After that process, all changes approved by us are “staged”. Changes, which are not approved are not staged. We can discard unstaged (and also unapproved) changes by typing git checkout -- .. After that, our repository is clean – unwanted changes are discarded & changes, which we approved are staged. Next, we can simply commit & push our changes to the remote repository.

This approach is, in my opinion, very useful and helps to avoid pushing unwanted code to the remote repository, what will hopefully make your co-workers happy.

My approach to Git aliases

2017-03-12 DSP2017, Git No comments

While we are working with Version Control Systems like Git, it’s good to adapt them to our needs to perform daily work in a more productive way. People often create so-called Git aliases, which are shortcuts for longer commands. E.g. you can edit your .gitconfig file, which is usually located in your home directory and place a few aliases in the [alias] section. For example:

[alias]
  ls = log --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate

Then you can type: git ls in your Git repository to see pretty Git log.

Sometimes people go further and create many more aliases like:

cp = cherry-pick
st = status
cl = clone
ci = commit
co = checkout
br = branch

and so on. I’ve seen configurations containing about 20 aliases or more consisting of shortcuts, which have 2 or 3 letters. Usually, we don’t use 20 commands every day. I can remember e.g. 5 shortcuts, but I don’t want to remember more.

Instead of alias:

lcm = log -1 --pretty=%B

I prefer:

last-commit-msg = log -1 --pretty=%B

When I’m using terminal on Linux or macOS, I have type hinting, so I can type: git la, hit Tab and terminal will autocomplete my command to git last-commit-. Then I can hit Tab again and I can choose one of my aliases and select one by hitting Enter.

git alias hints in unix terminal

Now, I don’t have to remember all of my aliases. I treat my .gitconfig file as a documentation. Whenever I want to browse aliases, I can type git list-aliases (it’s also an alias to !git config -l | grep alias | cut -c 7- | sort) and if I want to find aliases related to diffs, I can type git list-aliases | grep diff. I also have more descriptive aliases like:

undo-last-commit = reset --hard HEAD^

so I know what this command actually does.

Morover, divided my aliases into separate sections and marked these sections with comments. The sections are as follows:

  • showing metadata
  • showing urls
  • showing commits, logs & branches
  • ignoring files
  • adding & reviewing changes
  • resetting and reverting changes
  • merging changes
  • branching
  • showing diffs
  • searching files

It allows me to keep my aliases in more organized way. It’s useful when our .gitconfig file “lives” and we update it during the work day if we need to.

Maybe this approach won’t be the best way of using Git for everyone, but it works for me and allows me to solve my daily tasks easier and faster.

You can find complete source of my .gitconfig file in my dotfiles repository at https://github.com/pwittchen/dotfiles/blob/master/.gitconfig.

Further reading

Happy coding!

Working with different Git configs

2017-03-10 DSP2017, Git, Linux, macOS No comments

Short introduction

Sometimes people need to specify multiple values for single .gitconfig file or they want to share just part of the configuration between two machines. There are different approaches for that. I can show you mine.

Different configs for different Operating Systems

On my private computer, I use Linux. I use Git for my private projects and I use my private e-mail address there. At the same time, I use Git at work on macOS with exactly the same Git configuration, but with a different e-mail address. How to deal with that?

In my .gitconfig file, I set my private e-mail address, which is used by default. In my .zshrc file, I created two aliases:

alias setupGitPersonal="git config --global user.email \"piotr@wittchen.biz.pl\""
alias setupGitForWork="git config --global user.email \"piotr.wittchen@sap.com\""

Hint: If you want to configure more stuff than just an e-mail, you can do it in the appropriate alias or you can create separate shell scripts for that and place them in /usr/local/bin/ directory.

Then, on Linux, I don’t have to do anything and my private e-mail address is used out-of-the-box.
On macOS, I do the following trick in .zshrc file:

if [ `uname` = "Darwin" ]; then
  setupGitForWork

  # rest of the macOS config goes here...
fi

After that, every time I start terminal on macOS, it automatically sets up my e-mail address to the one I use at work and keeps my .gitconfig file updated.

Hint: If you don’t use zsh, instead of .zshrc file, edit .bashrc file.

Different configs for the same OS on two machines

If you’re using different configs on the different machines with the same OS, you can try another trick. Create configuration file – e.g. .machine_name in your home directory. Setup one name on one machine and another name on a different machine. Next, include this file in your .zshrc or .bashrc file, perform appropriate check and load different settings basing on variable name.

. ~/.machine_name

if [ $machineName = "workMachine" ]; then
  setupGitForWork
else
  setupGitPersonal
fi

Contents of the .machine_name file are simple:

machineName="workMachine"

Different configs on the single machine with one OS

In such case, we are supposed to perform the manual switch. We can use aliases provided above. When we want to have personal settings, we can open terminal and type setupGitPersonal. When we want to apply work settings, then we can type setupGitForWork.

Summary

As we can see, keeping different configs for different machines or operating systems and changing them depending on our needs is not so hard. I hope these ideas will help you to manage your configs.

Automate boring stuff

2017-01-01 Bash, Git, Python No comments

Introduction

In my current company all the people who perform creative work (mostly programmers) need to prepare so-called PKUP report. PKUP stands for Podwy┼╝szone Koszty Uzyskania Przychodu in the Polish language. It’s legal regulation in Poland, which allows paying a lower income tax due to the particular type of work. For the regular employee, it means that he or she will simply get a bit higher salary per month.

How the report looks in practice?

As a programmer, I simply create software as a source code. Added, removed and modified lines of code in the existing codebase are treated as my creative work. Luckily, we use Git so I can generate *.diff files from the Git repositories I’m contributing to. Besides that, I need to prepare document as a *.docx file with a short description of my work. My tasks look different every month, but report actually looks almost the same every month. Preparing this report is boring and repeatable stuff.

Let’s automate it!

Generating *.diff files from Git repos

I simply created a shell script, which goes through predefined project directories and saves *.diff files with names the same as project directory with changes performed by me from the 20th day of the last month until now.

Generating *.docx document

Next, I created a python script, which is parametrized and used by shell script. It uses python-docx library for generating *.docx report. I’ve chosen such option, because it’s one of the simplest solutions I’ve found and it’s lightweight. Moreover it can be easily used on Unix systems and integrated with shell scripts.

Personalization

I wanted to make a script available and usable for everyone, so I created .pkup.conf file, which is responsible for personalization and configuration of the script. I think, it looks pretty straightforward.

yDEV_PROJECTS_DIR=$yHYBRIS_SRC
yDEV_PROJECTS_LIST=(backoffice platform-backoffice cockpitng backofficesearch pcm pcmbackoffice cockpit cockpit-core)
yDEV_REPORT_DIR=~/Documents/hybris/pkup/raporty/doc/
yDEV_NAME="Your name"
yDEV_SURNAME="Your surname"
yDEV_ROLE="Software Developer"
yDEV_DEPARTMENT="P&I"
yDEV_MANAGER="Your manager name and surname"

Installation and uninstallation

I also created installation script, which allows to start using the scripts faster. Installation script install dependencies for python script, copies shell script and python script into /usr/local/bin/ directory and .pkup.conf file into home directory. Configuration file needs to be adjusted by the user manually after installtion. Of course, there’s another script, which can be used for uninstallation.

Tests

There are python tests for this solution in pkup_doc_test.py file, but they’re quite poor right now due to the limited amount of time. They can be a subject of improvements in the future. Note that such scripting solutions rarely have tests because they’re small and created ad-hoc. Nevertheless, I wanted to follow the philosophy from my last blog article and create tests for any kind of software I make.

Summary

I’ve spent some time for preparing this stuff, but it was fun and I think it should save me and hopefully my co-workers some amount of time during creating reports every month. In the future, it can be improved by automatic generation of report messages and sending data to the server.

To sum up, preparing reports manually is boring. Generating reports automatically is exciting!

Complete solution described in this article with documentation is available on GitHub: https://github.com/pwittchen/pkup.

3 questions about your Git repository

2015-12-28 Git, Linux, Open source, Python 3 comments

Introduction

Can you answer the following questions about your Git repository?

  1. Does development branch has all changes from master branch?
  2. Is your gitlog a crap?
  3. How old are your branches?

If not, but you want to know answers, you’re lucky, because I prepared 3 simple scripts for you, which can help to find it out.

Does development branch has all changes from master branch?

git-branch-comparator is a python script, which checks if development branch has all changes from master branch in Git repository.

Another, easier way to accomplish the same task suggested in comments by Mike (thanks!) is to call simply:

$ git pull
$ git branch --contains master --no-merged development

When we are working in a Git Flow and critical bug occurs on production, sometimes there is a necessity to create so called hot-fix. We can create separate branch from master branch for this hot-fix and then merge it into master branch or we can commit a change on master branch. Second option is not recommended. After that, we have to remember to merge master branch into a development branch to have our hot-fix in a development version as well and avoid merge conflicts in the future.

This python script checks, if all changes made on master branch were also merged into development branch to keep those two branches consistent. We can add it as a job into Jenkins CI server and monitor branches consistency. In addition, release jobs can depend on that job and we can avoid merge conflicts or project unstability before release.

source code & documentation: https://github.com/pwittchen/git-branch-comparator

Is your gitlog a crap?

craplog is a python script, which checks if git git log of the given project is crappy or not. Right now, script is very simple. It just checks if more than half of the commit messages are good. Commit message is considered as good, when it contains more than two words. Of course, this is not the only condition determining the quality of the commit message, but this is early beta version of the script and can be improved later.

I’ve read a discussion in one of the pull requests to Linux kernel. It made me think about quality of Git commit messages. Of course, Linux kernel is a specific project and has its own standards. Maybe not all of these standards will be valid for a simpler or less complicated projects. Nevertheless, a lot of people don’t pay attention to git commit messages. They put crappy stuff inside them like random letters and numbers or stupid expressions, which has no specific meaning, aren’t related to the project or aren’t informative enough. In my opinion, good git log is one of the factors determining good quality of the project. Sometimes, we need to browse log to find some changes or analyze project history in order to fix a bug or find important information. It’s easier to do it, when git log is good. I’ve made some of the mentioned mistakes in the past, but I try to avoid them now.

source code & documentation: https://github.com/pwittchen/craplog

How old are your branches?

git-aged-branches is a shell script showing git branches of defined repository with age of their last commit. It works on Mac OS X, Linux and can be helpful while investigating old Git branches to delete. This script does not delete anything! It’s just for informational purposes.

source code & documentation: https://github.com/pwittchen/git-aged-branches

Summary

I hope, some of you will find these tools useful and maybe they’ll solve your current problems or help to improve quality of your projects.
If you would like to know more details about mentioned projects, check instructions how to use them and their source code, visit linked repositories on GitHub.

Note: Any feedback, new issues or pull requests are appreciated!

Checking consistency of Git branches

2015-05-14 Git, Jenkins, Python No comments

Recently I’ve created a simple Python script, which checks whether ‘development’ branch has all changes from ‘master’ branch in a Git repository. It’s important when we work in a Git Flow. Branch inconsistency may occur when change with hot-fix will be committed to ‘master’ branch and we forget to merge ‘master’ branch back to ‘development’ branch to have our hot-fix in a ‘development’ version of the project as well. We should keep branch consistency to avoid merge conflicts and problems with release of the project in the future. Mentioned script is able to perform necessary validation helping to detect potential problems.

Moreover, script can be integrated with the Jenkins CI server and we can execute it from a command line via Jenkins job. When, changes from ‘master’ won’t be merged into ‘development’, job will fail. In opposite case, job should finish with a success. In a Jenkins job we need to remember to add the following Additional Behaviours in Source Code Management (Git) section:

  • Clean before checkout
  • Wipe out repository and force clone

Usage of this script is quite simple:

$ python compare-branches.py <path_to_your_git_repository>

Script is open-source and can be found at: https://github.com/pwittchen/git-branch-comparator

Common Git questions & solutions

2015-04-18 Git No comments

I’ve recently found very interesing article about most common git screwups/questions and solutions.
It’s very useful and you should check this out if you are Git user.

Link to the article: http://41j.com/blog/2015/02/common-git-screwupsquestions-solutions/

Basics of Git

2014-11-27 Git No comments

Introduction

Git is very popular Version Control System used in many software projects today. In my opinion, it’s the best VCS available today.
In order to start your adventure with this tool, you should know its basic commands and features.
There are graphical tools, which allows to use Git without terminal, but I recommend you to use terminal. With CLI you can work faster, you can understand Git better and you have more control over your repository.

Basic commands

In my opinion, list presented below contains commands, which are used on daily basis and you should start journey with them.

Git hist

There is one more fancy feature, which allows you to display colorful and graphical representation of branches and commits.

You can assign this command to hist alias in your .gitconfig file. After that, you can type: git hist and this command will be executed.

You should see something similar to the log on the screen below.

git_hist_example

It’s a history of commits to AndEngine repository.

More advanced commands and features can be mastered after some work with basic Git stuff.

Resolving conflicts

It may happen that someone modified file and pushed changes into repository and after that we modified the same file in the same place and want to push our changes. In such case, we have to resolve conflicts and merge changes. Sometimes, its more convenient to resolve conflicts with graphical tools than editing raw files modified by Git. If you are using IDE provided by JetBrains (e.g. IntelliJ IDEA or Android Studio) you can use VCS tools built-in IDE. Just choose option VCS -> Git -> Merge changes... for program menu and you can merges via graphical interface. There are also other tools like Kdiff3 or Meld, but I personally prefer JetBrains tools.

Git flow

Last, but not least, remember to read about Git workflow and familiarize yourself with that concept:

Further learning

There are many Git tutorials and materials worth reading, which can help with extending knowledge about this VCS:

How to update forked GitHub repository?

2014-11-07 Git No comments

When you fork GitHub repository, you usually want to have your fork up to date with the original repository.
You can update your fork in a few easy steps. Just look at the following example of the Git commands:

Original StackOverflow post with this solution can be found here: http://stackoverflow.com/a/7244456.

Updating Android XML resources before compilation via Gradle

2014-09-10 Android, Git, Gradle 2 comments

Problem

In a team project, we encountered one of the common problems connected with mobile applications. Android application sends requests to backend web service and we don’t have backend web service deployed right now on a separate server, so every mobile developer is compiling and running backend web service on the local machine for testing purposes. In the beginning, url of backend url looked as follows:

Of course address varies on different machines.

When every developer was pushing changes, configuration of the backed url changed as well. It became annoying, so we decided to do something about that.

Solution

Attempt #1

First, we came with an idea of ignoring local changes of the XML file, which contains backend url address.
It can be done via Git in the following way:

git update-index --assume-unchanged [<file>...]

We can undo this operation with such command:

git update-index --assume-unchanged [<file>...]

We can also add ignored alias to our .gitconfig file:

[alias]
ignored = !git ls-files -v | grep "^[[:lower:]]"

Then we can type: git ignored to display ignored files.

For more information check StackOverflow discussion.

This solution is kind of work-around, so we decided to do it better.

Attempt #2

We could create alias for backend url and replace it before compilation dynamically via Gradle.

Our new configuration file res/values/configuration.xml looks like that:

Then, our build.gradle file needed to be updated. The most important part starts in 29th line, where #const_backend_url# value is replaced with an IP address of the local machine, where mobile application is compiled. As I mentioned before, backend web service application is compiled on the same machine, so backend web service address will be proper in that case for testing purposes.

Similar trick was applied in project: https://github.com/nenick/android-gradle-template in file https://github.com/nenick/android-gradle-template/blob/master/App/build.gradle, so you can check it out.