Commit graph

446 commits

Author SHA1 Message Date
Junio C Hamano 280bd44551 Merge branch 'en/merge-recursive-cleanup'
The merge-recursive machiery is one of the most complex parts of
the system that accumulated cruft over time.  This large series
cleans up the implementation quite a bit.

* en/merge-recursive-cleanup: (26 commits)
  merge-recursive: fix the fix to the diff3 common ancestor label
  merge-recursive: fix the diff3 common ancestor label for virtual commits
  merge-recursive: alphabetize include list
  merge-recursive: add sanity checks for relevant merge_options
  merge-recursive: rename MERGE_RECURSIVE_* to MERGE_VARIANT_*
  merge-recursive: split internal fields into a separate struct
  merge-recursive: avoid losing output and leaking memory holding that output
  merge-recursive: comment and reorder the merge_options fields
  merge-recursive: consolidate unnecessary fields in merge_options
  merge-recursive: move some definitions around to clean up the header
  merge-recursive: rename merge_options argument to opt in header
  merge-recursive: rename 'mrtree' to 'result_tree', for clarity
  merge-recursive: use common name for ancestors/common/base_list
  merge-recursive: fix some overly long lines
  cache-tree: share code between functions writing an index as a tree
  merge-recursive: don't force external callers to do our logging
  merge-recursive: remove useless parameter in merge_trees()
  merge-recursive: exit early if index != head
  Ensure index matches head before invoking merge machinery, round N
  merge-recursive: remove another implicit dependency on the_repository
  ...
2019-10-15 13:47:59 +09:00
Junio C Hamano 3ff6af7753 Merge branch 'nd/switch-and-restore'
Resurrect a performance hack.

* nd/switch-and-restore:
  checkout: add simple check for 'git checkout -b'
2019-09-30 13:19:27 +09:00
Junio C Hamano d1a251a1fa Merge branch 'en/checkout-mismerge-fix'
Fix a mismerge that happened in 2.22 timeframe.

* en/checkout-mismerge-fix:
  checkout: remove duplicate code
2019-09-09 12:26:36 -07:00
Derrick Stolee 313677627a checkout: add simple check for 'git checkout -b'
The 'git switch' command was created to separate half of the
behavior of 'git checkout'. It specifically has the mode to
do nothing with the index and working directory if the user
only specifies to create a new branch and change HEAD to that
branch. This is also the behavior most users expect from
'git checkout -b', but for historical reasons it also performs
an index update by scanning the working directory. This can be
slow for even moderately-sized repos.

A performance fix for 'git checkout -b' was introduced by
fa655d8411 (checkout: optimize "git checkout -b <new_branch>"
2018-08-16). That change includes details about the config
setting checkout.optimizeNewBranch when the sparse-checkout
feature is required. The way this change detected if this
behavior change is safe was through the skip_merge_working_tree()
method. This method was complex and needed to be updated
as new options were introduced.

This behavior was essentially reverted by 65f099b ("switch:
no worktree status unless real branch switch happens"
2019-03-29). Instead, two members of the checkout_opts struct
were used to distinguish between 'git checkout' and 'git switch':

    * switch_branch_doing_nothing_is_ok
    * only_merge_on_switching_branches

These settings have opposite values depending on if we start
in cmd_checkout or cmd_switch.

The message for 64f099b includes "Users of big repos are
encouraged to move to switch." Making this change while
'git switch' is still experimental is too aggressive.

Create a happy medium between these two options by making
'git checkout -b <branch>' behave just like 'git switch',
but only if we read exactly those arguments. This must
be done in cmd_checkout to avoid the arguments being
consumed by the option parsing logic.

This differs from the previous change by fa644d8 in that
the config option checkout.optimizeNewBranch remains
deleted. This means that 'git checkout -b' will ignore
the index merge even if we have a sparse-checkout file.
While this is a behavior change for 'git checkout -b',
it matches the behavior of 'git switch -c'.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Acked-by: Elijah Newren <newren@gmail.com>
Acked-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-30 10:20:05 -07:00
Junio C Hamano 072735ea58 Merge branch 'vn/restore-empty-ita-corner-case-fix'
"git checkout" and "git restore" to re-populate the index from a
tree-ish (typically HEAD) did not work correctly for a path that
was removed and then added again with the intent-to-add bit, when
the corresponding working tree file was empty.  This has been
corrected.

