title | date | fontsize | monofont | mainfont | header-includes | ||
---|---|---|---|---|---|---|---|
Git workshop |
\today |
11pt |
Menlo |
Avenir |
|
Workshop goal: get good practices contributing code in team with git and GitHub:
- use core git commands,
- work on branches,
- submit pull requests for review,
- keep a clean history,
You will manipulate on a Scala.js playground.
-
Create a GitHub account attached to your society.
-
Update your account avatar, it will be easier for your collaborators to identify you.
- Create the key
~/.ssh/id_rsa_society
that will be attached to your account:
ssh-keygen -t rsa -b 4096 -C "mail@society.com"
- Add
society.github.com
host to your ssh config:
Host society.github.com
HostName github.com
IdentityFile ~/.ssh/id_rsa_society
- Attach your public key
~/.ssh/id_rsa_society.pub
to your GitHub account from the GitHub interface.
You are configuring git to use your society email in the folder
path-to-society-apps/
.
- Create
path-to-society-apps/.gitconfig
:
[user]
email = mail@society.com
- Include
path-to-society-apps/.gitconfig
in.gitconfig
:
[includeIf "gitdir:path-to-society-apps/"]
path = path-to-society-apps/.gitconfig
-
Fork
zengularity/git-workshop
from the GitHub interface. -
In the repository settings, under "Merge button" section, uncheck
merge commits
andrebase merging
, and keep onlysquash commit
checked. -
In branches settings, protect the master branch in the GitHub setting of your fork:
- from being forced-pushed,
- from being deleted,
- require 1 review before merging a branch into master.
-
In the collaborators settings, add the person sitting at your left. He will review your pull requests.
-
Accept the invitation of the person on your right.
- Clone the workshop repository with:
git clone
git@society.github.com:your-username/git-workshop
-
Install SBT.
-
Inside the
playground
directory, launch the playground with:
sbt "~fastOptJS"
- Open
file:///path/to/git-workshop/playground/index.html
on your browser.
This will display a minimal UI, to manage a To-Do list.
- List the previous commits with:
git log # or git log --oneline
- Show the details (diff) of the last commit with:
git show
- List the local branches:
git branch
- List all the branches (with remote):
git branch -a
You are going to add an arrow whose length is the number of todos.
Create a branch and move into it with:
git checkout -b arrow
First open the source of the view to be updated:
playground/src/main/scala/playground/view/TodoList.scala
Above the input field which let you add todos (see addTodo
in the code),
update the template so a <div>
is added, with an "arrow" =====>
as textual
content.
The goal is to have a number of =
character in this "arrow" which corresponds
to the number of todos (see the todos
variables in the code).
Arrow update scenario:
- Initially 2 todos:
==>
- A todo is added (3):
===>
- 2 todos are removed:
=>
A possible code to add the expected div
can be as bellow:
<div>{ todos.map(_.map(_ => '=').mkString) }></div>
- Look at the files you have modified with:
git status
- Look at your unstaged modifications with:
git diff
- Add files manually or by group with:
git add file-or-directory # git reset … to undo
- Look at the files staged for the next commit with:
git status # The files added previously should be listed
- Look at your staged modifications with:
git diff --staged
- Create a commit for your staged files with:
git commit
- The command above open an editor which let you write the commit message, resume your work by beginning with an action verb, like this:
- Add a login banner on the home page
- Integrate the project detail page
- Fix focus on the input component
- If you need to, add a description after a blank line.
If you want to commit files which were already added,
git commit -a
can be used without callinggit add
.
Use
git commit --amend
if you need to change your commit message afterward.
- Push your commit to origin with:
git push origin arrow
- In the command above,
origin
is the remote URI of your repository. You could have other remotes. Check your repository URI with:
git remote -v
A developer on the team informs you that you didn’t follow project’s branch naming conventions:
- feature/user-login
- fix/server-routes
- refactor/todo-model
- Rename your local branch with:
git branch -m arrow feature/arrow
- Rename your remote branch with:
git push -d origin arrow # delete,
git push origin feature/arrow # then create
It's not recommanded to rename a branch after a Pull Request has already been created as it will close the PR.
Still on the feature/arrow
branch, you want to improve the arrow so that it
gives the information of done todos.
The goal is to colorize in green the number of equals in the arrow corresponding to the number of completed todos.
The previously added "arrow" div
can be updated as bellow.
<div>{ todos.map(_.map { item =>
val color = if (item.isCompleted) "green" else "silver"
<span style={s"color:$color"}>=</span>
}) }></div>
Don’t add your files nor make a commit at this point.
You forgot but you have a demo to present. You did not have time to test your work and prefer to show the previous version. You’ll use the stash feature to put your current work aside for the moment.
Stashed files are often forgotten, that’s usually used to store code very temporarily. Prefer commits if you don’t want to loose code.
- Check that your stash is actually empty with:
git stash list
- Stash your files with:
git stash
- Look at the output of:
git status
- Check that your stash has ben added with:
git stash list
- Check that your arrow is all in black.
The demo was a success, congratulations!
- Unstash you files with:
git stash pop
- Check that your stash list is now empty with:
git stash list
- Let’s say you are using a system that create a file named
.OS
. Create this file with:
touch .OS
-
Using
git status
will indicate this newly created file is untracked. -
Add
.OS
along with your modified files.
git add .OS …
git commit
- Push it to origin.
Oops, you committed and pushed .OS!
- Remove
.OS
and stage it with:
git rm .OS
- Ammend the changes with the last commit with:
git commit --amend
- Push it to origin with
--force-with-lease
.
Force with lease will block your push if another person already pushed changes on your branch.
You want to be sure .OS
is not committed the next time. You could add
it to either:
- the project
.gitignore
, - or the global
~/.gitignore
.
Since .OS
is specific to your system and not to the project, you are going to
exclude it globally.
- Check the documentation with:
git config --help
Search for exclude with
/
- Check if you have a specific global ignore file with:
git config --global --list | grep core.excludesfile
- Create your ignore file and add a line containing
.OS
.
Note: Ignore rules specific to some environment (e.g. according the IDE) could rather be specified in the
.git/info/exclude
-
Create a pull request from
feature/arrow
in the GitHub interface. Because you have made a fork, the destination iszengularity/git-workflow
, change it to your repositoryusername/git-workflow
. -
Give it a title resuming your modification.
-
You can give more information in the description if necessary.
-
Add a Quality Assurance (QA) scenario in the description which indicate precisely the steps to check if your feature is valid or no.
**QA**
1. Go here and add this,
2. you should see that,
3. etc.
- Add the person on your left as a reviewer.
Because you need 1 review, you can’t merge your pull request yet. So, you’re gonna do another thing: refactor the TodoList component.
You’ll refactor changes from another branch, this will lead to another pull request. This new branch will be based on master, and not on the current feature branch you have been working on.
git checkout master
git checkout -b refactor/todo-list
It's recommanded not to create branch based on other previously created feature or task branch.
Rename the val todos
to items
in the TodoList
component
(see playground/src/main/scala/playground/view/TodoList.scala
).
At the end of the day, that’s interesting to push your code even if it’s still WIP.
-
Stage your files on the refactoring (
git add …
). -
Create your WIP commit, you don’t bother with the naming.
git commit -m "WIP"
As the file is already under SCM,
git commit -a -m "WIP"
could be used without priogit add
- Push it to origin.
Rename isCompleted
to isDone
in the Todo
model.
playground/src/main/scala/playground/model/Todo.scala
-
Stage your files on the refactoring (
git add …
). -
Check that the previous commit is the WIP commit before melting your staged changes into it.
git log -n 1 # Must show the WIP commit
- Now that you’re sure that the previous commit is the WIP one, melt your changes into it, and modify the commit message too:
git commit --amend
This command can be used even if there is no actual staged modifications, in order to modify the previous commit message.
-
Check what
git status
tells you. -
Try to push your changes to origin with:
git push origin refactor/todo-list
- Because you have modified the branch history that had already been pushed, you have to force your modifications to origin with:
git push --force-with-lease origin refactor/todo-list
Beware, a force commit is risky, and should not be used outside feature branches.
- Create a pull request from the GitHub interface, and think about the title
and the description, which should contains a QA. Don’t forget to target your
fork and not
zengularity/git-workflow
.
Review the refactor pull request of the person on your right. Because you
are picky, submit a comment to replace isDone
by isFinished
and request
changes.
The person on your left requested changes on you pull request. Because you agree on his comment:
- Replace
isDone
byisFinished
. - Stage your modified files.
- Create a fix commit.
- Push it to your branch.
You are creating a fix commit instead of amending the last one, so that the reviewer will see only new changes and will not have to review everything back again.
-
Check that the person on your right made the changes you requested
-
Approve his pull request.
Now that your pull request is approved:
-
Click on “Squash and merge”.
-
Prepare a well-formed commit message:
- The first line is:
- a summary of your modification,
- it begins with an action verb,
- keep the PR ref #XX, you’ll be able to see all the commits.
- The rest is a detail of your modifications:
- it can contain a list of modifications begining with
-
or*
, - it can link to un issue with its URL.
- it can contain a list of modifications begining with
-
Merge the pull request and then delete the branch with the provided button.
-
Check that you can still access to every commit of the Pull Request in the GitHub UI (history is kept).
- Go to the master branch and get synchronized with origin/master with:
git checkout master
git pull
-
Check that your refactoring is in a single commit on your local master branch (
git log …
). -
Delete your feature branch with:
git branch -D refactor/todo-list
You want to merge your feature/arrow
branch.
Unfortunately, your feature now has conflicts with the master branch. You have the choice between rebasing and merging.
You’ll use rebase instead of merge. Instead of having a merge commit, you move the entire branch to begin on the tip of the branch you rebase from.
See more details here.
That means:
- It can be more complex than merging if you have multiple commits.
- You have to change the history :
- you risk (when handling conflicts) to introduce unwanted changes while losing the original (valid) changes forever.
- That will lead to a cleaner history.
- You’ll avoid strange and repetitive merge conflicts in case you merge multiple times.
- Go to the feature branch.
git checkout …
- Get the remote changes and rebase from master with:
git fetch
git rebase origin/master
-
All the parts in conflict have been marked on your files, resolve them. You can use:
- your raw editor,
- your editor merge tool,
git mergetool
(with vim, nvim, meld, …).
-
Add your modified files.
-
Continue the rebase with:
git rebase --continue
The rebase will continue to be applied on the next commits, but because you have only one commit, the rebase is now done.
-
Check that the project compiles successfully, and that the visualization arrow still works.
-
Push force your branch to origin.
You now have time to check the arrow pull request of the person on your right. Whenever your pull request is validated, merge it.
Now, you will start a huge refactoring of our application.
- Create a new branch
task/refactor-playground
git checkout -b task/refactor-playground
-
Create a file
refactoring.txt
-
Add this file into git and commit your changes
git add refactoring.txt
git commit -m "Refactoring - Step 1 (WIP)"
-
Edit file
project/build.properties
and replace1.1.2
by1.2.7
-
Commit your changes into git
git add project/build.properties
git commit -m "Update to sbt v1.2.7"
- Create a new file
refactoring2.txt
and commit your changes
git add refactoring2.txt
git commit -m "Refactoring - Step 2 (WIP)"
One of your colleagues needs your changes in the file build.properties. You need to extract the commit in a new branch.
- Retrieve your commit with changes for build.properties
git log -n 3 --oneline
$ 6e13277 (HEAD -> feature/refactor-playground) Refactoring - Step 2 (WIP)
$ 19bd652 Update to sbt v1.2.7
$ e590939 Refactoring - Step 1 (WIP)
19bd652
is the commit ID for your changes about sbt version.
- Create a new branch from master
git branch task/update-sbt-127 master
- Move your working copy to the created branch
git checkout task/update-sbt-127
- Insert your previous commit into your branch
git cherry-pick <your-commit-id>
- Check that your commit is in your branch
git log -n 1 --oneline
$ 3a8f6de (HEAD -> task/update-sbt-127) Update to sbt v1.2.7
You can add git aliases in .gitconfig
, for example:
[alias]
tree = log --graph --oneline
p = push origin HEAD
- With the manual:
git branch --help
git rebase --help
…
- With stack overflow