Skip to content

Working on c:geo for git beginners

cylorak edited this page Apr 7, 2021 · 20 revisions

This describes the development setup and workflow for c:geo for a git beginner audience. Git experts may choose different settings at one point or another of course, but please also follow the c:geo Standard Development Workflow (see next section).

Note: The following examples in this guide assume that you have a GitHub user called bruno and your local c:geo repository is stored in a folder called d:\dev\cgeo.

c:geo Standard Development Workflow

The standard workflow for working on c:geo uses a couple of assumptions / prerequisites:

  • You have forked the original c:geo repository (e.g. from cgeo/cgeo to bruno/cgeo) - see below in "Initial Setup of environment" section
  • Every work is done on a local copy of your fork.
  • You do not commit changes directly to the c:geo repository, but to your fork.
  • And then create a PR in c:geo using GitHub web page.

Some conventions we use:

  • Use rebase wherever possible (e.g. always use pull --rebase over pure pull). This is to avoid merge commits.
  • If possible, squash non-meaningful commits before issuing a Pull Request (e.g. commits removing typos or to fix CI issues). This is to avoid overly large and meaningless commit history in master branch.

The following tries to guide you through the different steps and name a couple of useful git commands. It assumes you are using a git command line tool, but most steps can be done using some sort of GUI (e.g. Android Studio) as well (see menu VCS → Git).

Fundamentals: what is git, what is GitHub

git is a version-control system. When installed locally, it manages the content of a root folder with all its files and (sub)folders as a so-called repository. Git is distributed, meaning that each installation manages its own repositories, but those repositories can be synced with each other. Basic concepts are:

  • A commit is a set of changes to files (adding, modifying or deleting files) which moves the underlying repository from one version to the next. It can be seen like a transaction to the repository
  • A branch is a way to isolate different units of work in one repository from each other. A central branch called master contains the most up-to-date integrated state of the software. When you work on an issue, you will usually create a dedicated branch for it, work on it and at a later point merge it back to the master. By creating (branch) and switching (switch) between branches you can also work in parallel on multiple issues within the same repository.
  • Repositories and branches are synchronized with each other using commands like push, pull and rebase. Since git is a distributed VCS this is very important.

GitHub is a free cloud service to host remote git repositories. It is specifically designed to aid distributed software development projects like c:geo. It adds to git a lot of very cool features:

  • Git Management GUI: since GitHub is in the cloud, you cannot use command line arguments like your local repositories. Thus a GUI is provided
  • User Management: GitHub adds the possibility to manage users for repositories, assigning roles and give permissions (e.g. to merge) only to specific people.
  • Pull Requests: instead of directly merging stuff into repositories, using PR a user can request that a change is merged. Around the PR concept, things like permission control, automated code checks and peer code reviews are taking place
  • Lots of other project development tools like issue tracker or a project wiki are provided as well

Initial Setup of environment