* vn/restore-empty-ita-corner-case-fix:
  restore: add test for deleted ita files
  checkout.c: unstage empty deleted ita files
2019-08-22 12:34:11 -07:00
Elijah Newren 724dd767b2 cache-tree: share code between functions writing an index as a tree
write_tree_from_memory() appeared to be a merge-recursive special that
basically duplicated write_index_as_tree().  The two have a different
signature, but the bigger difference was just that write_index_as_tree()
would always unconditionally read the index off of disk instead of
working on the current in-memory index.  So:

  * split out common code into write_index_as_tree_internal()

  * rename write_tree_from_memory() to write_inmemory_index_as_tree(),
    make it call write_index_as_tree_internal(), and move it to
    cache-tree.c

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-19 10:08:03 -07:00
Elijah Newren b4db8a2b76 merge-recursive: remove useless parameter in merge_trees()
merge_trees() took a results parameter that would only be written when
opt->call_depth was positive, which is never the case now that
merge_trees_internal() has been split from merge_trees().  Remove the
misleading and unused parameter from merge_trees().

While at it, add some comments explaining how the output of
merge_trees() and merge_recursive() differ.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-19 10:08:03 -07:00
Elijah Newren 65c01c6442 checkout: provide better conflict hunk description with detached HEAD
When running 'git checkout -m' and using diff3 style conflict markers,
we want all the conflict hunks (left-side, "common" or "merge base", and
right-side) to have label markers letting the user know where each came
from.  The "common" hunk label (o.ancestor) came from
old_branch_info->name, but that is NULL when HEAD is detached, which
resulted in a blank label.  Check for that case and provide an
abbreviated commit hash instead.

