Пример #1
0
        public static string Merge(string @ref)
        {
            Files.AssertInRepo();
            Config.AssertNotBare();

            // Get the `receiverHash`, the hash of the commit that the
            // current branch is on.
            var receiverHash = Refs.Hash("HEAD");

            // Get the `giverHash`, the hash for the commit to merge into the
            // receiver commit.
            var giverHash = Refs.Hash(@ref);

            // Abort if head is detached.  Merging into a detached head is not
            // supported.
            if (Refs.IsHeadDetached())
            {
                throw new Exception("unsupported");
            }

            // Abort if `ref` did not resolve to a hash, or if that hash is
            // not for a commit object.
            if (giverHash == null || Objects.Type(Objects.Read(giverHash)) != "commit")
            {
                throw new Exception(@ref + ": expected commit type");
            }

            // Do not merge if the current branch - the receiver - already has
            // the giver's changes.  This is the case if the receiver and
            // giver are the same commit, or if the giver is an ancestor of
            // the receiver.
            if (Objects.IsUpToDate(receiverHash, giverHash))
            {
                return("Already up-to-date");
            }

            // Get a list of files changed in the working copy.  Get a list
            // of the files that are different in the receiver and giver. If
            // any files appear in both lists then abort.
            var paths = Diff.ChangedFilesCommitWouldOverwrite(giverHash);

            if (paths.Length > 0)
            {
                throw new Exception("local changes would be lost\n" + string.Join("\n", paths) + "\n");
            }

            // If the receiver is an ancestor of the giver, a fast forward
            // is performed.  This is possible because there is already a
            // commit that incorporates all of the giver's changes into the
            // receiver.
            if (Core.Merge.CanFastForward(receiverHash, giverHash))
            {
                // Fast forwarding means making the current branch reflect the
                // commit that `giverHash` points at.  The branch is pointed
                // at `giverHash`.  The index is set to match the contents of
                // the commit that `giverHash` points at.  The working copy is
                // set to match the contents of that commit.
                Core.Merge.WriteFastForwardMerge(receiverHash, giverHash);
                return("Fast-forward");
            }

            // If the receiver is not an ancestor of the giver, a merge
            // commit must be created.

            // The repository is put into the merge state.  The
            // `MERGE_HEAD` file is written and its contents set to
            // `giverHash`.  The `MERGE_MSG` file is written and its
            // contents set to a boilerplate merge commit message.  A
            // merge diff is created that will turn the contents of
            // receiver into the contents of giver.  This contains the
            // path of every file that is different and whether it was
            // added, removed or modified, or is in conflict.  Added files
            // are added to the index and working copy.  Removed files are
            // removed from the index and working copy.  Modified files
            // are modified in the index and working copy.  Files that are
            // in conflict are written to the working copy to include the
            // receiver and giver versions.  Both the receiver and giver
            // versions are written to the index.
            Core.Merge.WriteNonFastForwardMerge(receiverHash, giverHash, @ref);

            // If there are any conflicted files, a message is shown to
            // say that the user must sort them out before the merge can
            // be completed.
            if (Core.Merge.HasConflicts(receiverHash, giverHash))
            {
                return("Automatic merge failed. Fix conflicts and commit the result.");
            }

            return(Gitlet.Commit(new CommitOptions()));
        }