Changes between Initial Version and Version 1 of WorkingWithGitPRDraft


Ignore:
Timestamp:
Nov 4, 2016, 4:15:18 PM (8 years ago)
Author:
mojca (Mojca Miklavec)
Comment:

just copy contents from https://trac.macports.org/wiki/WorkingWithGit for further editing

Legend:

Unmodified
Added
Removed
Modified
  • WorkingWithGitPRDraft

    v1 v1  
     1= Working with Git =
     2
     3This document is a guide to working with the [https://git-scm.com Git] version control system, tailored to developers familiar with [https://subversion.apache.org Subversion].
     4
     5[[PageOutline]]
     6
     7
     8== Basic setup == #setup
     9
     10Git commits identify authors and committers by name and email address. You will likely use your name and a personal email address for most Git projects, so you can add them to `$HOME/.gitconfig`:
     11{{{
     12$ git config --global user.name 'Foo Barbaz'
     13$ git config --global user.email 'foo.bar.baz@email.com'
     14}}}
     15
     16If you're a MacPorts committer, you should use your MacPorts email address while working in MacPorts repositories. You can override your global settings by modifying `/path/to/MacPorts/repo/.git/config`:
     17{{{
     18$ cd /path/to/MacPorts/repo
     19$ git config user.email foobarbaz@macports.org
     20}}}
     21
     22
     23== Common `git` tasks == #tasks
     24
     25
     26=== Cloning a repository === #clone
     27
     28Obtaining a local copy of a Git repository is called "cloning" because you usually end up with a carbon copy of the source repository. GitHub allows cloning over [https://help.github.com/articles/which-remote-url-should-i-use HTTPS or SSH]:
     29{{{
     30$ git clone https://github.com/macports/macports-ports.git
     31}}}
     32{{{
     33$ git clone git@github.com:macports/macports-ports.git
     34}}}
     35Both of these create a `macports-ports` directory containing a working tree at the latest commit, with the repository itself—with full history—at `macports-ports/.git`.
     36
     37(A list of our repositories is available at [[FAQ/GitHubMigration#repositories]].)
     38
     39
     40=== Committing changes in your working copy === #commit
     41A fundamental difference between Subversion and Git working copies is that `svn commit` by default commits all changes in your working copy, but `git commit` by default commits none. Git uses a staging area called "index" that allows you to mark changes for inclusion in the next commit. To add changes to the next commit, use
     42{{{
     43git add <filename>...
     44}}}
     45
     46`git status` gives you an overview of the current index and your working copy. Additionally, it lists the commands to revert local uncommitted modifications (`git checkout -- <filename>`) and to remove files from the next commit, but preserve the modifications in your working copy (`git reset HEAD <filename>`).
     47
     48Once you have chosen which files to include in your next commit using `git add`, it is a good practice to review this list using
     49{{{
     50git status
     51}}}
     52and show the diff to be committed using
     53{{{
     54git diff --cached
     55}}}
     56If you are not satisfied with your changes, you can keep changing your files. Note that you will have to add any new modifications to the index using `git add` again. Once you are satisfied with your change run
     57{{{
     58git commit
     59}}}
     60which prompts you for the commit message. See the [#commitmessages section on commit messages in git] for more information on git conventions and expectations in commit messages.
     61
     62Because of Git's distributed nature, a commit on your local machine is not immediately available on the central server, like it was with Subversion. This means that you can continue to prepare further changes in additional commits before you publish your changes as a set. In fact, it is a very common practice in Git to do many small changes that are logically consistent in themselves and then publish them in one step.
     63
     64If you have commit access, you can publish your commits using `git push <remote-name> <branch-name>`. `<remote-name>` is the name of the repository to which you want to push. The most common push target is the location you initially cloned, which is automatically named `origin`. `<branch-name>` is the name of the branch you want to push. The Git equivalent to Subversion's `trunk` is called `master`. It is considered best practice to always specify your push target and the branch you are pushing, since git's default is pushing all branches that have a remote equivalent when you run `git push`, which might publish changes that you do not consider final yet (you can disable this behavior by changing the `push.default` git-config setting to `nothing`, see [https://git-scm.com/docs/git-config git-config(1)]).
     65{{{
     66git push origin master
     67}}}
     68
     69Note that the push will fail if the remote repository has new changes. Contrary to Subversion, it does not matter whether your changes conflict with the remote ones. If this happens, you must update your local working copy as described in the [#updating section on fetch the latest changes] and re-try the push.
     70
     71
     72=== Commit messages === #commitmessages
     73
     74{{{
     75#!div style="background-color: lightyellow; padding: 0.25em;"
     76TODO: This section needs to be merged with CommitRules
     77}}}
     78
     79To set which text editor is used by git for writing commit messages, you can do either of:
     80 * Set {{{core.editor}}} in your Git config: {{{git config --global core.editor "emacs"}}}
     81 * Set the {{{GIT_EDITOR}}} environment variable: {{{export GIT_EDITOR=emacs}}}
     82
     83There are a number of conventions to writing Git commit messages. For a detailed explanation, see http://chris.beams.io/posts/git-commit/. As a tl;dr, here are seven short rules:
     84
     85 1. Separate subject from body with a blank line
     86 1. Limit the subject line to 50 characters
     87 1. Capitalize the subject line
     88 1. Do not end the subject line with a period
     89 1. Use the imperative mood in the subject line
     90 1. Wrap the body at 72 characters
     91 1. Use the body to explain what and why vs. how
     92
     93Additionally, MacPorts has the following rules for references to tickets, pull requests and commits:
     94
     95 * When referencing a ticket, use the full URL to  Trac: !https://trac.macports.org/ticket/<number>
     96 * When referencing a pull request, use !#12345
     97 * When referencing a commit, use a git commit hash: !bfc6af313273c79515df9bde4f3eaa2dd0f15276, which may be abbreviated to up to 7 characters: !bfc6af3
     98
     99If you don't want to remember these rules, you can configure your git client to load a template whenever it prompts you for a commit message by setting the `commit.template` [https://git-scm.com/docs/git-config git-config(1)] option. The KDE developers [https://quickgit.kde.org/?p=macports-kde.git&a=blob&h=14f952f776b9f54263671cc2aba5886c6ebee75b&f=contrib%2Fgit-setup%2F.git-commit-template&o=plain have a nice example].
     100
     101
     102=== Fetching the latest changes === #updating
     103Git's equivalent to `svn update` is a little more complicated due to Git's distributed nature. Most of the complexity is not visible if you do not have commits in your working copy that have not been pushed yet. If both the local and the remote repository have changes (git calls them "diverged"), you will run into one of Git's core principles: Every commit has (at least) one parent commit, i.e. the commit history forms a directed acyclic graph.
     104
     105==== Background knowledge ====
     106
     107A picture is worth a thousand words:
     108{{{
     109 A --- B --- C ---- R1 ---- R2 ---- R3  <= origin/master
     110              \
     111               +--- L1 ---- L2          <= master
     112}}}
     113A, B and C are commits that are both in your local and in the remote repository. R1-3 are commits that have been pushed into the remote repository "origin"'s master branch while you were working. L1 and L2 are commits you prepared locally on your master branch. Git offers two different ways to bring R1-3 into your local branch:
     114
     115===== Merging =====
     116A merge commit, created by `git merge`, is a commit that has multiple parents. If no conflict occurs, merge commits do not usually have a diff attached (i.e. they do not modify files). On conflict, merge commits contain the diff that resolves the conflict. In pictures:
     117{{{
     118 A --- B --- C ---- R1 ---- R2 ---- R3   <= origin/master
     119              \                      \
     120               +--- L1 ---- L2 ------ M  <= master
     121}}}
     122The new commit M is the merge commit and can be pushed back to origin. This preserves the information that work was done in parallel, but unfortunately tends to mess up the history graph. See the [raw-attachment:commit-history-with-excessive-merging.png attached screenshot] of a commit history that always merges. To avoid this, you can instead rebase your changes.
     123
     124===== Rebasing =====
     125Rebasing commits rewrites their parent commit IDs and avoids the need for a merge commit. Running `git rebase origin/master` will take all commits in your local working copy that are not yet pushed and attach them after the end of `origin/master`, which yields this picture:
     126{{{
     127 A --- B --- C ---- R1 ---- R2 ---- R3   <= origin/master
     128                                      \
     129                                       L1' ---- L2'  <= master
     130
     131}}}
     132Note that L1 and L2 have been modified by this operation; their commit IDs changed because of that. This new state can be pushed back to origin without the need for a merge commit, and the history graph will stay linear. '''We recommend that all developers rebase their changes rather than merge when conflicts occur during pushing.'''
     133
     134==== Putting the background knowledge into production ====
     135First, get all new commits from the remote repository using `git fetch <remote-name>`, where `<remote-name>` identifies the repository from which you want to fetch and defaults to "origin":
     136{{{
     137git fetch
     138}}}
     139Then, rebase your local changes (if any) on top of any new changes in the remote repository and fix any conflicts that occur:
     140{{{
     141git rebase origin/master
     142}}}
     143
     144Because these two operations are very common, Git offers a shorthand for them:
     145{{{
     146git pull --rebase
     147}}}
     148
     149'''Note:''' `git rebase` requires that you do not have uncommitted modifications in your working copy. If you have modifications, you can temporarily save them using `git stash` and restore them after the rebase using `git stash pop`.
     150
     151'''Warning:''' `git pull` without the `--rebase` flag is a shorthand for `git fetch && git merge origin/master`, which will automatically create a merge commit if it thinks that's necessary.
     152
     153If you do not want to remember passing `--rebase` to `git pull` every time you run it, you can set a couple of [https://git-scm.com/docs/git-config git-config(1)] options to make it the default:
     154
     155 - Setting `pull.rebase` to `true` will change the default to always rebase when calling `git pull`. Note that this will also flatten any local merge commits you might have committed on purpose with `git merge`, which might be undesirable when merging development branches for MacPorts base. Consider using the `preserve` setting, which avoids this.
     156 - Rebasing can be enabled on a per-branch basis using the `branch.<name>.rebase` setting, which accepts the same values as `pull.rebase`.
     157 - You can make `branch.<name>.rebase true` the default for all branches that you clone by setting `branch.autoSetupRebase` to `always`. This allows you to change the setting back to a different value for specific branches but still keep the default to rebase. Note that this setting will not affect branches that you have already created.
     158
     159
     160=== Reverting changes === #revert
     161Subversion has two methods for reverting changes: `svn revert`, which drops uncommitted local modifications and restores the committed state and `svn merge -c -12345` to undo committed changes.
     162
     163Due to Git's distributed nature, there are three stages that can be reverted:
     164
     165 - To drop uncommitted modifications, use `git checkout -- <filename>`. If you had already added the file to the index using `git add`, you have to unstage it first using `git reset HEAD <filename>`. `git status` prints these commands, so you don't have to remember them.
     166 - To undo a change that has already been committed and pushed, use `git revert <commitID>`. This will create a new commit that applies the inverse diff. Note that you still have to push this commit to publish it.
     167 - To throw away all changes that you have locally committed but not yet pushed, use `git reset --hard origin/master`. '''You will lose all your uncommitted and committed modifications.''' If that is not what you want, Git provides a variety of tools that allow you to change commits that you have not pushed yet (and theoretically also commits that have already been pushed, which will prevent you from pushing any changes again). Since this is an advanced topic it will not be covered here. As a pointer for further research, look for `git commit --amend` to change the topmost commit and `git rebase --interactive`, the so-called "interactive rebase", to change older commits.
     168
     169
     170
     171
     172
     173== Common `git` tasks while working with ports ==
     174
     175
     176=== Checking out a working copy of the ports tree === #cloneports
     177To get a working copy of the MacPorts ports tree to start changing ports, clone a copy of the repository:
     178{{{
     179git clone git@github.com:macports/macports-ports.git # or
     180git clone https://github.com/macports/macports-ports.git # if SSH does not work on your network
     181}}}
     182
     183This will give you the entire history of the ports tree, with the latest version being checked out in the filesystem.
     184
     185'''Note:''' If you intend to submit a pull request on GitHub to get your changes included in MacPorts, you may want to create a fork of the repository first. To do that, go to https://github.com/macports/macports-ports/ and click the fork button at the top right. Then, run the command above, but use `<yourusername>/macports-ports.git` instead of `macports/macports-ports.git`.
     186
     187See the [#commit section on committing changes] to find out how to get your changes into the repository.
     188
     189
     190=== Submitting a pull request === #pr
     191If you are working on a fork of the ports repository, you can submit a pull request to have your changes considered for inclusion in the official repository. Follow the section on [#commit committing and pushing changes] to push your changes back to your fork (if you `git clone`d your fork, `git push origin` will push your changes back to your fork on GitHub). Then, go to your repository on GitHub and click the "New Pull Request" button. You will see a preview of the changes and a button to create a pull request. Modify the message for the pull request as you see fit and confirm the creation of the pull request.
     192
     193'''Note:''' This process is new to MacPorts developers. Please bear with us while we find the approach to pull requests that works best for us.
     194
     195
     196=== Updating your fork === #upstream-fetch
     197When submitting pull requests, we may ask you to rebase your changes on top of our current master branch. The easiest way to do this is adding the official repository as a second remote to your working copy and pulling from it. First, use `git remote` to add a reference to the upstream ports tree. Note that the name "upstream" can be chosen at random.
     198{{{
     199git remote add upstream git@github.com:macports/macports-ports.git # or
     200git remote add upstream https://github.com/macports/macports-ports.git # if SSH does not work on your network
     201}}}
     202
     203Then, fetch the contents of the upstream repository:
     204{{{
     205git fetch upstream
     206}}}
     207
     208Finally, follow the section on [#updating fetching the latest changes] but replace "origin" with "upstream". Eventually, you will end up running the equivalent of
     209{{{
     210git rebase upstream/master
     211}}}
     212which will put your local changes on top of ours. Pushing to your fork will update the pull request.
     213
     214
     215
     216
     217
     218== Common `git` tasks while working with MacPorts base ==
     219
     220
     221=== Checking out a working copy of MacPorts base === #clone
     222The source code of MacPorts itself is no longer managed in the same repository as all ports. Contrary to Subversion, checking out a sub-directory of a repository is not possible with Git. In order to avoid that all port maintainers have to clone the complete history of MacPorts base as well, the Subversion repository has been split into multiple separate repositories. MacPorts base is now available using
     223{{{
     224git clone git@github.com:macports/macports-base.git # or
     225git clone https://github.com/macports/macports-base.git # if SSH does not work on your network
     226}}}
     227
     228See the [#reposplit section on repository splitting during the export] to get an overview of where a path in the old Subversion history is now available in Git.
     229
     230
     231=== Merge a single change from master into a release branch === #cherrypick
     232The equivalent to Subversion's `svn merge -c <revision> .` is `git cherry-pick`. Use `git cherry-pick` to apply a single change from master to a release branch. To do this, look up the commit ID of the commit you want to pick:
     233{{{
     234git log
     235# copy the commit ID
     236}}}
     237Switch to the target branch of the cherry pick:
     238{{{
     239git checkout release_2_3
     240}}}
     241Cherry-pick the commit. It is good practice to pass `-x` to `git cherry-pick`, which will automatically add a "Cherry picked from commit <commmitID>" line to the commit message of your cherry pick. You will have the option to modify the commit message, e.g. to describe why the backport was necessary.
     242{{{
     243git cherry-pick -x <commitID>
     244}}}
     245Finally, push the new commit using
     246{{{
     247git push origin <branchname>
     248}}}
     249
     250
     251
     252
     253
     254== Tools == #tools
     255
     256There are many third-party tools that complement or replace the Git command-line client.
     257
     258- Command-line clients
     259  - [https://hub.github.com hub] is an open-source client designed specifically for use with GitHub. (Available from the `hub` port.)
     260  - [http://jonas.nitro.dk/tig Tig] is an ncurses-based client. (Available from the `tig` port.)
     261- Graphical clients
     262  - [https://git-scm.com/docs/git-gui git gui] is an open-source, Tk-based client included with Git itself.
     263  - [https://desktop.github.com GitHub Desktop] is a free client designed specifically for use with GitHub.
     264  - [https://git-scm.com/docs/gitk gitk] is an open-source, Tk-based repository browser included with Git itself.
     265  - [http://gitx.frim.nl GitX] is an open-source client designed for the Mac. (Our `GitX` port is [[ticket:42957|currently nonfunctional]].)
     266  - [https://www.sourcetreeapp.com SourceTree] is a commercial client that also supports Mercurial.
     267  - [https://www.git-tower.com/mac Tower] is a commercial client.
     268
     269
     270
     271
     272
     273== Learning Resources == #resources
     274
     275- [https://git-scm.com/doc Git Documentation]
     276- [https://help.github.com GitHub Help]
     277- [https://git-scm.com/documentation/external-links Git's list of external resources]
     278- [https://help.github.com/articles/good-resources-for-learning-git-and-github GitHub's list of external resources]
     279- [https://community.kde.org/Infrastructure/Git/Configuration “Infrastructure/Git/Configuration”] at the KDE Community Wiki
     280- [https://www.kernel.org/pub/software/scm/git/docs/giteveryday.html giteveryday(7)]