(Incidentally, this was the only case in the git codebase where
merge_trees() was called with opt->ancestor being NULL.  A subsequent
commit will prevent similar problems by enforcing that merge_trees()
always be called with opt->ancestor != NULL.)

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-16 12:47:20 -07:00
Elijah Newren acb7da05ac checkout: remove duplicate code
Both commit a7256debd4 ("checkout.txt: note about losing staged
changes with --merge", 2019-03-19) from nd/checkout-m-doc-update and
commit 6eff409e8a ("checkout: prevent losing staged changes with
--merge", 2019-03-22) from nd/checkout-m were included in git.git
despite the fact that the latter was meant to be v2 of the former.
The merge of these two topics resulted in a redundant chunk of code;
remove it.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-16 09:58:00 -07:00
Jean-Noël Avila 182f59daf0 l10n: reformat some localized strings for v2.23.0
Signed-off-by: Jean-Noël Avila <jn.avila@free.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-06 12:43:43 -07:00
Varun Naik ecd72042de checkout.c: unstage empty deleted ita files
It is possible to delete a committed file from the index and then add it
as intent-to-add. After `git checkout HEAD <pathspec>`, the file should
be identical in the index and HEAD. The command already works correctly
if the file has contents in HEAD. This patch provides the desired
behavior even when the file is empty in HEAD.

`git checkout HEAD <pathspec>` calls tree.c:read_tree_1(), with fn
pointing to checkout.c:update_some(). update_some() creates a new cache
entry but discards it when its mode and oid match those of the old
entry. A cache entry for an ita file and a cache entry for an empty file
have the same oid. Therefore, an empty deleted ita file previously
passed both of these checks, and the new entry was discarded, so the
file remained unchanged in the index. After this fix, if the file is
marked as ita in the cache, then we avoid discarding the new entry and
add the new entry to the cache instead.

This change should not affect newly added ita files. For those, inside
tree.c:read_tree_1(), tree_entry_interesting() returns
entry_not_interesting, so fn is never called.

Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Varun Naik <vcnaik94@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-02 10:28:10 -07:00
Junio C Hamano f496b064fc Merge branch 'nd/switch-and-restore'
Two new commands "git switch" and "git restore" are introduced to
split "checking out a branch to work on advancing its history" and
"checking out paths out of the index and/or a tree-ish to work on
advancing the current history" out of the single "git checkout"
command.

* nd/switch-and-restore: (46 commits)
  completion: disable dwim on "git switch -d"
  switch: allow to switch in the middle of bisect
  t2027: use test_must_be_empty
  Declare both git-switch and git-restore experimental
  help: move git-diff and git-reset to different groups
  doc: promote "git restore"
  user-manual.txt: prefer 'merge --abort' over 'reset --hard'
  completion: support restore
  t: add tests for restore
  restore: support --patch
  restore: replace --force with --ignore-unmerged
  restore: default to --source=HEAD when only --staged is specified
  restore: reject invalid combinations with --staged
  restore: add --worktree and --staged
  checkout: factor out worktree checkout code
  restore: disable overlay mode by default
  restore: make pathspec mandatory
  restore: take tree-ish from --source option instead
  checkout: split part of it to new command 'restore'
  doc: promote "git switch"
  ...
2019-07-09 15:25:44 -07:00
Nguyễn Thái Ngọc Duy d16dc428b4 switch: allow to switch in the middle of bisect
In c45f0f525d (switch: reject if some operation is in progress,
2019-03-29), a check is added to prevent switching when some operation
is in progress. The reason is it's often not safe to do so.

This is true for merge, am, rebase, cherry-pick and revert, but not so
much for bisect because bisecting is basically jumping/switching between
a bunch of commits to pin point the first bad one. git-bisect suggests
the next commit to test, but it's not wrong for the user to test a
different commit because git-bisect cannot have the knowledge to know
better.

For this reason, allow to switch when bisecting (*). I considered if we
should still prevent switching by default and allow it with
--ignore-in-progress. But I don't think the prevention really adds
anything much.

If the user switches away by mistake, since we print the previous HEAD
value, even if they don't know about the "-" shortcut, switching back is
still possible.

The warning will be printed on every switch while bisect is still
ongoing, not the first time you switch away from bisect's suggested
commit, so it could become a bit annoying.

(*) of course when it's safe to do so, i.e. no loss of local changes and
stuff.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-06-20 13:31:22 -07:00
Nguyễn Thái Ngọc Duy 2f0896ec3a restore: support --patch
git-restore is different from git-checkout that it only restores the
worktree by default, not both worktree and index. add--interactive
needs some update to support this mode.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-07 13:04:47 +09:00
Nguyễn Thái Ngọc Duy a5e5f399ca restore: replace --force with --ignore-unmerged
Use a more specific option name to express its purpose. --force may come
back as an alias of --ignore-unmerged and possibly more. But since this
is a destructive operation, I don't see why we need to "force" anything
more. We already don't hold back.

When 'checkout --force' or 'restore --ignore-unmerged' is used, we may
also print warnings about unmerged entries being ignore. Since this is
not exactly warning (people tell us to do so), more informational, let
it be suppressed if --quiet is given. This is a behavior change for
git-checkout.

PS. The diff looks a bit iffy since --force is moved to
add_common_switch_branch_options() (i.e. for switching). But
git-checkout is also doing switching and inherits this --force.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-07 13:04:47 +09:00
Nguyễn Thái Ngọc Duy 3a733ce523 restore: default to --source=HEAD when only --staged is specified
"git restore --staged" without --source does not make much sense since
by default we restore from the index.  Instead of copying the index to
itself, set the default source to HEAD in this case, yielding behavior
that matches "git reset -- <paths>".

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-07 13:04:47 +09:00
Nguyễn Thái Ngọc Duy e3ddd3b5e5 restore: reject invalid combinations with --staged
git-checkout rejects plenty of invalid option combinations. Since
git-checkout is equivalent of either

    git restore --source --staged --worktree

or

    git restore --worktree

that still leaves the new mode 'git restore --index' unprotected. Reject
some more invalid option combinations.

The other new mode 'restore --source --worktree' does not need anything
else.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-07 13:04:47 +09:00
Nguyễn Thái Ngọc Duy 183fb44fd2 restore: add --worktree and --staged
'git checkout <tree-ish> <pathspec>' updates both index and
worktree. But updating the index when you want to restore worktree
files is non-intuitive. The index contains the data ready for the next
commit, and there's no indication that the user will want to commit
the restored versions.

'git restore' therefore by default only touches worktree. The user has
the option to update either the index with

    git restore --staged --source=<tree> <path>  (1)

or update both with

    git restore --staged --worktree --source=<tree> <path> (2)

PS. Orignally I wanted to make worktree update default and form (1)
would add index update while also updating the worktree, and the user
would need to do "--staged --no-worktree" to update index only. But it
looks really confusing that "--staged" option alone updates both. So
now form (2) is used for both, which reads much more obvious.

PPS. Yes form (1) overlaps with "git reset <rev> <path>". I don't know
if we can ever turn "git reset" back to "_always_ reset HEAD and
optionally do something else".

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-07 13:04:47 +09:00
Nguyễn Thái Ngọc Duy 4058199c0e checkout: factor out worktree checkout code
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-07 13:04:47 +09:00
Nguyễn Thái Ngọc Duy a6cfb9ba36 restore: disable overlay mode by default
Overlay mode is considered confusing when the command is about
restoring files on worktree. Disable it by default. The user can still
turn it on, or use 'git checkout' which still has overlay mode on by
default.

While at it, make the check in checkout_branch() stricter. Neither
--overlay or --no-overlay should be accepted in branch switching mode.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-07 13:04:47 +09:00
Nguyễn Thái Ngọc Duy be8ed5022b restore: make pathspec mandatory
"git restore" without arguments does not make much sense when
it's about restoring files (what files now?). We could default to
either

    git restore .

or

    git restore :/

Neither is intuitive. Make the user always give pathspec, force the
user to think the scope of restore they want because this is a
destructive operation.

"git restore -p" without pathspec is an exception to this
because it really is a separate mode. It will be treated as running
patch mode on the whole worktree.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-07 13:04:47 +09:00
Nguyễn Thái Ngọc Duy c9c935f6d4 restore: take tree-ish from --source option instead
This is another departure from 'git checkout' syntax, which uses -- to
separate ref and pathspec. The observation is restore (or "git
checkout -- <pathspec>") is most often used to restore some files from
the index. If this is correct, we can simplify it by taking away the
ref, so that we can write

    git restore some-file

without worrying about some-file being a ref and whether we need to do

    git restore -- some-file

for safety. If the source of the restore comes from a tree, it will be
in the form of an option with value, e.g.

    git restore --source=this-tree some-file

This is of course longer to type than using "--". But hopefully it
will not be used as often, and it is clearly easier to understand.

dwim_new_local_branch is no longer set (or unset) in cmd_restore_files()
because it's irrelevant because we don't really care about dwim-ing.
With accept_ref being unset, dwim can't happen.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-07 13:04:47 +09:00
Nguyễn Thái Ngọc Duy 46e91b663b checkout: split part of it to new command 'restore'
Previously the switching branch business of 'git checkout' becomes a
new command 'switch'. This adds the restore command for the checking
out paths path.

Similar to git-switch, a new man page is added to describe what the
command will become. The implementation will be updated shortly to
match the man page.

A couple main differences from 'git checkout <paths>':

- 'restore' by default will only update worktree. This matters more
  when --source is specified ('checkout <tree> <paths>' updates both
  worktree and index).

- 'restore --staged' can be used to restore the index. This command
  overlaps with 'git reset <paths>'.

- both worktree and index could also be restored at the same time
  (from a tree) when both --staged and --worktree are specified. This
  overlaps with 'git checkout <tree> <paths>'

- default source for restoring worktree and index is the index and
  HEAD respectively. A different (tree) source could be specified as
  with --source (*).

- when both index and worktree are restored, --source must be
  specified since the default source for these two individual targets
  are different (**)

- --no-overlay is enabled by default, if an entry is missing in the
  source, restoring means deleting the entry

(*) I originally went with --from instead of --source. I still think
  --from is a better name. The short option -f however is already
  taken by force. And I do think short option is good to have, e.g. to
  write -s@ or -s@^ instead of --source=HEAD.

(**) If you sit down and think about it, moving worktree's source from
  the index to HEAD makes sense, but nobody is really thinking it
  through when they type the commands.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-07 13:04:47 +09:00
Junio C Hamano 4a3ed2bec6 Merge branch 'nd/checkout-m'
"git checkout -m <other>" was about carrying the differences
between HEAD and the working-tree files forward while checking out
another branch, and ignored the differences between HEAD and the
index.  The command has been taught to abort when the index and the
HEAD are different.

* nd/checkout-m:
  checkout: prevent losing staged changes with --merge
  read-tree: add --quiet
  unpack-trees: rename "gently" flag to "quiet"
  unpack-trees: keep gently check inside add_rejected_path
2019-04-25 16:41:14 +09:00
Junio C Hamano 4284497396 Merge branch 'jk/unused-params-even-more'
Code cleanup.

* jk/unused-params-even-more:
  parse_opt_ref_sorting: always use with NONEG flag
  pretty: drop unused strbuf from parse_padding_placeholder()
  pretty: drop unused "type" parameter in needs_rfc2047_encoding()
  parse-options: drop unused ctx parameter from show_gitcomp()
  fetch_pack(): drop unused parameters
  report_path_error(): drop unused prefix parameter
  unpack-trees: drop unused error_type parameters
  unpack-trees: drop name_entry from traverse_by_cache_tree()
  test-date: drop unused "now" parameter from parse_dates()
  update-index: drop unused prefix_length parameter from do_reupdate()
  log: drop unused "len" from show_tagger()
  log: drop unused rev_info from early output
  revision: drop some unused "revs" parameters
2019-04-25 16:41:12 +09:00
Junio C Hamano 3feaacbaa1 Merge branch 'nd/checkout-m-doc-update'
Doc about the above.

* nd/checkout-m-doc-update:
  checkout.txt: note about losing staged changes with --merge
2019-04-16 19:28:10 +09:00
Nguyễn Thái Ngọc Duy 1806c29f2e switch: make --orphan switch to an empty tree
Switching and creating branches always involves knowing the
<start-point> to begin the new branch from. Sometimes, people want to
create a new branch that does not have any commits yet; --orphan is a
flag to allow that.

--orphan overrides the default of HEAD for <start-point> instead causing
us to start from an empty history with all tracked files removed from
the index and working tree. The use of --orphan is incompatible with
specifying a <start-point>.

A note on the implementation. An alternative is just create a dummy
commit in-core with empty tree and switch to it. But there's a chance
the commit's SHA-1 may end up somewhere permanent like reflog. It's best
to make sure "commit" pointer is NULL to avoid it.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:57:00 +09:00
Nguyễn Thái Ngọc Duy c45f0f525d switch: reject if some operation is in progress
Unless you know what you're doing, switching to another branch to do
something then switching back could be confusing. Worse, you may even
forget that you're in the middle of something. By the time you realize,
you may have done a ton of work and it gets harder to go back.

A new option --ignore-in-progress was considered but dropped because it
was not exactly clear what should happen. Sometimes you can switch away
and get back safely and resume the operation. Sometimes not. And the
git-checkout behavior is automatically clear merge/revert/cherry-pick,
which makes it a bit even more confusing [1].

We may revisit and add this option in the future. But for now play it
safe and not allow it (you can't even skip this check with --force). The
user is suggested to cancel the operation by themselves (and hopefully
they do consider the consequences, not blindly type the command), or to
create a separate worktree instead of switching. The third option is
the good old "git checkout", but it's not mentioned.

[1] CACsJy8Axa5WsLSjiscjnxVK6jQHkfs-gH959=YtUvQkWriAk5w@mail.gmail.com

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:57:00 +09:00
Nguyễn Thái Ngọc Duy 65f099b398 switch: no worktree status unless real branch switch happens
When we switch from one branch to another, it makes sense to show a
summary of local changes since there could be conflicts, or some files
left modified.... When switch is used solely for creating a new
branch (and "switch" to the same commit) or detaching, we don't really
need to show anything.

"git checkout" does it anyway for historical reasons. But we can start
with a clean slate with switch and don't have to.

This essentially reverts fa655d8411 (checkout: optimize "git checkout
-b <new_branch>" - 2018-08-16) and make it default for switch,
but also for -B and --detach. Users of big repos are encouraged to
move to switch.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:57:00 +09:00
Nguyễn Thái Ngọc Duy ccb111b342 switch: implicit dwim, use --no-guess to disable it
This is already the default in git-checkout. The real change in here is
just minor cleanup. The main excuse is to explain why dwim is kept default.

Contrary to detach mode that is easy to get into and confusing to get
back out. Automatically creating a tracking branch often does not kick
in as often (you would need a branch of the same name on a remote). And
since the branch creation is reported clearly, the user should be able
to undo/delete it if it's unwanted.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:57:00 +09:00
Nguyễn Thái Ngọc Duy 163e3b2975 switch: add short option for --detach
"git checkout" automatically detaches branches and --detach is not
that useful (--no-detach is more likely). But for "switch", you
may want to use it more often once you're used to detached HEAD. This
of course adds -d to git-checkout but it does not harm (yet?) to do it.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:57:00 +09:00
Nguyễn Thái Ngọc Duy 7968bef06b switch: only allow explicit detached HEAD
"git checkout <commit>" will checkout the commit in question and
detach HEAD from the current branch. It is naturally a right thing to
do once you get git references. But detached HEAD is a scary concept
to new users because we show a lot of warnings and stuff, and it could
be hard to get out of (until you know better).

To keep switch a bit more friendly to new users, we only allow
entering detached HEAD mode when --detach is given. "git
switch" must take a branch (unless you create a new branch,
then of course switch can take any commit-ish)

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:57:00 +09:00
Nguyễn Thái Ngọc Duy e342c63a4e switch: reject "do nothing" case
"git checkout" can be executed without any arguments. What it does is
not exactly great: it switches from HEAD to HEAD and shows worktree
modification as a side effect.

Make switch reject this case. Just use "git status" if you want
that side effect. For switch, you have to either

- really switch a branch
- (explicitly) detach from the current branch
- create a new branch

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:57:00 +09:00
Nguyễn Thái Ngọc Duy 5c06e26903 switch: stop accepting pathspec
This command is about switching branch (or creating a new one) and
should not accept pathspec. This helps simplify ambiguation
handling. The other two ("git checkout" and "git restore") of
course do accept pathspec as before.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:56:59 +09:00
Nguyễn Thái Ngọc Duy 492ededc26 switch: remove -l
This option is ancient. Nowadays reflog is enabled by default and
automatically created for new branches. Keep it in git-checkout only.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:56:59 +09:00
Nguyễn Thái Ngọc Duy 3ec37ad13d switch: add --discard-changes
--discard-changes is a better name than --force for this option since
it's what really happens. --force is turned to an alias for
--discard-changes. But it's meant to be an alias for potentially more
force options in the future.

Side note. It's not obvious from the patch but --discard-changes also
affects submodules if --recurse-submodules is used. The knob to force
updating submodules is hidden behind unpack-trees.c

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:56:59 +09:00
Nguyễn Thái Ngọc Duy b7b5fce270 switch: better names for -b and -B
The shortcut of these options do not make much sense when used with
switch. And their descriptions are also tied to checkout. Move -b/-B
to cmd_checkout() and new -c/-C with the same functionality in
cmd_switch_branch()

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:56:59 +09:00
Nguyễn Thái Ngọc Duy d787d311db checkout: split part of it to new command 'switch'
"git checkout" doing too many things is a source of confusion for many
users (and it even bites old timers sometimes). To remedy that, the
command will be split into two new ones: switch and restore. The good
old "git checkout" command is still here and will be until all (or most
of users) are sick of it.

See the new man page for the final design of switch. The actual
implementation though is still pretty much the same as "git checkout"
and not completely aligned with the man page. Following patches will
adjust their behavior to match the man page.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:56:59 +09:00
Nguyễn Thái Ngọc Duy 2087182272 checkout: split options[] array in three pieces
This is a preparation step for introducing new commands that do parts
of what checkout does. There will be two new commands, one is about
switching branches, detaching HEAD... one about checking out
paths. These share the a subset of command line options. The rest of
command line options are separate.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:56:59 +09:00
Nguyễn Thái Ngọc Duy 55cf704a9d checkout: move 'confict_style' and 'dwim_..' to checkout_opts
These local variables are referenced by struct option[]. This struct
will soon be broken down, moved away and we can't rely on local
variables anymore. Move these two to struct checkout_opts in
preparation for that.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:56:59 +09:00
Nguyễn Thái Ngọc Duy b3edccb967 checkout: make "opts" in cmd_checkout() a pointer
"opts" will soon be moved out of cmd_checkout(). To keep changes in
that patch smaller, convert "opts" to a pointer and keep the real
thing behind "real_opts".

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:56:59 +09:00
Nguyễn Thái Ngọc Duy 7ab4ad00cc checkout: factor out some code in parse_branchname_arg()
This is in preparation for the new command restore, which also
needs to parse opts->source_tree but does not need all the
disambiguation logic.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:56:59 +09:00
Nguyễn Thái Ngọc Duy 0dabeffc16 checkout: keep most #include sorted
The include list becomes very long and frankly a bit unorganized. With
the exception of builtin.h, cache.h or git-compat-util.h which have to
come first, keep the rest sorted.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:56:59 +09:00
Nguyễn Thái Ngọc Duy f4a4b9aca3 checkout: inform the user when removing branch state
After a successful switch, if a merge, cherry-pick or revert is ongoing,
it is canceled. This behavior has been with us from the very early
beginning, soon after git-merge was created but never actually
documented [1]. It may be a good idea to be transparent and tell the
user if some operation is canceled.

I consider this a better way of telling the user than just adding a
sentence or two in git-checkout.txt, which will be mostly ignored
anyway.

PS. Originally I wanted to print more details like

    warning: cancelling an in-progress merge from <SHA-1>

which may allow some level of undo if the user wants to. But that seems
a lot more work. Perhaps it can be improved later if people still want
that.

[1] ... and I will try not to argue whether it is a sensible behavior.
There is some more discussion here if people are interested:
CACsJy8Axa5WsLSjiscjnxVK6jQHkfs-gH959=YtUvQkWriAk5w@mail.gmail.com

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-02 13:56:59 +09:00
Nguyễn Thái Ngọc Duy 6eff409e8a checkout: prevent losing staged changes with --merge
When --merge is specified, we may need to do a real merge (instead of
three-way tree unpacking), the steps are best seen in git-checkout.sh
version before it's removed:

    # Match the index to the working tree, and do a three-way.
    git diff-files --name-only | git update-index --remove --stdin &&
    work=`git write-tree` &&
    git read-tree $v --reset -u $new || exit

    git merge-recursive $old -- $new $work

    # Do not register the cleanly merged paths in the index yet.
    # this is not a real merge before committing, but just carrying
    # the working tree changes along.
    unmerged=`git ls-files -u`
    git read-tree $v --reset $new
    case "$unmerged" in
    '')     ;;
    *)
            (
                    z40=0000000000000000000000000000000000000000
                    echo "$unmerged" |
                    sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /"
                    echo "$unmerged"
            ) | git update-index --index-info
            ;;
    esac

Notice the last 'read-tree --reset' step. We restore worktree back to
'new' tree after worktree's messed up by merge-recursive. If there are
staged changes before this whole command sequence is executed, they
are lost because they are unlikely part of the 'new' tree to be
restored.

There is no easy way to fix this. Elijah may have something up his
sleeves [1], but until then, check if there are staged changes and
refuse to run and lose them. The user would need to do "git reset" to
continue in this case.

A note about the test update. 'checkout -m' in that test will fail
because a deletion is staged. This 'checkout -m' was previously needed
to verify quietness behavior of unpack-trees. But a different check
has been put in place in the last patch. We can safely drop
'checkout -m' now.

[1] CABPp-BFoL_U=bzON4SEMaQSKU2TKwnOgNqjt5MUaOejTKGUJxw@mail.gmail.com

Reported-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-03-24 21:35:34 +09:00
Nguyễn Thái Ngọc Duy b165fac8c1 unpack-trees: rename "gently" flag to "quiet"
The gently flag was added in 17e4642667 (Add flag to make unpack_trees()
not print errors. - 2008-02-07) to suppress error messages. The name
"gently" does not quite express that. Granted, being quiet is gentle but
it could mean not performing some other actions. Rename the flag to
"quiet" to be more on point.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-03-24 21:35:34 +09:00
Nguyễn Thái Ngọc Duy a7256debd4 checkout.txt: note about losing staged changes with --merge
If you have staged changes in path A and perform 'checkout
--merge' (which could result in conflicts in a totally unrelated path
B), changes in A will be gone. Which is unexpected. We are supposed
to keep all changes, or kick and scream otherwise.

This is the result of how --merge is implemented, from the very first
day in 1be0659efc (checkout: merge local modifications while switching
branches., 2006-01-12):

1. a merge is done, unmerged entries are collected
2. a hard switch to a new branch is done, then unmerged entries added
   back

There is no trivial fix for this. Going with 3-way merge one file at a
time loses rename detection. Going with 3-way merge by trees requires
teaching the algorithm to pick up staged changes. And even if we detect
staged changes with --merge and abort for safety, an option to continue
--merge is very weird. Such an option would keep worktree changes, but
drop staged changes.

Because the problem has been with us since the introduction of --merge
and everybody has been pretty happy (except Phillip, who found this
problem), I'll just take a note here to acknowledge it and wait for
merge wizards to come in and work their magic. There may be a way
forward [1].

[1] CABPp-BFoL_U=bzON4SEMaQSKU2TKwnOgNqjt5MUaOejTKGUJxw@mail.gmail.com

Reported-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-03-21 12:07:41 +09:00
Jeff King c5c33504c9 report_path_error(): drop unused prefix parameter
This hasn't been used since 17ddc66e70 (convert report_path_error to
take struct pathspec, 2013-07-14), as the names in the struct will have
already been prefixed when they were parsed.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-03-20 18:34:09 +09:00
Junio C Hamano 32038fef00 Merge branch 'jh/trace2'
A more structured way to obtain execution trace has been added.