You have to do this one time only to set up your development environment. You will set up an environment consisting of three git repositories:

  • c:geo main repository (https://github.com/cgeo/cgeo): the main repository for the c:geo project
  • Your personal fork/copy of c:geo main repository on GitHub (e.g. bruno/cgeo): this will be used by you to issue pull requests to c:geo main repository
  • A local clone/copy of your personal copy of c:geo on GitHub (e.g. at d:/dev/cgeo): this is your local copy to really work on the code

On GitHub:

  • create an account at GitHub
  • If you want to use ssh later instead of https (optional but recommended): set up or check your ssh settings. See here for details

On your local machine:

  • make sure git is installed. See github set up for details.
  • open a git-bash and navigate to your root development folder (e.g. d:\dev)
  • Clone your forked repository:
    • If you want to use ssh: git clone git@github.com:bruno/cgeo.git
    • If you want to use https (Update: note that https will be desupported by GitHub in August 2021, so rather use ssh): git clone https://github.com/bruno/cgeo.git
  • (the last step automatically created the standard alias origin for this remote repository)
  • Create alias upstream for the c:geo main repository:
    • If you want to use ssh: git remote add upstream git@github.com:cgeo/cgeo.git
    • If you want to use https: git remote add upstream https://github.com/cgeo/cgeo.git

Note that https will be desupported in 2021, so consider setting up ssh right from the start.

In case you have to deal with multiple users on github using different ssh configs, check out this link: https://gist.github.com/jexchan/2351996

Optional initial settings:

  • For Windows: set Notepad++ as git editor instead of vim: git config --global core.editor "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"
  • For interactive rebase: set other message format (→ esp. includes author!): git config --global rebase.instructionFormat "(%an <%ae>) %s"
  • Sets globally that every pull request is doing a rebase by default: git config --global pull.rebase true

Working on an issue:

On start:

  • Refresh your local environment (see follow-up section)
  • Checkout the branch you want to use as a base for your development. Normally this is the master branch.
    • git switch master
  • create a branch for your development:
    • git switch -c <branchname>
    • A typical naming convention for <branchname> is to use issue_xxxx with xxxx being the issue number of the related GitHub issue your are working on. But that's optional, and you're free to use a different naming.

Now start coding on your issues. Whenever you feel you have achieved something worth saving, commit it and save it also to your personal GitHub fork of c:geo

  • commit your changes locally
    • git commit -a - give a comment in the opened file
    • or git commit -a -m <commit comment>
    • If you want to have more control over what files should be included into your commit, have a look at the git add <file> and git add -i commands.
  • upload your development into your fork on GitHub (origin) - the branch will be created there automatically
    • For the first push in this branch: git push -u origin <branchname> - for the first push in this branch
    • for following pushes: git push - for following pushes in this branch

When you feel that your coding comes to a conclusion and you want to request your code being merged into the main repository, then perform a Pull Request:

  • Prepare locally
    • Refresh your local environment (see follow-up section)
    • Make sure your changes are up-to-standard. At least the Unit-tests should run and Checkstyle should pass
    • If you have many commits on the branch you want to merge consider **squashing ** them (see section "Squasing commits / interactive rebase")
  • Open a Pull Request
    • open https://github.com/cgeo/cgeo
    • click "Pull Request"
    • left side (base repository): choose cgeo/cgeo, master
    • right side (head repository): choose your fork repository,
    • fill out form and submit pull request
  • Once you submitted a PR, automated code checks will run (code style, server build and running of unit tests). Only if these automated checks are passed, the PR will be reviewed by a c:geo core team member and, if suitable, will be merged to master.
  • If you have to change code AFTER the PR was already issued, simply change it in your branch as before and push changes to your fork (origin). PR will then automatically get updates (checks are retriggered).

Refreshing your local environment

Do this regularly to stay up-to-date with the server's code.

  • Change to the directory your local copy of your fork is in (e.g. cd d:/dev/cgeo)
  • Check if you have local changes not yet committed: git status. If you have:
    • Either: Commit your changes (normally it is sufficient to do a git commit -a) and merge again
    • Or: Stash away your changes (git stash) merge again and then re-apply the changes (git stash --apply)
  • fetch the most recent changes from the upstream repository to the local copy of your fork:
    • git fetch upstream
  • rebase your local and fork master branch to have the same contents as the upstream master branch:
    • git switch master
    • git pull --rebase upstream master
    • git push origin master
  • Rebase your local working branch with the refreshed master:
    • git switch <branchname>
    • git rebase master
    • Note: this step may result in merge conflicts. See section "Rebasing a branch and handling merge conflicts" if this happens.
  • If you're working with release branch as well, repeat the last steps for release branch:
    • git switch release
    • git pull --rebase upstream release

Rebasing a branch and handling merge conflicts

The base of your branch is the branch you have been on when you created your new branch, and with the state it then had. Sometimes it is necessary to update that base, e.g. when you have conflicting changes signalled by GitHub. To resolve this, you need to do a so called "rebase" to your base branch.

  • refresh your local environment as described above
  • change to the branch you want to rebase:
    • git switch <issue_xxxx>
  • rebase the branch (in this case to master):
    • git rebase upstream/master

Sometimes there may be conflicting changes which prevent an automatic merging by git. Look for lines having the word CONFLICT in the git message.

  • If you have changes which conflict with changes made online, git rebase will not succeed.
  • git will name the the conflicting files, and you will have to resort the conflicts in the editor.

You can resolve the conflicts in different ways:

  • Way 1: Using Android Studio
    • Open Android Studio, navigate to VCS → Git → Resolve Conflicts
    • You will get a list of all files with merge conflicts. Choose one and select merge
    • In the following three-parted screen (left: your version, right: server version, middle: merged version), use the tools to resolve conflicts
    • Click Merge to conclude merge. AS will automatically issue git add for you in the back
  • Way 2: use normal text editor:
    • Open conflicting file with text editor
    • Conflicting parts are marked in the file with >>>>> and <<<<<.
    • After having resolved the conflicts, you will have to add the files again (using git add command), and when all conflicting files are resolved, you can continue the rebase:

Either way, after resolving all conflicts, continue rebase with:

  • git rebase --continue.

Finally, when everything's ready, you can re-push to the server. As you have changed an existing commit, a regular git push will fail. You will have to add the --force-with-lease parameter to overwrite the existing commit:

  • git push --force-with-lease

Squashing commits / interactive rebase

When you work on an issue in your branch, you can commit as often as you like and that is totally fine. However, when this branch is merged in the end into the c:geo master, then all these commits will be visible in the c:geo master history for all times. This is usually fine when the number of commits is low and they have meaningful messages/changes in them. However, sometimes it happens that there are many commits with messages like Make CI happy or save local work to server, which are relevant for your development but should maybe not end up in public history of c:geo master.

This is where "squashing" might be a good idea. Squashing commits means to merge multiple commits into a single one. This can be done using interactive rebase.

Warning: interactive rebase is a powerful tool, but when used wrong it can result in loss of work. If you use it for the first time, consider make a local backup of your changes sources before.

To squash all commits of one of your branches into one:

  • Refresh your local environment
  • Change to branch: git switch <branchname>
  • Start interactive rebase: git rebase -i --keep-base --fork-point master
  • → Git will open a text editor LISTING all these commits, with the word pick at the beginning of the line
  • Change the word pick to squash (or s) for all lines EXCEPT THE FIRST ONE (leave pick there) and close the editor
  • → Git will open another text editor asking you for a new commit message for the new squashed commit
  • Enter/change the suggested message and close the editor
  • → Git will conclude the squash
  • Issue git log → you should only see one commit for <branchname>
  • Push this to your origin: git push --force-with-lease

Some notes:

  • Interactive rebase has lots of more options, most of them explained in the text files git opens in the editor
  • Interactive rebase rewrites git history. This is only save when used on branches/repositories where you are the single user

Other useful commands

This is a more or less unsorted list of useful git commands

  • Show differences:
    • check what a git commit would upload / what did you do since your last commit:
      • git diff
    • check what a git merge upstream/master would do with the code on your computer:
    • Visual comparison (if you have configured a diff tool like WinDiff or Beyond Compare)
      • git difftool
  • Working with branches
    • List branches:
      • git branch
    • Delete local branch:
      • git branch -d <branchname>
      • git branch -D <branchname>
    • Delete remote branch:
      • git push -d origin <branchname>
    • Undelete a deleted branch:
      • git switch -c <branchname> <sha> (<sha> being the checksum determined by git reflog)
    • Retarget a branch from master to release
      • git rebase --onto release master Afterwards, you need git push --force-with-lease to push the changes
  • reflog
    • pretty formatted reflog: git reflog --format='%C(auto)%h %<|(20)%gd %C(blue)%cr%C(reset) %C(red)%an%C(reset) %gs (%s)'

To ignore the translation files while merging branches, you need to accept the .gitconfig configuration with running the following command in you're local cgeo repo: git config --local include.path ../.gitconfig (See issue #9259)

Clone this wiki locally