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 whenever 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 an 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>
|