10 things I hate about Git
It's different but powerful and familiarity with help you understand the flow. In a typical Git repository you need fewer characters to uniquely identify a commit object. There are several, in fact. I think the fact that you use github adds complexity that you are attributing to git. The icon will change columns from right unstaged status to left staged status , and you might see one of two new icons:.
RStudio, Git and GitHub
It allows you to override the changes in files in your working tree. You will not be able to restore these changes. Changes in the working tree which are not staged can be undone with git checkout command. This command resets the file in the working tree to the latest staged version. If there are no staged changes, the latest committed version is used for the restore operation.
For example, you can restore the content of a directory called data with the following command. If you want to undo a staged but uncommitted change, you use the git checkout [commit-pointer] [paths] command. This version of the command resets the working tree and the staged area. The additional commit pointer parameter instructs the git checkout command to reset the working tree and to also remove the staged changes.
When you have added the changes of a file to the staging area, you can also revert the changes in the staging area base on the last commit. Sometimes you want to change the commmit your branch pointer is pointing to. The git reset command allows you to manually set the current HEAD pointer and its associated branch to a specified commit.
This is for example useful to undo a particular change or to build up a different commit history. Via parameters you can decide what you happen to the changes in the working tree and changes which were included in the commits between the original commit and the commit now referred to by the HEAD pointer. As a reminder, the working tree contains the files and the staging area contains the changes which are marked to be included in the next commit.
Depending on the specified parameters the git reset command performs the following:. If you specify the --soft parameter, the git reset command moves the HEAD pointer. Changes in the working tree will be left unchanged and all changes which were commited included in commits which are reseted are staged. Any file change between the original commit and the one you reset to shows up as modifications or untracked files in your working tree.
Use this option to remove commits but keep all the work you have done. You can do additional changes, stage changes and commit again. This way you can build up a different commit history.
This effectively removes the changes you have done between the original commit and the one you reset to. Via parameters you can define if the staging area and the working tree is updated. These parameters are listed in the following table. The git reset command does not remove untracked files. See Remove untracked files with git clean command for this purpose. It updates the staging area or also the working tree depending on your specified option.
If you reset the branch pointer of a branch to a certain commit, the git log commands does not show the commits which exist after this branch pointer. You if you reset your branch pointer to A, the git log command does not include B anymore.
Commits like B can still be found via the git reflog command. See Recovering lost commits. The reset command does not delete untracked files. If you want to delete them also see Recovering lost commits. As the staging area is not changed with a soft reset, you keep it in the desired state for your new commit. This means that all the file changes from the commits which were reseted are still part of the staging area.
The interactive rebase adds more flexibility to squashing commits and allows to use the existing commit messages. See Editing history with the interactive rebase for details. The git show command allows to see and retrieve files from branches, commits and tags. It allows seeing the status of these files in the selected branch, commit or tag without checking them out into your working tree. By default, this command addresses a file from the root of the repository, not the current directory.
If you want the current directory then you have to use the. For example to address the pom. You can checkout a file from the commit. To find the commit which deleted the file you can use the git log or the git ref-list command as demonstrated by the following command. The git log command allows you to determine which commit deleted a file. You can use the -- option in git log to see the commit history for a file, even if you have deleted the file.
This command reverts the changes of a commit. You can check out arbitrary revisions of your file system via the git checkout command followed by the commit ID. This command will reset your complete working tree to the status described by this commit. If you checkout a commit, you are in the detached head mode and commits in this mode are harder to find after you checkout another branch. Before committing it is good practice to create a new branch. If you checkout a commit or a tag, you are in the so-called detached HEAD mode.
If you commit changes in this mode, you have no branch which points to this commit. After you checkout a branch you cannot see the commit you did in detached head mode in the git log command.
There are multiple reflogs: Your local Git repository contains references to the state of the branches on the remote repositories to which it is connected. These local references are called remote-tracking branches. To update remote-tracking branches without changing local branches you use the git fetch command. See Updating your remote-tracking branches with git fetch for more information. It is safe to delete a remote branch in your local Git repository, this does not affect a remote repository.
The next time you run the git fetch command, the remote branch is recreated. You can use the following command for that. Branches can track another branch. This is called to have an upstream branch and such branches can be referred to as tracking branches. If you clone a Git repository, your local master branch is created as a tracking branch for the master branch of the origin repository short: You create new tracking branches by specifying the remote branch during the creation of a branch.
The following example demonstrates that. Instead of using the git checkout command you can also use the git branch command. The --no-track allows you to specify that you do not want to track a branch. You can explicitly add a tracking branch with the git branch -u command later. To see the tracking branches for a remote repository short: The git fetch command updates your remote-tracking branches, i.
The following command updates the remote-tracking branches from the repository called origin. The fetch command only updates the remote-tracking branches and none of the local branches. It also does not change the working tree of the Git repository.
Therefore, you can run the git fetch command at any point in time. After reviewing the changes in the remote tracking branchm you can merge the changes into your local branches or rebase your local branches onto the remote-tracking branch.
See Applying a single commit with cherry-pick for information about cherry-pick. See Merging for the merge operation and Rebasing branches. The git fetch command updates only the remote-tracking branches for one remote repository. In case you want to update the remote-tracking branches of all your remote repositories you can use the following command.
The above commands show the changes introduced in HEAD compared to origin. If you want to see the changes in origin compared to HEAD, you can switch the arguments or use the -R parameter. You can rebase your current local branch onto a remote-tracking branch.
The following commands demonstrate that. More information on the rebase command can be found in Rebasing branches. The git pull command performs a git fetch and git merge or git rebase based on your Git settings.
The git fetch does not perform any operations on your local branches. You can always run the fetch command and review the incoming changes. Git allows you to combine the changes which were created on two different branches. One way to achieve this is merging , which is described in this chapter. You can merge based on branches, tags or commits. Other ways are using rebase or cherry-pick. This part explains how to merge changes between two different branches under the assumption that no merging conflicts happen.
Solving conflicts is covered in What is a conflict during a merge operation? If the commits which are merged are direct successors of the HEAD pointer of the current branch, Git performs a so-called fast forward merge. This fast forward merge only moves the HEAD pointer of the current branch to the tip of the branch which is being merged.
This process is depicted in the following diagram. The first picture assumes that master is checked out and that you want to merge the changes of the branch labeled "branch 1" into your "master" branch. Each commit points to its predecessor parent. The "branch 1" branch points to the same commit. If commits are merged which are not direct predecessors of the current branch, Git performs a so-called three-way-merge between the latest commits of the two branches, based on the most recent common predecessor of both.
As a result a so-called merge commit is created on the current branch. It combines the respective changes from the two branches being merged. This commit points to both of its predecessors. If multiple common predecessors exist, Git uses recursion to create a virtual common predecessor. For this Git creates a merged tree of the common ancestors and uses that as the reference for the 3-way merge.
This is called the recursive merge strategy and is the default merge strategy. If a fast-forward merge is not possible, Git uses a merge strategy. The default strategy called recursive merge strategy was described in Merge commit. The Git command line tooling also supports the octopus merge strategy for merges of multiple references. With this operation it can merge multiple branches at once. The subtree option is useful when you want to merge in another project into a sub-directory of your current project.
It is rarely used and you should prefer the usage of Git submodules. See Git Submodules for more information. The ours strategy merges a branch without looking at the changes introduced in this branch. This keeps the history of the merged branch but ignores the changes introduced in this branch. You can use the ours merge strategy to document that you have integrated a branch and decided to ignore all changes from this branch. The git merge command performs a merge.
You can merge changes from one branch to the current active one via the following command. The -s parameter allows you to specify other merge strategies.
This is demonstrated with the following command. For example, you can specify the ours strategy in which the result of the merge is always that of the current branch head, effectively ignoring all changes from all other branches.
Be careful if you use the ours merge strategy, it ignores everything from the branch which is merged. The usage of the octopus merge strategy is triggered if you specify more than one reference to merge. The recursive merge strategy default allows you to specify flags with the -X parameter. For example you can specify here the ours option. This option forces conflicting changes to be auto-resolved by favoring the local version. Changes from the other branch that do not conflict with our local version are reflected to the merge result.
For a binary file, the entire contents are taken from the local version. The ours option for the recursive merge strategy should not be confused with the ours merge strategy. A similar option to ours is the theirs option. This option prefers the version from the branch which is merged. Another useful option is the ignore-space-change parameter which ignores whitespace changes. For more information about the merge strategies and options see Git merge manpage.
If you prefer to have merge commits even for situations in which Git could perform a fast-forward merge you can use the git merge --no-ff command. The --no-ff parameter can make sense if you want to record in the history at which time you merged from a maintenance branch to the master branch.
When pulling from a remote repository, prefer doing a rebase to a merge. This will help to keep the history easier to read. A merge commit can be helpful to document that functionality was developed in parallel. You can use Git to rebase one branch on another one. As described, the merge command combines the changes of two branches. If you rebase a branch called A onto another, the git command takes the changes introduced by the commits of branch A and applies them based on the HEAD of the other branch.
After this operation the changes in the other branch are also available in branch A. The process is displayed in the following picture. Running the rebase command creates a new commit with the changes of the branch on top of the master branch. Performing a rebase does not create a merge commit. The final result for the source code is the same as with merge but the commit history is cleaner; the history appears to be linear. Rebase can be used to forward-port a feature branch in the local Git repository onto the changes of the master branch.
This ensures that your feature is close to the tip of the upstream branch until it is finally published. If you rewrite more than one commit by rebasing, you may have to solve conflicts per commit.
In this case the merge operations might be simpler to be performed because you only have to solve merge conflicts once. Also, if your policy requires that all commits result in correct software you have to test all the rewritten commits since they are "rewritten" by the rebase algorithm. Hence, it might be more efficient to merge a long feature branch into upstream instead of rebasing it since you only have to review and test the merge commit.
You can use the rebase command to change your Git repository history commits. This is called interactive rebase, see? You should avoid using the Git rebase operation for changes which have been published in other Git repositories.
The Git rebase operation creates new commit objects, this may confuse other developers using the existing commit objects. Assume that a user has a local feature branch and wants to push it to a branch on the remote repository. However, the branch has evolved and therefore pushing is not possible. Now it is good practice to fetch the latest state of the branch from the remote repository.
Afterwards you rebase the local feature branch onto the remote tracking branch. This avoids an unnecessary merge commit. This rebasing of a local feature branch is also useful to incorporate the latest changes from remote into the local development, even if the user does not want to push right away.
Rebasing and amending commits is safe as long as you do not push any of the changes involved in the rebase. For example, when you cloned a repository and worked in this local repository. Rebasing is a great way to keep the history clean before contributing back your modifications.
In case you want to rewrite history for changes you have shared with others you need to use the -f parameter in your git push command and subsequently your colleagues have to use fetch -f to fetch the rewritten commits. Git allows you to edit your commit history with a functionality called interactive rebase. For example, you can combine several commits into one commit, reorder or skip commits and edit the commit message.
This is useful as it allows the user to rewrite some commit history cleaning it up before pushing the changes to a remote repository. The setup for the rebase is called the rebase plan. Based on this plan, the actual interactive rebase can be executed. It is safe to use interactive rebase as long as the commits have not been pushed to another repository. As the interactive rebase creates new commit objects, other developers might be confused if you rebase already published changes.
We want to combine the last seven commits. You can do this interactively via the following command. This command opens your editor of choice and lets you configure the rebase operation by defining which commits to pick , squash or fixup.
The following listing shows an example of the selection. We pick the last commit, squash 5 commits and fix the sixth commit. The listing uses the long format of the commands for example fixup instead of the short form f for better readability. The git cherry-pick command allows you to select the patch which was introduced with an individual commit and apply this patch on another branch.
The patch is captured as a new commit on the other branch. The new commit does not point back to its original commit so do not use cherry-pick blindly since you may end up with several copies of the same change. Most often cherry-pick is either used locally to emulate an interactive rebase or to port individual bug fixes done on a development branch into maintenance branches.
The following command selects the first commit based on the commit ID and applies its changes to the master branch. This creates a new commit on the master branch. The cherry-pick command can be used to change the order of commits.
See Commit ranges with the double dot operator for more information about commit ranges. If things go wrong or you change your mind, you can always reset to the previous state using the following command. Merge conflict A conflict during a merge operation occurs if two commits from different branches have modified the same content and Git cannot automatically determine how both changes should be combined when merging these branches. If a conflict occurs, Git marks the conflict in the file and the programmer has to resolve the conflict manually.
After resolving it, he adds the file to the staging area and commits the change. These steps are required to finish the merge operation. He decides that he wants to keep the original version or the new version of the file. For this, there is the --theirs and the --ours options on the git checkout command. The first option keeps the version of the file that you merged in, and the second option keeps the version before the merge operation was started.
The following steps create a merge conflict. It assumes that repo1 and repo2 have the same origin repository defined. As this push would not result in a non-fast-format merge, you receive an error message similar to the following listing. To solve this, you need to integrate the remote changes into your local repository. In the following listing the git fetch command gets the changes from the remote repository.
The git merge command tries to integrate it into your local repository. If you use the git pull command it performs the "fetch and merge" or the "fetch and rebase" command together in one step.
Whether merge or rebase is used depends on your Git configuration for the branch. Git marks the conflicts in the affected files. In the example from? In this example you resolve the conflict which was created in? To solve the merge conflict you edit the file manually. The following listing shows a possible result. Afterwards add the affected file to the staging area and commit the result. This creates the merge commit. You can also push the integrated changes now to the remote repository.
Instead of using the -m option in the above example you can also use the git commit command without this option. In this case the command opens your default editor with the default commit message about the merged conflicts.
It is good practice to use this message. Alternatively, you could use the git mergetool command. Some operating systems may come with a suitable merge tool already installed or configured for Git.
Rebase conflict During a rebase operation, several commits are applied onto a certain commit. If you rebase a branch onto another branch, this commit is the last common ancestor of the two branches. If a conflict occurs during a rebase operation, the rebase operation stops and the developer needs to resolve the conflict.
After he has solved the conflicts, the developer instructs Git to continue with the rebase operation. A conflict during a rebase operation is solved similarly to the way a conflict during a merge operation is solved. The developer edits the conflicts and adds the files to the Git index.
Afterwards he continues the rebase operation with the following command. If a file is in conflict, you can instruct Git to take the version from the new commit of the version of commit onto which the new changes are applied. This is sometimes easier than to solve all conflicts manually. For this you can use the git checkout with the --theirs or --ours flag. During the conflict --ours points to the file in the commit onto which the new commit is placed, i.
An alias in Git allows you to create a short form of one or several existing Git commands. For example, you can define an alias which is a short form of your own favorite commands or you can combine several commands with an alias. The following defines an alias to see the staged changes with the new git staged command.
Or you can define an alias for a detailed git log command. The following command defines the git ll alias. You can also run external commands. In this case you start the alias definition with a! For example, the following defines the git ac command which combines git add. You specify a range of commits and a script that the bisect command uses to identify whether a commit is good or bad. This script must return 0 if the condition is fulfilled and non-zero if the condition is not fulfilled.
Create a new Git repository, create the text1. Do a few more changes, remove the file and again do a few more changes. We use a simple shell script which checks the existence of a file. Ensure that this file is executable.
Afterwards use the git bisect command to find the bad commit. First you use the git bisect start command to define a commit known to be bad showing the problem and a commit known to be good not showing the problem. The above commands serve as an example. The existence of a file can be easier verified with the git bisect command: The git filter-branch command allows you to rewrite the Git commit history. This can be done for selected branches and you can apply custom filters on each revision.
This creates different hashes for all modified commits. This implies that you get new IDs for all commits based on any rewritten commit. The command allows you to filter for several values, e. For details please see the git-filter-branch manual page.
Using the filter-branch command is dangerous as it changes the Git repository. It changes the commit IDs and reacting on such a change requires explicit action from the developer, e. For example, you can use git filter-branch if you want to remove a file which contains a password from the Git history. Or you want to remove huge binary files from the history. To completely remove such files, you need to run the filter-branch command on all branches.
The following command extracts a directory from a Git repository and retains all commits for this subfolder. A patch is a text file that contains changes to other text files in a standarized format. A patch created with the git format-patch command includes meta-information about the commit committer, date, commit message, etc and also contains the changes introduced in binary data in the commit.
This file can be sent to someone else and the receiver can use it to apply the changes to his local repository. The metadata is preserved. Alternatively you could create a diff file with the git diff command, but this diff file does not contain the metadata information. The following example creates a branch, changes several files and creates a commit recording these changes. To apply this patch to your master branch in a different clone of the repository, switch to it and use the git apply command.
Use the git am command to apply and commit the changes in a single step. You specify the order in which the patches are applied by specifying them on the command line.
You can specify the commit ID and the number of patches which should be created. For example, to create a patch for selected commits based on the HEAD pointer you can use the following commands. Git provides commit hooks, e. For example, you can ensure that the commit message has a certain format or trigger an action after a push to the server.
These programs are usually scripts and can be written in any language, e. You can also implement a hook, for example, in C and use the resulting executables. Git calls the scripts based on a naming convention. Git provides hooks for the client and for the server side.
On the server side you can use the pre-receive and post-receive script to check the input or to trigger actions after the commit. The usage of a server commit hook requires that you have access to the server.
Hosting providers like GitHub or Bitbucket do not offer this access. If you create a new Git repository, Git creates example scripts in the. The example scripts end with. To activate them make them executable and remove the. The hooks are documented under the following URL: Git hooks manual page. Not all Git server implementations support server side commit hooks. For example Gerrit a Git server which also provides the ability to do code review does not support hooks in this form.
Also Github and Bitbucket do not support server hooks at the time of this writing. Every time a developer presses return on the keyboard an invisible character called a line ending is inserted. Unfortunately, different operating systems handle line endings differently.
Linux and Mac use different line endings than Windows. This becomes a problem if developers use different operating system to commit changes to a Git repository. To avoid commits because of line ending differences in your Git repository you should configure all clients to write the same line ending to the Git repository. Use the following setting for this.
You can also configure the line ending handling per repository by adding a special. If this file is committed to the repository, it overrides the core. Not all graphical Git tools support the. See Eclipse Bug report. To convert Subversion projects to Git you can use a RubyGem called svn2git. This tool relies on git svn internally and handles most of the trouble. Then navigate to your git directory and use the following commands:.
The parameter --verbose adds detailed output to the commandline so you can see what is going on including potential errors. The second svn2git --rebase command aligns your new git repository with the svn import. You are now ready to push to the web and get forked! If your svn layout deviates from the standard or other problems occur, seek svn2git --help for documentation on additional parameters.
If the symlink points to a file, then Git stores the path information it is symlinking to, and the file type. This is similar to a symlink to a directory; Git does not store the contents under the symlinked directory.
This tutorial is part of a series about the Git version control system. See the other tutorials for more information. Hosting Git repositories at Bitbucket or on your own server. Typical workflows with Git. EGit - Teamprovider for Eclipse. This tutorial is part of a book available as paper print and electronic form for your Kindle. Blog post about Git 2. We offer both public and inhouse training.
The vogella company offers expert consulting services, development support and coaching. Our customers range from Fortune corporations to individual developers. Free use of the software examples is granted under the terms of the EPL License. This tutorial explains the usage of the distributed version control system Git via the command line.
The examples were done on Linux Ubuntu , but should also work on other operating systems like Microsoft Windows. Introduction into version control systems 1. What is a version control system? Localized and centralized version control systems A localized version control system keeps local copies of the files.
Distributed version control systems In a distributed version control system each user has a complete local copy of a repository on his individual computer. Introduction into Git 2. Git repositories A Git repository contains the history of a collection of files starting from a certain directory. A local non-bare Git repository is typically called local repository. Working tree A local repository provides at least one collection of files which originate from a certain version of the repository.
These states are the following: Adding to a Git repository via staging and committing After modifying your working tree you need to perform the following two steps to persist these changes in your local repository: For committing the staged changes you use the git commit command.
Synchronizing with other Git repositories remote repositories Git allows the user to synchronize the local repository with other remote repositories. The concept of branches Git supports branching which means that you can work on different versions of your collection of files.
Summary of the core Git terminology The following table provides a summary of important Git terminology discussed in this section. The details of the commit objects 3. Commit object commit Conceptually a commit object short: Technical details of a commit object This commit object is addressable via a hash SHA-1 checksum. Predecessor commits, parents and commit references Each commit has zero or more direct predecessor commits. Git allows addressing commits via commit reference for this purpose.
Commit ranges with the double dot operator You can also specify ranges of commits. You can also list all commits which are in the "testing" but not in the "master" branch. Commit ranges with the triple dot operator The triple dot operator allows you to select all commits which are reachable either from commit c1 or commit c2 but not from both of them.
This is useful to show all commits in two branches which have not yet been combined. The Git command line tools The core Git development team provides tooling for the command line via the the git command. See all possible commands, use the git help --all command. Separating parameters and file arguments in Git commands The double hyphens -- in Git separates out any references or other options from a path usually file names.
Other graphical tools for Git You can also use graphical tools. Installation of the Git command line tooling 6. Ubuntu, Debian and derived systems On Ubuntu and similar systems you can install the Git command line tool via the following command: Fedora, Red Hat and derived systems On Fedora, Red Hat and similar systems you can install the Git command line tool via the following command: Other Linux systems To install Git on other Linux distributions please check the documentation of your distribution.
Windows A Windows version of Git can be found on the Git download page. Git configuration levels The git config command allows you to configure your Git settings.
Git system-wide configuration You can provide a system wide configuration for your Git settings. Git user configuration Git allows you to store user settings in the. Repository specific configuration You can also store repository specific settings in the. User credential configuration You have to configure at least your user and email address to be able to commit to a Git repository because this information is stored in each commit.
Push configuration If your are using Git in a version below 2. Avoid merge commits for pulling By default, Git runs the git fetch followed by the git merge command if you use the git pull command.
Allow rebasing with uncommited changes If you want Git to automatically save your uncommited changes before a rebase you can activate autoStash. Color Highlighting The following commands enables color highlighting for Git in the console.
Setting the default merge tool File conflicts might occur in Git during an operation which combines different versions of the same files. More settings All possible Git settings are described under the following link: Query Git settings To query your Git settings, execute the following command: If you want to query the global settings you can use the following command.
Configure files and directories to ignore 8. Ignoring files and directories with a. Stop tracking files based on the. Local per-repository ignore rules You can also create local per-repository rules by editing the. Tracking empty directories with Git Git ignores empty directories, i.
Setting up Git via the command line After the installation of the Git tooling for the command line you need to configure Git. The minimum required information to use Git is the user name and the email which Git should use.
Performing a local Git workflow via the command line In this exercise, you learn how to create and work with a local Git repository. Create a directory The following commands create an empty directory which is used later in this exercise to contain the working tree and the Git repository.
Create a new Git repository You now create a new Git repository with a working tree. Create new content Use the following commands to create several new files. See the current status of your repository The git status command shows the status of the working tree, i.
On branch master Initial commit Untracked files: Add changes to the staging area Before committing changes to a Git repository, you need to mark the changes that should be committed with the git add command. On branch master Initial commit Changes to be committed: Change files that are staged In case you change one of the staged files before committing, you need to add the changes again to the staging area, to commit the new changes.
Use the git status command again to see that all changes are staged. Commit staged changes to the repository After adding the files to the Git staging area, you can commit them to the Git repository with the git commit command. Viewing the Git commit history The Git operations you performed have created a local Git repository in the. Mon Dec 1 Viewing the changes of a commit Use the git show command to see the changes of a commit. Review the resulting directory structure Review the resulting directory structure.
Remove files If you delete a file, you use the git add. Revert changes in files in the working tree Use the git checkout command to reset a tracked file a file that was once staged or committed to its latest staged or commit state.
On branch master nothing to commit, working directory clean. Correct the changes of the commit with git amend The git commit --amend command makes it possible to rework the changes of the last commit. Ignore files and directories with the. Git allows that you can synchronize your repository with more than one remote repository.
You can specify properties for the remove, e. URL, branches to fetch or branches to push. A remote repository can also be hosted in the local file system. Bare repositories A remote repository on a server typically does not require a working tree. By convention the name of a bare repository should end with the.
Convert a Git repository to a bare repository Converting a normal Git repository to a bare repository is not directly support by Git. Cloning a repository The git clone command copies an existing Git repository. Alternatively you could clone the same repository via the http protocol. Adding remote repositories If you clone a repository, Git implicitly creates a remote named origin by default.
Rename remote repositories To rename an existing remote repository use the git remote rename command. The following listing configures the proxy via environment variables. Adding a remote repository You add as many remotes to your repository as desired. Synchronizing with remote repositories You can synchronize your local Git repository with remote repositories. Show the existing remotes To see the existing definitions of the remote repositories, use the following command.
To see the details of the remotes , e. Push changes to another repository The git push command allows you to send data to other repositories. Pull changes from a remote repository The git pull command allows you to get the latest changes from another repository for the current branch. Working with a local remote repository This exercise is based on Exercise: Create a bare Git repository via the clone operation Execute the following commands to create a bare repository based on your existing Git repository.
Clone your bare repository Clone your bare repository and checkout a working tree in a new directory via the following commands. Using the push command Make some changes in one of your non-bare local repositories and push them to your bare repository via the following commands. Using the pull command To test the git pull in your example Git repositories, switch to other non-bare local repository.
You can pull in the changes in your first example repository with the following commands. List available branches The git branch command lists all local branches. The -v option lists more information about the branches. Create new branch You can create a new branch via the git branch [newname] command. Checkout branch To start working in a branch you have to checkout the branch. Rename a branch Renaming a branch can be done with the following command.
Delete a branch To delete a branch which is not needed anymore, you can use the following command. Push changes of a branch to a remote repository You can push the changes in a branch to a remote repository by specifying the target branch.
If you do not specify the remote repository, the origin is used as default. Switching branches with untracked files Untracked files never added to the staging area are unrelated to any branch. Switching branches with uncommitted changes Similar to untracked files you can switch branches with unstaged or staged modifications which are not yet committed.
You can switch branches if the modifications do not conflict with the files from the branch. Differences between branches To see the difference between two branches you can use the following command.
Using tags in Git. Lightweight and annotated tags Git supports two different types of tags, lightweight and annotated tags. Naming conventions for tags Tags are frequently used to tag the state of a release of the Git repository. List tags You can list the available tags via the following command: Search by pattern for a tag You can use the -l parameter in the git tag command to search for a pattern in the tag.
Creating annotated tags You can create a new annotated tag via the git tag -a command. Creating signed tags You can use the option -s to create a signed tag.
Checkout tags If you want to use the code associated with the tag, use: Push tags By default the git push command does not transfer tags to remote repositories. Delete tags You can delete tags with the -d parameter. Listing changed files The git status command shows the current status of your repository and possible actions which you can perform. Using git status The following commands create some changes in your Git repository.
Using git diff The git diff command allows you to compare changes between commits, the staging area and working tree, etc.
The following example code demonstrate the usage of the git diff command. Analyzing the commit history with git log Using git log The git log command shows the history of the Git repository. Helpful parameters for git log The following gives an overview of useful parameters for the git log command.
This parameter uses 7 characters by default, but you can specify other numbers, e. View the change history of a file To see changes in a file you can use the -p option in the git log command. Configuring output format You can use the --pretty parameter to configure the output. The following command lists all commits with an author name containing the word "Vogel".
See also git shortlog for release announcements. Viewing changes with git diff and git show See the differences introduced by a commit To see the changes introduced by a commit use the following command. See the difference between two commits To see the differences introduced between two commits you use the git diff command specifying the commits. See the files changed by a commit To see the files which have been changed in a commit use the git diff-tree command.
Using the Git blame command Analyzing line changes with git blame. Commit history of a repository or certain files Gitk can be used to visualize the history of a repository of certain files.
This command also allows you to see the commits done by a certain author or committer. Stashing changes in Git The git stash command Git provides the git stash command which allows you to record the current state of the working directory and the staging area and to revert to the last committed revision. When to use git stash In general using the stash command should be the exception in using Git. Using the git stash command The following commands will save a stash and reapply them after some changes.
Create a branch from a stash You can also create a branch for your stash if you want to continue to work on the stashed changes in a branch.
Remove untracked files with git clean Removing untracked files If you have untracked files in your working tree which you want to remove, you can use the git clean command.
Using git clean The following commands demonstrate the usage of the git clean command. Revert uncommitted changes in tracked files Use cases If you have a tracked file in Git, you can always recreate the file content based on the staging area or based on a previous commit.
Remove staged changes from the staging area Staging area, remove staged changes You can use the git reset [paths] command to remove staged changes from the staging area. The output of git status command should look similar to the following. On branch master Changes to be committed: On branch master Changes not staged for commit: Remove changes in the working tree. Remove changes in the working tree and the staging area If you want to undo a staged but uncommitted change, you use the git checkout [commit-pointer] [paths] command.
The following demonstrates the usage of this to restore a delete directory. Remove staging area based on last commit change When you have added the changes of a file to the staging area, you can also revert the changes in the staging area base on the last commit. Using Git reset Moving the HEAD and branch pointer Sometimes you want to change the commmit your branch pointer is pointing to.
Depending on the specified parameters the git reset command performs the following: Resetting changes with git reset Finding commits that are no longer visible on a branch If you reset the branch pointer of a branch to a certain commit, the git log commands does not show the commits which exist after this branch pointer.
Deleting changes in the working tree and staging area for tracked files The git reset --hard command makes the working tree exactly match HEAD. If you have tracked files with modifications, you lose these changes with the above command.
Using git reset to squash commits git reset, squash commits As a soft reset does not remove your change to your files and index, you can use the git reset --soft command to squash several commits into one commit. Retrieving files from the history View file in different revision The git show command allows to see and retrieve files from branches, commits and tags. You can also make a copy of the file. One in the root of the Git repository and one in the current working directory address the pom.
Restore a deleted file in a Git repo You can checkout a file from the commit. See which commit deleted a file The git log command allows you to determine which commit deleted a file. Reverting a commit git revert You can revert commits via the git revert command.
Reverting a commit The following command demonstrates the usage of the git revert command. Resetting the working tree based on a commit Checkout based on commits and working tree git checkout, based on commit ID.
The commit ID is shown if you enter the git log command. Wed Jun 5 Checkout a commit To checkout a specific commit you can use the following command. Recovering lost commits To find such commits you can use the git reflog command.
The reflog command gives a history of the complete changes of the HEAD reference. It took something like Git to make everyone see the benefits and potential of DVCS — now someone just needs to refine it. The complexity serves a purpose, and is actually very elegant.
Until we end up with an iPad with Clippy running on it, that is useless for anyone with a working brain. But of course few people get to choose their VCS software anyway.
Refusing to use Git vastly reduces the number of open source projects you can contribute to. More like a waste of time. Being decentralized is great and so are easy branches, etc.
But the badly or apparently not at all designed user interface is still a problem, and not just because I have to read the man page every time I need to know which git reset flag I need. This is a nice write-up, and many of your points are valid. The thing that I like about Git is that despite what you say in 5 there is a lot of abstraction and quite a few nice shortcuts. For example, you can skip the whole staging process git add by passing the -a flag to git commit.
But the SVN concepts were easier to grasp. An extra option flag bolted onto one command is not an elegant abstraction whereas a setting that completely hid the index from sight would be. There is a sweet spot for SVN for which it works quite well: You update, code, update again, resolve the rare conflict, and commit — simple and easy to understand. If you want to create two separate patches for the same file, or you are asked to fix something in your patch, things will get messy quickly.
On the other end of the scale, if you are a major contributor to a project of nontrivial size, which needs versioning and backwards compatibility, or has big rewrite efforts which should not conflict with the continuous maintenance going on in other words, you need multiple branches , then SVN starts sucking bad: Files disappear from the diff because a merged add is actually not an add but a copy , commits start conflicting with themselves, code is duplicated without any edit conflict, and worse.
Not to mention that the whole thing is excruciatingly slow. Why make an inscrutable prompt when there are already a great prompt built in to git-completion. As someone relatively new to git, the thing I find really messy is submodules. Concept is great but the implementation sucks.
You really hit the nail on the head: Tools and apps with intuitive interfaces and workflows have been around for a couple of decades, at least. So expecting something to be straight-forward to operate is not an unrealistic dream.
But why do you want to make people change git for that? The complexity is harder to understand but if you have done so, it gives you much more power over your repository. But if you make it simpler, it will automatically destroy the advantages people love it for.
There are many ways that the usability of Git could be improved without decreasing its power at all. Yeah, I sometimes use EasyGit — but it definitely runs a risk of creating even more commands to remember. It should give pointers to the Git developers though.
I think the problem with feature branches is not that you can use them, but that you have to. Feature branches are great, when you do somewhat larger development. But they are a needless complexity when you just want to do some smaller changes. It does not allow you do to add names to you changes, but enforces that — even for the most trivial changes.
In projects where many people work simultaneously from a given base either large or small and merge only after many smaller changes, that forcing does no harm , because they would want to separate and name their changes anyway.
But there, persistent naming would actually be more helpful, so people can later retrieve the information, why a given change was added. The information is lost. So the forcing does not help for large projects and does harm for small projects. I like the way you explained certain things but the use of illustrative diagrams is more exciting…thanks.
Git makes simple things hard and has a completely unintuitive CLI. Frontends like EGit do not help much. Mercurial is DVCS done right, from the usability point of view. So the really interesting question is, why is Git so popular, when there is an equivalent but better alternative? Good strategic option likely not planned, though: Most times the maintainer chooses the DVCS, so cater to the maintainer to get spread around. Linus scratched his itch. Other maintainers had the same itch.
Now the users are itching all over, but they do not get to choose the DVCS except with hg-git. The way I like to put it is, Git was written by Martians.
All your points are dead on right. You only need onw git command and a 2nd version control to get by: The drawback is, that you dont find my tag in any git based project.
Try to download Android Cyanogenmod source. You will likely need a day even with a fast internet line. I love git, but I agree that some of the commands are difficult to understand, and man pages for commands like rebase are awful. Pull fetches all branches, but only merges or rebases the the currently checked out branch HEAD , push pushes ALL your branches to any matching remote branches unless you specify which branch you want to push to.
Git could definitely use a UI make over. I also agree that Git has a steep learning curve. I also like how open source projects use pull requests, which are infinitely better than the SVN equivalent: I also have trouble without the index when going back to SVN.
It doesn't seem like a super useful feature until you go back to a system without it. For those of you who that think that power has to come with a crappy user interface, take this post I wrote a year ago as an example of something that is an obvious mistake in the UI design.
It just makes it harder to learn. Even SVN is too difficult if you need to persuade non-software-developers to commit their code, so I agree with your thesis and then some! The philosophy behind Git and most DVCS out there is that you need that complexity to manage the problem of version control effectively. Man pages suck, but I reckon Git has about the best docs out there.
There is a huge community, a lot of books, etc. Not sure what the example is about, is that a regular workflow for you? Seems like an exceptional flow. The Git model is clearly appreciated by contributors, as seen by the massive adoption. What helps maintainers is also good for contributors. I just press commit and push. Yes this is scary about Git.
There is a back-up to get most changes back. Although sometimes useful, I feel this ease of destroying history is a golden rule Git broke. I do think in a DVCS world it makes some sense to clean up a bit. I like the IBM Jazz model a lot. Git is by no means a perfect tool.
But it is a massive improvement over SVN, especially for distributed open source development. If you need a complex tool to manage the problem, then why can Mercurial do it as well while staying simple? In that case you should just use it for some time — and have a look at hg-git, which provides you a transparent bridge. So everything you can do it git can be done in hg, too.
But most things are much easier. Let me know when you find such a system. The kind that uses the best tool for the job. I stand by my statement that git is the most powerful. You can moan about it all you want, but it works and it works really well. But then, it will still take some time. But it would completely invalidate any argument you can make about the power of git. You can blame hacker news for me being here http: This is precisely the reason I went with hg. I plan to get my feet wet with the latter and if it sticks, remove svn from my vernacular forever.
When using a DVCS and getting used to even the basics, going backwards is like taking a trip back to the stone age. You mean I have to be connected to the internet to commit? The remote server has to be up? Hg Workbench combines basically every UI dialog into one location which is amazingly useful. If I could choose it would always be Hg but there are things I pine for in Git, well specifically one: But there is one complaint I could add:.
No ability to edit log messages after the fact. In SVN you can if the repository admin enables it tweak log messages after the fact, and it turns out to be really handy. It has many other uses as well.
Because of it, editing log messages post facto is a conceptually consistent thing to do. Safe, easy, propagating history rewriting. Can I use this as my homepage? OK git has a steep learning curve, so we got someone to teach us, we mad some videos and made themn freely available here http: The combination does a very good job, obviates the need for command line and has returned far more than the learning cost and smart git licences: There are built-in tools in git for that.
This not only prevents from accidental or intentional history rewriting but also keeps your sources safe if your git server gets hacked. GPG does not solve 9. It just means pushing the cost of scaling onto the contributors. If you do not use the —rebase option when you pull the contributions, how does the rewrite get into your repository? Or, if you are particularly strict and you probably should be, if you are pining for svn , you could use —ff-only. If someone else does a rebase of stuff you already pulled, your history gets garbled, because you now have duplicate history.
If you send a pull request and the other one does a rebase, you have to prune out your copy — and rebase everything you did on top of the changes to the other changes. Honestly, I did not read very single word of your post. To be fare, the learning curve is much deeper than svn. This is not complete because the tool itself, but because it introduce lots idea of versioning control which is seem odd in other svn.
The workflow of versioning in git is quite different, and this workflow looks complicated at first, but once we get used to it, we find lots rational. Now I have come to the crossroads in my life. I always knew what the right path was. Without exception, I knew, but I never took it. It was too damn hard. He has chosen a path. Let him continue on his journey. Personally, I use the guide at http: I disagree that git does not provide meaningful abstractions.
The abstractions git provides are very much like the abstractions provided by a file system — and once you understand them, they are simple to work with. I dislike some of the defaults that git provides for example, I always have people I am working with put in their global config: But my distaste for those defaults is a reflection of the admin system provided by github, and git was designed before github. Finally, comparing git to svn is sort of like comparing google maps with a tumblr.
I can be totally in awe of the aesthetics of the tumblr and I can say all I want about how google maps does not have those design characteristics. And, in doing so, I would be pretty much missing the point of why people would like either one of them. Thank you for this well-timed post.
I am familiar with at least 9 source control systems, and I am paid-administrator-proficient with 4 of those, including ClearCase and Perforce. Git is such a mighty pain in the rear that I just gave up ever working on any open source project that uses it.
Its learning curve is a sucktastic cliff and you really do need to know almost everything about it before you can stop being dangerous. The tool should not be more complicated and inconsistent than the programming language source it protects.
But two branches in the same repository and you do not want to consider the target branch as the current branch? Why would you even want to do that? If you know git internals pretty well, you could probably find a way to forge a merge commit in memory without checking them out. Linus never ever studied properly even having such learning grands like Tannebaum. But I fully agree that Mercurial achieves the same as git without introducing the same kind of complex interface.
That does not make git a bad tool. It just makes it inferior — but heavily hyped. Even the first hate-thing is enough to not to read further for each one who really tried git. Other 9 are also a crap of subjective shit, decorated with lovely graphics: No more command line syntax to remember and it shows you a nice log on all the branches and past commits.
Just read your post for the first time, complete with the August update. But even back then, decentralized version control was not some new field of research. Linus was indeed bold to write his own system from scratch, and its success speaks for itself — but part of the reason he was free to do that was that he was the only constituent he had to satisfy. But even if we had seriously considered it, I think SVN would still be a centralized system today. The MediaWiki team has been going through a lot of pain, adopting Gerrit as a code review and Git management tool.
I guess my feeling in all this is that Git or something equally powerful is necessary, but not sufficient, for effective code management in distributed teams.
Besides the basic version control functions, intuitive and secure are the essential features of a version control tool. If the tool cannot even manage the source code safely, then why use it.
This new-fangled world with distributed workflows, and the new ideas that come with it are too much. In other words, more than half of the rant is a person used to wheelchair complaining about complexity of using wings.
The rant is only useful to Git maintainers really, just as a reminder that their user base is growing very diverse. I have a feeling you approached git expecting it to be like svn and got disappointed.
They are used for completely different workflows. They are suitable for completely different workflows. Try managing Linux kernel with svn…. If you have a 10 developer project maybe git is overkill, but if your project grows enough then git is the best choice around.
Just a note about Github, many people use pull requests PR as part of their daily workflow. A pull request should be opened early, very early, before any real changes have been made. The PR serves as a staging ground for discussions about the change, and a place for code review to occur. You can PR between two branches in the same repository. When I work on a project we all have push access to the same repository, but we still use PRs to coordinate changes.
Comparing Subversion to git is like comparing a single-speed bicycle to a Jeep Wrangler or notepad to Microsoft Word. But once you learn the basic theory you have a much more powerful tool at your disposal. This article is like hearing a whiny teenager complain about how hard his calculus class is because he thinks algebra should be enough math to get through a Computer Science degree.
Unfortunately, it was actually created because Linus needed a tool. It was created for Linus by Linus, and then he decided maybe other people would like it too and let everyone use it. Because Linus is a Computer Scientist and a Maintainer. And if they do, they certainly have no right to complain about it. I was thinking that, right up until I read the actual examples.
But that someone in your project decides what subset of Git features make most sense to you. Your post has good points. From my perspective, git is awesome and I can live with the complexity of the commands because doing a lot of the things I do now easily with git were painful and dangerous with the previous version control systems. CVS was incredibly limited and I was constantly repairing checkouts by editing files in the. Hmm, very interesting idea. That said, my impression is that people working to design new git user interfaces often have a rather limited view of what will want to be doing or what they should be wanting to do with git for example: It would be nice to have a tool that is really really simple for the simple things, yet also able to handle the more complex things when required, so it can be used by time-pressed non-programmers who would really prefer not to use version control at all and experienced developers with sophisticated needs alike.
Sensible defaults, easy installation, good documentation etc.. Unfortunately, I suspect that the tool would have to have absolutely no interface whatsoever to stop them being bamboozled. It is tempting to take an arrogant line and give up on these individuals, but I strongly disagree. There are highly intelligent domain specialists with limited time and little interest in software engineering issues, who nevertheless have a huge contribution to make to many projects.
Bringing their contributions under version control has a huge benefit in terms of communication, automation, organization, and team synchronization. We need to make our tools simpler. Not just a little bit simpler, but dramatically, radically, disappear-from-sight zero-interaction simple. Mercurial is still too complicated. Telling people that they are ignorant is not the solution, particularly when they represent valuable specialist expertise to the organization.
I would rather take a more conciliatory approach and save up my balance of good-will for situations where it really matters Like the importance of keeping files neatly organized. This is particularly true when the specialists in question view the software engineering function as something that is subordinate to them, and that should operate in the sole service of their objectives.
It would really help me if the tools just got out of the way, and I did not have to apologize for them and the inconvenience that they cause. If I am using prepackaged software, and I am working with someone that does not want to deal with it, there are a variety of options open, including providing wrappers click on this icon… and engaging someone else to support them if this fails, talk to Sam , and so on….
I agree with you that, amongst developers, learning new tools is rarely a significant issue — because we accept that as part of our job. I feel quite strongly that the same tools that we use to communicate, coordinate, synchronize and integrate work within an engineering team can also be used to fulfill the same needs across the entire organizational management structure, and that lack of systematic attention to such issues is the underlying reason for a great deal of inefficiency, waste and grief in a wide range of organizations.
I am an empiricist, and, as such, I think that empirical evidence is the most important, reliable source of truth in decision making. However, so many of our decision makers are so distant from the results of their decisions, and so removed from empirical truth, so distorted and disfigured by social and political pressures, that the quality of decisions in many organizations is simply execrable.
I wish for that benefit, that feedback loop, to be extended more widely through the organization. For people to cease hand-waving platitudes and generalizations, to get to grips with the detail of the problems that we face, and to realize that to make real progress, you need to do real work, not busywork.
Moving the bulk of our source code from svn to git was probably the best thing we ever did in our company, but we set up a pretty significant process and automated-merge-to-master intranet page that tied in with our work tracking system. We also left a bunch of third party stuff in svn because it just made more sense to not have every version of every binary on every clone of the git repo.
I originally got annoyed reading your rant until I realized it was pretty much a laundry list of everything we had to plumb around in getting widespread acceptance of a distributed source-control system in the company. Obviously we encourage GUIs like SmartGit, TortoiseGit and Git Extensions instead of the command line for everyone but the top end of power users, which paves over most of the usability complaints.
Yes, I wonder whether something git flow could be integrated into the core git suite. Those commands would also be able to give much more verbose output, and be free from the dual requirements of human usability and scriptability. Power-users activate the extensions they want. All the others have safe defaults. You could easily, for example, use svn to track the history of a branch managed in git, and you could use git to propagate changes introduced in that branch using svn.
I suppose, though, some people are saying that they do not need both features. People that are using svn but not git do not need to coordinate changes from a group of contributors, and people that use git but not svn do not need another copy of the document history.
Do remember that SVN has real branches, though they are implemented via the file system. Too many states This has been mentioned a few times now, detatched head, merge conflicted, in-the-middle-of-that-but-got-stuck state etc.
Do we need them all? This brings me on to: Git gives up Someone on hacker news summed this up: Like if something fucks up, talk me through the issue. This is carried through into GUIs for Git. Why not bring up a diff tool at that point? GUIs Ever try and learn about revision control? Read a blog about it? Have a buddy explain it? They ALL use diagrams at least the good ones do. Why not use that for git, and combine it with the user interface, we could call it a GUI!
Why not make a tool that covers the corner cases infact, not even the corner cases, just the edge cases, or the top-left-quadrant cases, or the non-svn-user case so you dont end up taking a user, confusing them, then sending them to the commandline. I suppose I am spoilt by this. I still get stuck and confused, and my head still gets detached, and then you have to guess which reset command to use.
Your point 13 is well made, too. Much of the complexity of Git revolves around trying to construct the right representation in your head, then take appropriate steps to resolve it. Perhaps there is one already, but it needs to be free. I played with tortoiseHG today without really reading the manual. I can commit, merge, rebase, revert and push to SVN entirely from the gui.
I got in some messed up states, broke a few things, but even so, after initial set-up I never typed hg again and solved all isues through the GUI. In fact, the only issues I really had were because i was doing operations against an SVN repository, which tortoiseHG has poor support for self admittedly.
The best part was it provided a simple graph so i could see all the changes i was making as i made them. UI is waaayyy too hard. Even using eGit in Eclipse is still complicated. And no, I am not dumb or lazy, I just need to make code and commit it. Back to SVN for me. I could intuitively make it work, even doing reasonably complicated things like rebasing, i managed to get it to work with a bit of playing around.
I will agree with you on exactly 2 points: The git command line tools are inconsistent and suck. The git man pages need to be improved. Your other points either stem from this, or are simply wrong. The only reason I know about them is because the man pages mention them for some reason. The way branches and tags etc work is exactly how I imagined they would before I was introduced to subversion.
So your problems there are mostly to do with you familiarity with subversion I guess. I think the fact that you use github adds complexity that you are attributing to git. We have our own server where people can pull and push, so that eliminates several of your complaints already. Naturally every other complaint when using the tool stems from these, because they describe the whole default user interface.
And the only way to avoid them is not using the tool directly, but using some program which uses the tool. You could say that you can improve every interface by not using it…. I hope git is not the final stop in the source control evolution. You can do it, but it has much higher friction than being able to use one language for one project. Personally, I use a variety of languages, and that seems to me to be a very different experience from someone coming up to me and asking me to drop what I am doing and work on something else.
And since i use them all anyways its automatic for me when i use them. Thts y i like using all of them. I have no problem interacting with git via emacs, because it is exactly the same as interacting with Mercurial or SVN. But an augmented GUI which works differently for the different systems is still a context switch which creates friction. And everyone who pulled from you has to do the same. Seriously, the whole reason pulls are not automated is so that you can exercise judgement about which pulls to make, and when.
Problems should be fixed by the person introducing them. That creates a shism in the project, and from there on it goes downward. The problem is brought upon you by someone else, but git makes it easy for mainainers to screw with contributors and hard for contributors to recover.
Git makes it easy to rewrite published history you can even do so remotely! When you are using git, you need to be a code review process before you accept changes.
If you define your policies properly, you might even be able to automate this process allowing anything that can be fast-forwarded, for example. That is still too short: Code review processes are exactly what creates the problem: Some code is not accepted, but someone already pulled it from another repo, then it is rebased, improved and accepted. Suddenly you have two versions of mostly the same changes floating around, which everyone has to join by hand and change all the code they based upon that.
A tool which makes it that easy to break lots of code of other people should have better ways to recover. But all you have is rebasing — which multiplies the effort when people share code very vividly.
And git offers nothing to recover from that condition. I experienced that first hand a few times: Rather it forces you to give your changes names which you will throw away. You are not forced to use names which you will throw away.
For example, you could use your own name. And you can keep using that same branch name for all of your changes, if that seems to be a good thing for you. Or you could use initials and the current date.
Or you can create a file documenting the changes and you can use the same name for your branch that you used for the file.
Or, you know, you could just stay on master and try to do all of your work there. That might not be the best idea, but it can be done. Same for time and anything else with which you try to replicate anonymous branching. It has no information correllation to the repo I work in, so it is just useless effort forced on my by the lack of anonymous branching.
Staying on master is hard for the same reason: Though that would be possible to fix by automatically creating a branch with a random name whenever someone commits on master. So, if you are seriously talking about modifying git, why not introduce new commands that work the way you want them to work?
Mercurial already does all that. And since the Mercurial devs discuss the interface in depth before adding anything, the number of unintuitive options is extremely low. There are several reasons: So you are not actually trying to solve the problem of how to improve the UI. You are just finding reasons to object to it. Just say what you like about hg and have fun with it….
I am forced to use git in some projects or rather: Due to that I think that promoting git over equally powerful but easier to use solutions is a problem for making free DVCS systems become the de-facto standard — with the goal of replacing all unfree versioning tools from VSS over Clearcase to TimeMachine.
And those are the people who could really help free software. Please read this with a grain of salt: Git is a great tool. I just think that it is not the best, despite its popularity, and that other tools would draw more people towards free software and DVCS — and even more importantly: In my opinion git is pretty much unfixable for several reasons: In my mind the biggest problem is that I need to tell everyone I work with to use:.
I own my local repository, and it can only include changes that I bring into it. And if someone creates a problem for someone else, that person is responsible for fixing it. That last concept is worth repeating: If you are working with people that will not take responsibility for fixing the problems that they create, your life is going to be unpleasant. Personally, I think that that problem should not be considered a technical problem, but a social problem.
I do wish that git could be configured to never allow a local name for a branch to differ from the remote name for a branch. But by restricting myself to the above commands and note that I never name a branch during push nor pull , I get close enough to that ideal for me to get my job done.
I think we should ignore ignorant comments like that. But if they want to have a coherent discussion about the problems that they are encountering, and I have the time and interest, I might try seeing if I can talk with them on some sort of reasonable basis. In my mind the biggest problem is that I need to tell everyone I work with to use: If you manage to get people to restrict themselves to those commands, you should have a quite solid setup which people can enter nicely.
Is there any reason to not prune? If it exists in origin and not locally, why should I ever not want the branch from origin? But restricting checkout to getting branches is the best reason I ever saw for forcing people to use branches. You should only need pull, if you work on a remote branch, after all. So cut pull and always merge remote branches explicitely.
Though it would be nice to be able to branch it instead of having to copy your commands. Being able to show a diff between your commands and those I consider mostly sane: In Linux kernel development you have clear hierarchies: There is Linus and there are his lieutenants.
Some lieutenants release special builds of their domain. And you have groups working on a clearly limited area of the kernel, who rebase once their changes get accepted. Now imagine this as a writing group I am a hobby author, so my VCS has to work for that task, too. Now the rewritten part gets accepted, but rebased, so history appears linear. You might have someone in charge of publishing the final book, but if the writers coordinate independently, he can either not rebase at all, or break their work repeatedly.
As such git cements a hierarchy: Interestingly Linus himself warns against rebasing — possibly for exactly that reason: But git itself does not help you with that: It will happily break other peoples history, without even giving a warning. It does not track for you what has been published and thus should not be committed and if a given rebase would be safe.
You have to keep all that in your mind — where you would normally rather keep more of the structure of your code. So git makes it very easy for you to make mistakes, but really hard to fix them because other people have to fix your mistakes in their repositories.
And that irritates me. Right… do not accept rebases. Anyways, if someone sent me a rebase and I wanted the change, I might accept the changed content without accepting the history change. But I think that these are already far too many commands. Still too much, but hard to get smaller. Being able to show a diff between your commands and those I consider mostly sane. I advise people not to use git branch with a branch name. When your team is productively generating several branches an hour, after a few months things can start slowing down.
So someone needs to delete the branches from the remote and fetch —prune copies those deletions locally. It does not have that right now, though, so I have to cope with this issue somehow. I can easily imagine a new command set which is more technical, requiring explicit keywords to represent each of these three data structures.
Until then, I use http: All of this is additive only. So this brings down everything from git and possibly chokes if something conflicting has happened. So far, the one time that that has happened, I went to the developer who caused the problem, talked to him about it, and he cleaned up the problem. But I forgot to mention git branch -a in my list of commands we use and perhaps in single remote mode it should do an implicit git fetch, if it can. Anyways, not everyone uses github, and things that seem necessary when using github can be silly in other contexts.
So, anyways, my thing has been to discover enough about how git works to use it, as is, sensibly. So far those issues all have seemed to resolve around the idea that local branch names can be different from remote branch names.
For fetch without —prune, I think it would be nice to have it prune those branches automatically which are neither checked out nor changed locally nor ancestors of local branches. That way you would likely never need the —prune, because all useless remote branches would disappear automatically and the others would stick. Additionally it has diverging-change detection, though: When you pull the changes from him with Mercurial, you now get either the refactor branch with 2 heads for named branches or the bookmarks refactor and refactor mark.
If you use it with a shared repository, the bookmarks would instead be named refactor and refactor default, since the default remote repository is called default in mercurial. That could be annoying.
In other words, it would assume that upstream was available and any remote branch would be assumed to exist locally — the local repository would be a cache of the remote. Tags and reflog may be ignored. Web- Interfaces like cgit can produce one for an arbitrary hash if you do at one time need one just to eschew the revision control system.
Yes, history is the important product, because it can reduce the amount of WTFs. Or a system which works better for them. History can help, but good code goes first. And if you worry too much about the history, it can have a bad impact on your code. How best to learn Git? But, what about the conclusion? Are you certain about the supply? Overall, I understand your frustrations with git.
I probably once shared them, but as I get more and more used to git, I find myself bumping into the sharp edges less often. What capricious use of random letters for commands! And that you have to know to choose checkout. You only get something extra, if you happen to be maintaines of a program with more than developers — and then at the expense of the others. That means, that my perception today is skewed, but for good reasons….
Your top ten is very fair IMHO. I guess your point 7 is my biggest concern. For a company to keep a central repo of their expensive IP, requires someone to babysit it so no idiot can rebase the history into oblivion. This is a crazy waste of time and money. Hoping that someone has an untarnished clone of it on a PC somewhere that you can recover is not a mitigating strategy!
Second is that CM should be as close to invisible as possible for the humble developer. A company pays them good money to develop IP.
While they are doing that, your other n-1 developers will be sat there waiting patiently.. You always need someone who knows the internals of a SCM system, who can set up the branches and the integration strategy..
You could have a look at Mercurial. An example Workflow I wrote just requires the developers to commit and merge — and I can explain it in 3 steps:. Only maintainers touch stable. They always start at default since you do all the work on default. More advanced developers can use feature branches and a host of other features, but no one has to.
Yep you have to take a solid week out of your life and work sched to learn the monster. Get the concepts then use smartgit is my plan.
Thanks for the post. While they are smart, they are not brilliant. From my time in the field it seems like a lot of people have forewent actually looking at the problem of VCS. Most chose a centralized one and left the developers to fight with it. In my opinion, things like Eclipse cover up the giant gaping hole in centralized versioning systems.
I think Linus saw the flaws in existing tools and truly tried to create one that would help everyone. It IS complex, but that complexity comes with great flexibility. I am able to use Git to produce just about any imaginable workflow. Local branching support and stash are the bar for how much git will be of use to you. There are people who would rather work surrounded by a local VCS bubble in which they can make their changes without being affected by the unwashed masses.
I find commits important. I find what I commit on what branch to be important. I want to keep around experimental changes locally in case I need to use them again. Git is a replacement for not only a centralized version control system, but also a replacement for Eclipse local history. It functions in both ways and allows you to work independently of what you commit, allowing you to push what you want when you want where you want.
I have not seen another VCS even come close when you look at the ideas it abstracts. But is VI not difficult to learn at first? Was bash a walk in the park?
I find git better than the alternatives because after I learned the basics of what I was actually trying to do, I can stack overflow a way to get there. People who like to get shit done without the tooling getting in their way. I cannot tell you how many times you wind up resorting to making a copy of your whole workspace just so you can get SVN or CVS out of some retard state in Eclipse and then had to pull diffs back in.
I have never done so with Git…because I never had the need to. Let it help you. Mercurial showed me that it is possible to have all that flexibility without the complexity of git. The decentralized model gives a lot of flexibility and I would not want to work without that.
But git makes it pretty hard for normal developers to harness the power of the model while Mercurial makes it really easy, giving all the safety and convenience without the pain of git.
So I disagree with your sentence. It implies that the complexity of git is required to get the flexibility of the decentralized model. And that is not true. SVN is, indeed, very simple to understand. I know training guys from my company, most people non-technical are able to work with it just fine after one hour of basic training. And merging is merging, the git heads often pretend to save a lot of time on merging with their great system while in fact most time is spent on resolving the conflicts in actual contents.
And a VCS can hardly help you there. Did you read the same article above as I did? Git is awful Smash Company. Git is like a ferrari covered in fresh dog turd. Yes, the fundamentals are awesome. Consider a really, really simple and common action: How on earth did they do such an awful job?
The whole thing is inexcusable. Linus Torvalds is actually against GitHubs pull requests. You were supposed to send a patch to the ML and then a maintainer merged the patch. Submit your college class semester project.
Git is NOT happy at Intel. In this environment, Git sucks. Focus on their code, their features. Code analysis tools and Build machines will catch errors and reject submits. In this environment, SVN or Perforce are kings.
Oh, how I wish this post existed when I was forced into the Git world. It would have helped me understand a little bit better how to hold my head when I try to understand anything related to Git. Reblogged this on Sergey Tihon's Blog and commented: Exactly the same emotions. Steve, thank you so much for this summary. It points out most things I have been feeling for git in the last couple of years.
Honestly, git is a toy from nerds made for other githeads ticking the same way as they do. It seems to match the taste of many project managers who then quickly switch to git, forcing whole communities to use this user-unfriendly software. I thought I was too old, or too stupid, or a little bit of both. I am glad I am not the only one with the same frustrations. I have been using VCS for 17 years. I spent a lot of time learning each and everyone one of them. Knowing my tool is important.
I was able to master SVN and it was not frustrating. I found Bazzar more intuitive and easy to use than git. I was confident with Bazzar even though I did not use it for a long time.
I had the feeling that I was controlling my project. With GIT, I am not confident at all. I am always cautious and nervous and.. Trying to master git is very frustrating. Pretty much the same feeling as you. The reset command is still black magic to me even though I have spent plenty of time reading how it works. You know something is wrong when you need to figure out all the things the commands will do before running them should I use the —soft flag when reseting to leave the index and tree untouched?
My take is that resets and other such reversions should never be pushed off into another repository — they are only for cleaning up messes locally. And, eventually, pruning the damaged branches. I do not get to control what other people do in their own repositories. They all say something different and give no valid examples. And, yes, everyone can agree to rebase instead of merge, but that means that you lose the ability to revert to earlier versions of the code!
If you have a shared history with someone and you really want a re-arranged view of history, you really should put that new view into a new branch. Otherwise, you are not using git as a version control system which might be fine, but you should never expect that other people want to lose their version control abilities.
Thank you for that! Git caters to the maintainer, and who chooses the VCS? Interestingly most projects which did a clear check of requirements mozilla, google, python came out in favor of Mercurial with the disclaimer: Consider, for example, consider: On the other hand, Linus Torvalds had some interesting comments on git, and github, visible at https: That said, everyone has their own needs, and their own ideas of how to address those needs, so personally I do not buy into the idea that one tool can be universally superior to another tool — I am much more interested in the reasons a person uses to pick a tool than I am in the choice they made.
But, sometimes these discussions reveal the kind of view points that I am interested in…. Why you would push the burden of VCS maintenance and branching i.
But the google hosting is no real counter-example: It shows a handful of projects which chose to not use googlecode…. The example I showed is not what google does today it now also offers git for code hosting, see the group effects , but why they chose to use Mercurial:. I have more usability problems with git itself than with github. I wrote some of my reasons and wishes herein our previous discussion here: Many thanks for this article.
Not because of you but because of the subject matter. Anything about git automatically makes my brain shutdown. A few weeks ago I ran into a revolving door and broke my nose.
It was less painful that git branching. As an example of git being somewhat batshit insane, this is the method I found necessary to properly and fully garbage collect the repo. There might be some unnecessary steps in there, but yeah… this took quite a while to figure out! No git, I do not want you to provide backup services in case I am stupid, I do my own backups before dangerous operations. The closest to garbage that hg has is backup bundles.
There are thousands of medium size, commercial project for which svn is perfect. The author is absolutely correct. Git is a nightmare. What was the sequence of events exactly?
Haha — pshew this post makes me feel much less stupid. Plus I learned more about how git works from this page then half the other git instruction sources including the oreilly book…LOL!