mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
280 lines
9.5 KiB
ReStructuredText
280 lines
9.5 KiB
ReStructuredText
:orphan:
|
||
|
||
Git Workflows
|
||
=============
|
||
|
||
Purpose
|
||
-------
|
||
|
||
Swift development has been based on SVN since its inception. As part of the
|
||
transition to Git this document helps to address questions about how common SVN
|
||
workflows we use today translate to their Git counterparts as well as to discuss
|
||
Git workflow practices we plan on having — at least initially — after the Git
|
||
transition. Notably we will follow a model where commits to trunk — which is
|
||
the ‘master’ branch in Git — has commits land (in the common case) via rebasing
|
||
instead of merging. This model is open to evolution later, but this mimics the
|
||
workflow we have today with SVN.
|
||
|
||
SVN -> GIT Workflows
|
||
====================
|
||
|
||
The general SVN workflow consists of the following commands:
|
||
|
||
1. Checkout: This means checking out/setting up a new repository.
|
||
2. Update: Pulling the latest remote changes into a local repository.
|
||
3. Committing: Committing a change to the remote repository.
|
||
4. Reverting: Reverting a change from a remote repository.
|
||
5. Browsing: Looking at commits.
|
||
|
||
This document will show how to translate these commands to Git and additionally
|
||
how to configure Git. It assumes that one is attempting to manipulate a Git
|
||
repository via bash in a terminal. A lot of information since this is supposed
|
||
to be a short, actionable guide. For more information, please see the Git crash
|
||
course guide for SVN users at <https://git-scm.com/course/SVN.html>
|
||
|
||
*NOTE* Whenever we say the Swift repository, we mean any repository in the
|
||
Swift project.
|
||
|
||
Quicksetup (TLDR)
|
||
-----------------
|
||
|
||
For those who do not want to read the full document, use the following commands
|
||
to perform a simple repo setup for the Swift repository::
|
||
|
||
$ git config --global user.name "<My Name>"
|
||
$ git config --global user.email "<My Email>"
|
||
$ mkdir swift-source && cd swift-source
|
||
$ git clone <LLVM_REPO_URL>
|
||
$ git clone <CLANG_REPO_URL>
|
||
$ git clone <SWIFT_REPO_URL>
|
||
$ (cd swift && git config branch.autosetuprebase always)
|
||
$ git clone <CMARK_REPO_URL>
|
||
$ git clone <NINJA_REPO_URL>
|
||
|
||
Then to commit a new commit to the remote swift repository::
|
||
|
||
$ git commit
|
||
$ git push origin master
|
||
|
||
and to pull new commits from the remote swift repository::
|
||
|
||
$ git pull origin master
|
||
|
||
In order to ease updating all repositories, consider using the script in
|
||
'./utils/update-checkout'. This will automate updating the repositories in the
|
||
proper way.
|
||
|
||
Preliminary
|
||
-----------
|
||
|
||
Before beginning, we need to perform some global configuration of Git. Git
|
||
includes a username/email of the committer in every commit. By default this is
|
||
the current logged in user and the hostname of the machine. This is /not/ what
|
||
one wants. We configure Git globally (i.e. across all repositories) to have our
|
||
proper name and email by running the following commands::
|
||
|
||
$ git config --global user.name "<My Name>"
|
||
$ git config --global user.email "<My Email>"
|
||
|
||
Checkout
|
||
--------
|
||
|
||
Normally if one wishes to checkout a repository in SVN, one would use a command
|
||
like this::
|
||
|
||
$ SVN co <repository url> <local directory>
|
||
|
||
This would then checkout the latest revision from the repository specified by
|
||
'repository url' and place it into the directory 'local directory'. In Git,
|
||
instead of checking out the repository, one clones the repository. This is done
|
||
as follows::
|
||
|
||
$ git clone <repository url> <local directory>
|
||
|
||
This will cause Git to clone the repository at 'repository url' and check out
|
||
the 'master' branch. The 'master' branch corresponds to 'trunk' in SVN. For more
|
||
information about branching in Git please see
|
||
<https://git-scm.com/course/SVN.html#branch>
|
||
|
||
Before beginning to commit though, we /must/ perform some default configuration
|
||
of our repository to match the Swift repository default configuration by
|
||
enabling default rebasing.
|
||
|
||
Repository Configuration (Enabling Default Rebasing)
|
||
----------------------------------------------------
|
||
|
||
Once we have cloned the repository, we need to configure the repository for our
|
||
use. Specifically we want to configure the swift repository so that we rebase
|
||
whenever we update the repository (see the update section below for more
|
||
details)::
|
||
|
||
$ git config branch.autosetuprebase always
|
||
|
||
By default when updating, Git will attempt to merge the remote changes and your
|
||
local changes. Ignoring what that sentence means, this is not an SVN-esque
|
||
model. Instead we want any local changes that we have to be applied on top of
|
||
any new remote changes. The 'branch.autosetuprebase' flag causes this to be done
|
||
automatically when ever one updates the local repository.
|
||
|
||
Update
|
||
------
|
||
|
||
In SVN, one updates your local repository by running the update command::
|
||
|
||
$ SVN update
|
||
|
||
In Git, instead of performing SVN update, one pulls from the remote repository::
|
||
|
||
$ git pull --rebase origin master
|
||
|
||
This will pull any new remote commits into your local repository and then replay
|
||
your current local commits on top of those new commits.
|
||
|
||
By default the '--rebase' flag is not necessary for the Swift repository because
|
||
it is configured to always rebase by setting the 'branch.autosetuprebase' flag
|
||
(see the section 'Repository Configuration (Enabling Default Rebasing)' above).
|
||
|
||
Commit
|
||
------
|
||
|
||
In SVN, committing always means submitting changes to a remote repository. In
|
||
Git, committing refers to the process of first telling Git to track a change by
|
||
staging the change and then committing all staged changes into a change in the
|
||
local repository. One can have many such commits. Then when one is ready, one
|
||
pushes the new local changes to the remote repository. We go through these steps
|
||
in more detail below:
|
||
|
||
In terms of replicating the SVN model, there are now two steps. In order to
|
||
commit changes one first stages a changed file using 'git add'::
|
||
|
||
$ git add <path>
|
||
|
||
Then once all changes that you want to be apart of the commit have been staged,
|
||
a commit is created in the local repository via the 'commit' command::
|
||
|
||
$ git commit
|
||
|
||
As a shortcut to commit /all/ changes to local files that are already being
|
||
tracked by Git to the local repository, you can use the '-a' command::
|
||
|
||
$ git commit -a
|
||
|
||
In both of these cases, an editor will pop up to accept a commit message. To
|
||
specify a short commit message at the commandline, you can use the '-m' flag::
|
||
|
||
$ git commit -m 'My great commit message.'
|
||
|
||
In order to see the diff of changes that have not been staged, run the command::
|
||
|
||
$ git diff
|
||
|
||
To see all changes that have been staged, run the command::
|
||
|
||
$ git diff --staged
|
||
|
||
To get a diff for a specific revision/path, perform the following command::
|
||
|
||
$ git diff <revision> <path>
|
||
|
||
In order to get a more concise view of the files that have staged and or
|
||
unstaged changes, run the command::
|
||
|
||
$ git status
|
||
|
||
In order to restore a file from the last revision, one uses the checkout
|
||
command::
|
||
|
||
$ git checkout <path>
|
||
|
||
To restore a file to a specific revision, one must use a longer form of the
|
||
command::
|
||
|
||
$ git checkout <revision> -- <path>
|
||
|
||
To unstage a file, one uses the 'reset' command::
|
||
|
||
$ git reset <path>
|
||
|
||
This tells Git to reset '<path>' in the staging area to the top of tree commit
|
||
(which in Git is called 'HEAD'). In order to correct a mistake, you can pass the
|
||
'amend' flag to Git::
|
||
|
||
$ git commit --amend
|
||
|
||
This will cause all staged changes to be merged into 'HEAD'. Once one has made
|
||
all the relevant commits, in order to push the changes to the remote repository
|
||
the 'push' command is used::
|
||
|
||
$ git push origin master
|
||
|
||
If a different committer has committed changes such that there are remote
|
||
commits that are not present locally, this will fail. In order to get around
|
||
this issue, perform::
|
||
|
||
$ git pull --rebase origin master
|
||
|
||
in order to pull the new remote commits and replay your new commits on top. Then
|
||
try to push again. See the 'Checkout' section above how to configure the local
|
||
swift repository to always rebase allowing you to drop the '--rebase' flag.
|
||
|
||
Revert
|
||
------
|
||
|
||
In SVN reverting a commit implies performing a reverse merge. In Git, this is no
|
||
longer true. Instead one now just uses the 'revert' command::
|
||
|
||
$ git revert <revision>
|
||
|
||
This will cause Git to perform the reverse merge of that revision for you
|
||
against HEAD and bring up a message window for you to write a commit
|
||
message. This will be autofilled in with the title of the commit that is going
|
||
to be reverted and the revision number of that commit like so::
|
||
|
||
Revert "<FIRST LINE OF REVERTED COMMITS COMMIT MSG>"
|
||
|
||
This reverts commit <REVISION>.
|
||
|
||
One can edit this message as one sees fit. Once this has been done, the revert
|
||
will become a normal commit in your repository like any other commit. Thus to
|
||
revert the commit in the remote repository, you need to perform a Git push::
|
||
|
||
$ git push origin master
|
||
|
||
Browsing
|
||
--------
|
||
|
||
This section explains how one can view Git changes. In order to view a history
|
||
of all changes on a branch to the beginning of time use the 'log' command::
|
||
|
||
$ git log
|
||
|
||
This will for each commit show the following information::
|
||
|
||
commit <REVISION>
|
||
Author: <AUTHOR NAME> <AUTHOR EMAIL>
|
||
Date: <TIMESTAMP>
|
||
|
||
<COMMIT MSG>
|
||
|
||
To see history starting at a specific commit use the following form of a Git log
|
||
command::
|
||
|
||
$ git log <REVISION>
|
||
|
||
To see a oneline summary that includes just the title of the commit and its
|
||
hash, pass the '--oneline' command::
|
||
|
||
$ git log --oneline
|
||
|
||
It will not show you what was actually changed in each commit. In order to see
|
||
what was actually changed in a commit, use the command 'show'::
|
||
|
||
$ git show
|
||
|
||
This will show the aforementioned information shown by Git log, but additionally
|
||
will perform a diff against top of tree showing you the contents of the
|
||
change. To see the changes for a specific commit, pass the revision to Git
|
||
show::
|
||
|
||
$ git show <REVISION>
|