* jh/trace2:
  trace2: add for_each macros to clang-format
  trace2: t/helper/test-trace2, t0210.sh, t0211.sh, t0212.sh
  trace2:data: add subverb for rebase
  trace2:data: add subverb to reset command
  trace2:data: add subverb to checkout command
  trace2:data: pack-objects: add trace2 regions
  trace2:data: add trace2 instrumentation to index read/write
  trace2:data: add trace2 hook classification
  trace2:data: add trace2 transport child classification
  trace2:data: add trace2 sub-process classification
  trace2:data: add editor/pager child classification
  trace2:data: add trace2 regions to wt-status
  trace2: collect Windows-specific process information
  trace2: create new combined trace facility
  trace2: Documentation/technical/api-trace2.txt
2019-03-07 09:59:56 +09:00
Junio C Hamano 7d0c1f4556 Merge branch 'tg/checkout-no-overlay'
"git checkout --no-overlay" can be used to trigger a new mode of
checking out paths out of the tree-ish, that allows paths that
match the pathspec that are in the current index and working tree
and are not in the tree-ish.

* tg/checkout-no-overlay:
  revert "checkout: introduce checkout.overlayMode config"
  checkout: introduce checkout.overlayMode config
  checkout: introduce --{,no-}overlay option
  checkout: factor out mark_cache_entry_for_checkout function
  checkout: clarify comment
  read-cache: add invalidate parameter to remove_marked_cache_entries
  entry: support CE_WT_REMOVE flag in checkout_entry
  entry: factor out unlink_entry function
  move worktree tests to t24*
2019-03-07 09:59:51 +09:00