Merge branch 'lk/more-helpful-status-hints'
Give finer classification to various states of paths in conflicted state and offer advice messages in the "git status" output.maint
						commit
						30e8e6fdea
					
				|  | @ -159,9 +159,10 @@ advice.*:: | ||||||
| 		specified a refspec that isn't your current branch) and | 		specified a refspec that isn't your current branch) and | ||||||
| 		it resulted in a non-fast-forward error. | 		it resulted in a non-fast-forward error. | ||||||
| 	statusHints:: | 	statusHints:: | ||||||
| 		Directions on how to stage/unstage/add shown in the | 		Show directions on how to proceed from the current | ||||||
| 		output of linkgit:git-status[1] and the template shown | 		state in the output of linkgit:git-status[1] and in | ||||||
| 		when writing commit messages. | 		the template shown when writing commit messages in | ||||||
|  | 		linkgit:git-commit[1]. | ||||||
| 	commitBeforeMerge:: | 	commitBeforeMerge:: | ||||||
| 		Advice shown when linkgit:git-merge[1] refuses to | 		Advice shown when linkgit:git-merge[1] refuses to | ||||||
| 		merge to avoid overwriting local changes. | 		merge to avoid overwriting local changes. | ||||||
|  |  | ||||||
|  | @ -30,6 +30,9 @@ test_expect_success 'Report new path with conflict' ' | ||||||
|  |  | ||||||
| cat >expect <<EOF | cat >expect <<EOF | ||||||
| # On branch side | # On branch side | ||||||
|  | # You have unmerged paths. | ||||||
|  | #   (fix conflicts and run "git commit") | ||||||
|  | # | ||||||
| # Unmerged paths: | # Unmerged paths: | ||||||
| #   (use "git add/rm <file>..." as appropriate to mark resolution) | #   (use "git add/rm <file>..." as appropriate to mark resolution) | ||||||
| # | # | ||||||
|  | @ -118,4 +121,97 @@ test_expect_success 'git diff-index --cached -C shows 2 copies + 1 unmerged' ' | ||||||
| 	test_cmp expected actual | 	test_cmp expected actual | ||||||
| ' | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when conflicts with add and rm advice (deleted by them)' ' | ||||||
|  | 	git reset --hard && | ||||||
|  | 	git checkout master && | ||||||
|  | 	test_commit init main.txt init && | ||||||
|  | 	git checkout -b second_branch && | ||||||
|  | 	git rm main.txt && | ||||||
|  | 	git commit -m "main.txt deleted on second_branch" && | ||||||
|  | 	test_commit second conflict.txt second && | ||||||
|  | 	git checkout master && | ||||||
|  | 	test_commit on_second main.txt on_second && | ||||||
|  | 	test_commit master conflict.txt master && | ||||||
|  | 	test_must_fail git merge second_branch && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# On branch master | ||||||
|  | 	# You have unmerged paths. | ||||||
|  | 	#   (fix conflicts and run "git commit") | ||||||
|  | 	# | ||||||
|  | 	# Unmerged paths: | ||||||
|  | 	#   (use "git add/rm <file>..." as appropriate to mark resolution) | ||||||
|  | 	# | ||||||
|  | 	#	both added:         conflict.txt | ||||||
|  | 	#	deleted by them:    main.txt | ||||||
|  | 	# | ||||||
|  | 	no changes added to commit (use "git add" and/or "git commit -a") | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'prepare for conflicts' ' | ||||||
|  | 	git reset --hard && | ||||||
|  | 	git checkout -b conflict && | ||||||
|  | 	test_commit one main.txt one && | ||||||
|  | 	git branch conflict_second && | ||||||
|  | 	git mv main.txt sub_master.txt && | ||||||
|  | 	git commit -m "main.txt renamed in sub_master.txt" && | ||||||
|  | 	git checkout conflict_second && | ||||||
|  | 	git mv main.txt sub_second.txt && | ||||||
|  | 	git commit -m "main.txt renamed in sub_second.txt" | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when conflicts with add and rm advice (both deleted)' ' | ||||||
|  | 	test_must_fail git merge conflict && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# On branch conflict_second | ||||||
|  | 	# You have unmerged paths. | ||||||
|  | 	#   (fix conflicts and run "git commit") | ||||||
|  | 	# | ||||||
|  | 	# Unmerged paths: | ||||||
|  | 	#   (use "git add/rm <file>..." as appropriate to mark resolution) | ||||||
|  | 	# | ||||||
|  | 	#	both deleted:       main.txt | ||||||
|  | 	#	added by them:      sub_master.txt | ||||||
|  | 	#	added by us:        sub_second.txt | ||||||
|  | 	# | ||||||
|  | 	no changes added to commit (use "git add" and/or "git commit -a") | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when conflicts with only rm advice (both deleted)' ' | ||||||
|  | 	git reset --hard conflict_second && | ||||||
|  | 	test_must_fail git merge conflict && | ||||||
|  | 	git add sub_master.txt && | ||||||
|  | 	git add sub_second.txt && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# On branch conflict_second | ||||||
|  | 	# You have unmerged paths. | ||||||
|  | 	#   (fix conflicts and run "git commit") | ||||||
|  | 	# | ||||||
|  | 	# Changes to be committed: | ||||||
|  | 	# | ||||||
|  | 	#	new file:   sub_master.txt | ||||||
|  | 	# | ||||||
|  | 	# Unmerged paths: | ||||||
|  | 	#   (use "git rm <file>..." to mark resolution) | ||||||
|  | 	# | ||||||
|  | 	#	both deleted:       main.txt | ||||||
|  | 	# | ||||||
|  | 	# Untracked files not listed (use -u option to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual && | ||||||
|  | 	git reset --hard && | ||||||
|  | 	git checkout master | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
| test_done | test_done | ||||||
|  |  | ||||||
|  | @ -0,0 +1,649 @@ | ||||||
|  | #!/bin/sh | ||||||
|  | # | ||||||
|  | # Copyright (c) 2012 Valentin Duperray, Lucien Kong, Franck Jonas, | ||||||
|  | #		     Thomas Nguy, Khoi Nguyen | ||||||
|  | #		     Grenoble INP Ensimag | ||||||
|  | # | ||||||
|  |  | ||||||
|  | test_description='git status advices' | ||||||
|  |  | ||||||
|  | . ./test-lib.sh | ||||||
|  |  | ||||||
|  | . "$TEST_DIRECTORY"/lib-rebase.sh | ||||||
|  |  | ||||||
|  | set_fake_editor | ||||||
|  |  | ||||||
|  | test_expect_success 'prepare for conflicts' ' | ||||||
|  | 	test_commit init main.txt init && | ||||||
|  | 	git branch conflicts && | ||||||
|  | 	test_commit on_master main.txt on_master && | ||||||
|  | 	git checkout conflicts && | ||||||
|  | 	test_commit on_conflicts main.txt on_conflicts | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when conflicts unresolved' ' | ||||||
|  | 	test_must_fail git merge master && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# On branch conflicts | ||||||
|  | 	# You have unmerged paths. | ||||||
|  | 	#   (fix conflicts and run "git commit") | ||||||
|  | 	# | ||||||
|  | 	# Unmerged paths: | ||||||
|  | 	#   (use "git add <file>..." to mark resolution) | ||||||
|  | 	# | ||||||
|  | 	#	both modified:      main.txt | ||||||
|  | 	# | ||||||
|  | 	no changes added to commit (use "git add" and/or "git commit -a") | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when conflicts resolved before commit' ' | ||||||
|  | 	git reset --hard conflicts && | ||||||
|  | 	test_must_fail git merge master && | ||||||
|  | 	echo one >main.txt && | ||||||
|  | 	git add main.txt && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# On branch conflicts | ||||||
|  | 	# All conflicts fixed but you are still merging. | ||||||
|  | 	#   (use "git commit" to conclude merge) | ||||||
|  | 	# | ||||||
|  | 	# Changes to be committed: | ||||||
|  | 	# | ||||||
|  | 	#	modified:   main.txt | ||||||
|  | 	# | ||||||
|  | 	# Untracked files not listed (use -u option to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'prepare for rebase conflicts' ' | ||||||
|  | 	git reset --hard master && | ||||||
|  | 	git checkout -b rebase_conflicts && | ||||||
|  | 	test_commit one_rebase main.txt one && | ||||||
|  | 	test_commit two_rebase main.txt two && | ||||||
|  | 	test_commit three_rebase main.txt three | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when rebase in progress before resolving conflicts' ' | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	test_must_fail git rebase HEAD^ --onto HEAD^^ && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently rebasing. | ||||||
|  | 	#   (fix conflicts and then run "git rebase --continue") | ||||||
|  | 	#   (use "git rebase --skip" to skip this patch) | ||||||
|  | 	#   (use "git rebase --abort" to check out the original branch) | ||||||
|  | 	# | ||||||
|  | 	# Unmerged paths: | ||||||
|  | 	#   (use "git reset HEAD <file>..." to unstage) | ||||||
|  | 	#   (use "git add <file>..." to mark resolution) | ||||||
|  | 	# | ||||||
|  | 	#	both modified:      main.txt | ||||||
|  | 	# | ||||||
|  | 	no changes added to commit (use "git add" and/or "git commit -a") | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when rebase in progress before rebase --continue' ' | ||||||
|  | 	git reset --hard rebase_conflicts && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	test_must_fail git rebase HEAD^ --onto HEAD^^ && | ||||||
|  | 	echo three >main.txt && | ||||||
|  | 	git add main.txt && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently rebasing. | ||||||
|  | 	#   (all conflicts fixed: run "git rebase --continue") | ||||||
|  | 	# | ||||||
|  | 	# Changes to be committed: | ||||||
|  | 	#   (use "git reset HEAD <file>..." to unstage) | ||||||
|  | 	# | ||||||
|  | 	#	modified:   main.txt | ||||||
|  | 	# | ||||||
|  | 	# Untracked files not listed (use -u option to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'prepare for rebase_i_conflicts' ' | ||||||
|  | 	git reset --hard master && | ||||||
|  | 	git checkout -b rebase_i_conflicts && | ||||||
|  | 	test_commit one_unmerge main.txt one_unmerge && | ||||||
|  | 	git branch rebase_i_conflicts_second && | ||||||
|  | 	test_commit one_master main.txt one_master && | ||||||
|  | 	git checkout rebase_i_conflicts_second && | ||||||
|  | 	test_commit one_second main.txt one_second | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status during rebase -i when conflicts unresolved' ' | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	test_must_fail git rebase -i rebase_i_conflicts && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently rebasing. | ||||||
|  | 	#   (fix conflicts and then run "git rebase --continue") | ||||||
|  | 	#   (use "git rebase --skip" to skip this patch) | ||||||
|  | 	#   (use "git rebase --abort" to check out the original branch) | ||||||
|  | 	# | ||||||
|  | 	# Unmerged paths: | ||||||
|  | 	#   (use "git reset HEAD <file>..." to unstage) | ||||||
|  | 	#   (use "git add <file>..." to mark resolution) | ||||||
|  | 	# | ||||||
|  | 	#	both modified:      main.txt | ||||||
|  | 	# | ||||||
|  | 	no changes added to commit (use "git add" and/or "git commit -a") | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status during rebase -i after resolving conflicts' ' | ||||||
|  | 	git reset --hard rebase_i_conflicts_second && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	test_must_fail git rebase -i rebase_i_conflicts && | ||||||
|  | 	git add main.txt && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently rebasing. | ||||||
|  | 	#   (all conflicts fixed: run "git rebase --continue") | ||||||
|  | 	# | ||||||
|  | 	# Changes to be committed: | ||||||
|  | 	#   (use "git reset HEAD <file>..." to unstage) | ||||||
|  | 	# | ||||||
|  | 	#	modified:   main.txt | ||||||
|  | 	# | ||||||
|  | 	# Untracked files not listed (use -u option to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when rebasing -i in edit mode' ' | ||||||
|  | 	git reset --hard master && | ||||||
|  | 	git checkout -b rebase_i_edit && | ||||||
|  | 	test_commit one_rebase_i main.txt one && | ||||||
|  | 	test_commit two_rebase_i main.txt two && | ||||||
|  | 	test_commit three_rebase_i main.txt three && | ||||||
|  | 	FAKE_LINES="1 edit 2" && | ||||||
|  | 	export FAKE_LINES && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	git rebase -i HEAD~2 && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently editing a commit during a rebase. | ||||||
|  | 	#   (use "git commit --amend" to amend the current commit) | ||||||
|  | 	#   (use "git rebase --continue" once you are satisfied with your changes) | ||||||
|  | 	# | ||||||
|  | 	nothing to commit (use -u to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when splitting a commit' ' | ||||||
|  | 	git reset --hard master && | ||||||
|  | 	git checkout -b split_commit && | ||||||
|  | 	test_commit one_split main.txt one && | ||||||
|  | 	test_commit two_split main.txt two && | ||||||
|  | 	test_commit three_split main.txt three && | ||||||
|  | 	test_commit four_split main.txt four && | ||||||
|  | 	FAKE_LINES="1 edit 2 3" && | ||||||
|  | 	export FAKE_LINES && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	git rebase -i HEAD~3 && | ||||||
|  | 	git reset HEAD^ && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently splitting a commit during a rebase. | ||||||
|  | 	#   (Once your working directory is clean, run "git rebase --continue") | ||||||
|  | 	# | ||||||
|  | 	# Changes not staged for commit: | ||||||
|  | 	#   (use "git add <file>..." to update what will be committed) | ||||||
|  | 	#   (use "git checkout -- <file>..." to discard changes in working directory) | ||||||
|  | 	# | ||||||
|  | 	#	modified:   main.txt | ||||||
|  | 	# | ||||||
|  | 	no changes added to commit (use "git add" and/or "git commit -a") | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status after editing the last commit with --amend during a rebase -i' ' | ||||||
|  | 	git reset --hard master && | ||||||
|  | 	git checkout -b amend_last && | ||||||
|  | 	test_commit one_amend main.txt one && | ||||||
|  | 	test_commit two_amend main.txt two && | ||||||
|  | 	test_commit three_amend main.txt three && | ||||||
|  | 	test_commit four_amend main.txt four && | ||||||
|  | 	FAKE_LINES="1 2 edit 3" && | ||||||
|  | 	export FAKE_LINES && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	git rebase -i HEAD~3 && | ||||||
|  | 	git commit --amend -m "foo" && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently editing a commit during a rebase. | ||||||
|  | 	#   (use "git commit --amend" to amend the current commit) | ||||||
|  | 	#   (use "git rebase --continue" once you are satisfied with your changes) | ||||||
|  | 	# | ||||||
|  | 	nothing to commit (use -u to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'prepare for several edits' ' | ||||||
|  | 	git reset --hard master && | ||||||
|  | 	git checkout -b several_edits && | ||||||
|  | 	test_commit one_edits main.txt one && | ||||||
|  | 	test_commit two_edits main.txt two && | ||||||
|  | 	test_commit three_edits main.txt three && | ||||||
|  | 	test_commit four_edits main.txt four | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status: (continue first edit) second edit' ' | ||||||
|  | 	FAKE_LINES="edit 1 edit 2 3" && | ||||||
|  | 	export FAKE_LINES && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	git rebase -i HEAD~3 && | ||||||
|  | 	git rebase --continue && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently editing a commit during a rebase. | ||||||
|  | 	#   (use "git commit --amend" to amend the current commit) | ||||||
|  | 	#   (use "git rebase --continue" once you are satisfied with your changes) | ||||||
|  | 	# | ||||||
|  | 	nothing to commit (use -u to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status: (continue first edit) second edit and split' ' | ||||||
|  | 	git reset --hard several_edits && | ||||||
|  | 	FAKE_LINES="edit 1 edit 2 3" && | ||||||
|  | 	export FAKE_LINES && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	git rebase -i HEAD~3 && | ||||||
|  | 	git rebase --continue && | ||||||
|  | 	git reset HEAD^ && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently splitting a commit during a rebase. | ||||||
|  | 	#   (Once your working directory is clean, run "git rebase --continue") | ||||||
|  | 	# | ||||||
|  | 	# Changes not staged for commit: | ||||||
|  | 	#   (use "git add <file>..." to update what will be committed) | ||||||
|  | 	#   (use "git checkout -- <file>..." to discard changes in working directory) | ||||||
|  | 	# | ||||||
|  | 	#	modified:   main.txt | ||||||
|  | 	# | ||||||
|  | 	no changes added to commit (use "git add" and/or "git commit -a") | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status: (continue first edit) second edit and amend' ' | ||||||
|  | 	git reset --hard several_edits && | ||||||
|  | 	FAKE_LINES="edit 1 edit 2 3" && | ||||||
|  | 	export FAKE_LINES && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	git rebase -i HEAD~3 && | ||||||
|  | 	git rebase --continue && | ||||||
|  | 	git commit --amend -m "foo" && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently editing a commit during a rebase. | ||||||
|  | 	#   (use "git commit --amend" to amend the current commit) | ||||||
|  | 	#   (use "git rebase --continue" once you are satisfied with your changes) | ||||||
|  | 	# | ||||||
|  | 	nothing to commit (use -u to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status: (amend first edit) second edit' ' | ||||||
|  | 	git reset --hard several_edits && | ||||||
|  | 	FAKE_LINES="edit 1 edit 2 3" && | ||||||
|  | 	export FAKE_LINES && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	git rebase -i HEAD~3 && | ||||||
|  | 	git commit --amend -m "a" && | ||||||
|  | 	git rebase --continue && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently editing a commit during a rebase. | ||||||
|  | 	#   (use "git commit --amend" to amend the current commit) | ||||||
|  | 	#   (use "git rebase --continue" once you are satisfied with your changes) | ||||||
|  | 	# | ||||||
|  | 	nothing to commit (use -u to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status: (amend first edit) second edit and split' ' | ||||||
|  | 	git reset --hard several_edits && | ||||||
|  | 	FAKE_LINES="edit 1 edit 2 3" && | ||||||
|  | 	export FAKE_LINES && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	git rebase -i HEAD~3 && | ||||||
|  | 	git commit --amend -m "b" && | ||||||
|  | 	git rebase --continue && | ||||||
|  | 	git reset HEAD^ && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently splitting a commit during a rebase. | ||||||
|  | 	#   (Once your working directory is clean, run "git rebase --continue") | ||||||
|  | 	# | ||||||
|  | 	# Changes not staged for commit: | ||||||
|  | 	#   (use "git add <file>..." to update what will be committed) | ||||||
|  | 	#   (use "git checkout -- <file>..." to discard changes in working directory) | ||||||
|  | 	# | ||||||
|  | 	#	modified:   main.txt | ||||||
|  | 	# | ||||||
|  | 	no changes added to commit (use "git add" and/or "git commit -a") | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status: (amend first edit) second edit and amend' ' | ||||||
|  | 	git reset --hard several_edits && | ||||||
|  | 	FAKE_LINES="edit 1 edit 2 3" && | ||||||
|  | 	export FAKE_LINES && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	git rebase -i HEAD~3 && | ||||||
|  | 	git commit --amend -m "c" && | ||||||
|  | 	git rebase --continue && | ||||||
|  | 	git commit --amend -m "d" && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently editing a commit during a rebase. | ||||||
|  | 	#   (use "git commit --amend" to amend the current commit) | ||||||
|  | 	#   (use "git rebase --continue" once you are satisfied with your changes) | ||||||
|  | 	# | ||||||
|  | 	nothing to commit (use -u to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status: (split first edit) second edit' ' | ||||||
|  | 	git reset --hard several_edits && | ||||||
|  | 	FAKE_LINES="edit 1 edit 2 3" && | ||||||
|  | 	export FAKE_LINES && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	git rebase -i HEAD~3 && | ||||||
|  | 	git reset HEAD^ && | ||||||
|  | 	git add main.txt && | ||||||
|  | 	git commit -m "e" && | ||||||
|  | 	git rebase --continue && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently editing a commit during a rebase. | ||||||
|  | 	#   (use "git commit --amend" to amend the current commit) | ||||||
|  | 	#   (use "git rebase --continue" once you are satisfied with your changes) | ||||||
|  | 	# | ||||||
|  | 	nothing to commit (use -u to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status: (split first edit) second edit and split' ' | ||||||
|  | 	git reset --hard several_edits && | ||||||
|  | 	FAKE_LINES="edit 1 edit 2 3" && | ||||||
|  | 	export FAKE_LINES && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	git rebase -i HEAD~3 && | ||||||
|  | 	git reset HEAD^ && | ||||||
|  | 	git add main.txt && | ||||||
|  | 	git commit --amend -m "f" && | ||||||
|  | 	git rebase --continue && | ||||||
|  | 	git reset HEAD^ && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently splitting a commit during a rebase. | ||||||
|  | 	#   (Once your working directory is clean, run "git rebase --continue") | ||||||
|  | 	# | ||||||
|  | 	# Changes not staged for commit: | ||||||
|  | 	#   (use "git add <file>..." to update what will be committed) | ||||||
|  | 	#   (use "git checkout -- <file>..." to discard changes in working directory) | ||||||
|  | 	# | ||||||
|  | 	#	modified:   main.txt | ||||||
|  | 	# | ||||||
|  | 	no changes added to commit (use "git add" and/or "git commit -a") | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status: (split first edit) second edit and amend' ' | ||||||
|  | 	git reset --hard several_edits && | ||||||
|  | 	FAKE_LINES="edit 1 edit 2 3" && | ||||||
|  | 	export FAKE_LINES && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	git rebase -i HEAD~3 && | ||||||
|  | 	git reset HEAD^ && | ||||||
|  | 	git add main.txt && | ||||||
|  | 	git commit --amend -m "g" && | ||||||
|  | 	git rebase --continue && | ||||||
|  | 	git commit --amend -m "h" && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently editing a commit during a rebase. | ||||||
|  | 	#   (use "git commit --amend" to amend the current commit) | ||||||
|  | 	#   (use "git rebase --continue" once you are satisfied with your changes) | ||||||
|  | 	# | ||||||
|  | 	nothing to commit (use -u to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'prepare am_session' ' | ||||||
|  | 	git reset --hard master && | ||||||
|  | 	git checkout -b am_session && | ||||||
|  | 	test_commit one_am one.txt "one" && | ||||||
|  | 	test_commit two_am two.txt "two" && | ||||||
|  | 	test_commit three_am three.txt "three" | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status in an am session: file already exists' ' | ||||||
|  | 	git checkout -b am_already_exists && | ||||||
|  | 	test_when_finished "rm Maildir/* && git am --abort" && | ||||||
|  | 	git format-patch -1 -oMaildir && | ||||||
|  | 	test_must_fail git am Maildir/*.patch && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# On branch am_already_exists | ||||||
|  | 	# You are in the middle of an am session. | ||||||
|  | 	#   (fix conflicts and then run "git am --resolved") | ||||||
|  | 	#   (use "git am --skip" to skip this patch) | ||||||
|  | 	#   (use "git am --abort" to restore the original branch) | ||||||
|  | 	# | ||||||
|  | 	nothing to commit (use -u to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status in an am session: file does not exist' ' | ||||||
|  | 	git reset --hard am_session && | ||||||
|  | 	git checkout -b am_not_exists && | ||||||
|  | 	git rm three.txt && | ||||||
|  | 	git commit -m "delete three.txt" && | ||||||
|  | 	test_when_finished "rm Maildir/* && git am --abort" && | ||||||
|  | 	git format-patch -1 -oMaildir && | ||||||
|  | 	test_must_fail git am Maildir/*.patch && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# On branch am_not_exists | ||||||
|  | 	# You are in the middle of an am session. | ||||||
|  | 	#   (fix conflicts and then run "git am --resolved") | ||||||
|  | 	#   (use "git am --skip" to skip this patch) | ||||||
|  | 	#   (use "git am --abort" to restore the original branch) | ||||||
|  | 	# | ||||||
|  | 	nothing to commit (use -u to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status in an am session: empty patch' ' | ||||||
|  | 	git reset --hard am_session && | ||||||
|  | 	git checkout -b am_empty && | ||||||
|  | 	test_when_finished "rm Maildir/* && git am --abort" && | ||||||
|  | 	git format-patch -3 -oMaildir && | ||||||
|  | 	git rm one.txt two.txt three.txt && | ||||||
|  | 	git commit -m "delete all am_empty" && | ||||||
|  | 	echo error >Maildir/0002-two_am.patch && | ||||||
|  | 	test_must_fail git am Maildir/*.patch && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# On branch am_empty | ||||||
|  | 	# You are in the middle of an am session. | ||||||
|  | 	# The current patch is empty. | ||||||
|  | 	#   (use "git am --skip" to skip this patch) | ||||||
|  | 	#   (use "git am --abort" to restore the original branch) | ||||||
|  | 	# | ||||||
|  | 	nothing to commit (use -u to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when bisecting' ' | ||||||
|  | 	git reset --hard master && | ||||||
|  | 	git checkout -b bisect && | ||||||
|  | 	test_commit one_bisect main.txt one && | ||||||
|  | 	test_commit two_bisect main.txt two && | ||||||
|  | 	test_commit three_bisect main.txt three && | ||||||
|  | 	test_when_finished "git bisect reset" && | ||||||
|  | 	git bisect start && | ||||||
|  | 	git bisect bad && | ||||||
|  | 	git bisect good one_bisect && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently bisecting. | ||||||
|  | 	#   (use "git bisect reset" to get back to the original branch) | ||||||
|  | 	# | ||||||
|  | 	nothing to commit (use -u to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when rebase conflicts with statushints disabled' ' | ||||||
|  | 	git reset --hard master && | ||||||
|  | 	git checkout -b statushints_disabled && | ||||||
|  | 	test_when_finished "git config --local advice.statushints true" && | ||||||
|  | 	git config --local advice.statushints false && | ||||||
|  | 	test_commit one_statushints main.txt one && | ||||||
|  | 	test_commit two_statushints main.txt two && | ||||||
|  | 	test_commit three_statushints main.txt three && | ||||||
|  | 	test_when_finished "git rebase --abort" && | ||||||
|  | 	test_must_fail git rebase HEAD^ --onto HEAD^^ && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# Not currently on any branch. | ||||||
|  | 	# You are currently rebasing. | ||||||
|  | 	# | ||||||
|  | 	# Unmerged paths: | ||||||
|  | 	#	both modified:      main.txt | ||||||
|  | 	# | ||||||
|  | 	no changes added to commit | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'prepare for cherry-pick conflicts' ' | ||||||
|  | 	git reset --hard master && | ||||||
|  | 	git checkout -b cherry_branch && | ||||||
|  | 	test_commit one_cherry main.txt one && | ||||||
|  | 	test_commit two_cherries main.txt two && | ||||||
|  | 	git checkout -b cherry_branch_second && | ||||||
|  | 	test_commit second_cherry main.txt second && | ||||||
|  | 	git checkout cherry_branch && | ||||||
|  | 	test_commit three_cherries main.txt three | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when cherry-picking before resolving conflicts' ' | ||||||
|  | 	test_when_finished "git cherry-pick --abort" && | ||||||
|  | 	test_must_fail git cherry-pick cherry_branch_second && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# On branch cherry_branch | ||||||
|  | 	# You are currently cherry-picking. | ||||||
|  | 	#   (fix conflicts and run "git commit") | ||||||
|  | 	# | ||||||
|  | 	# Unmerged paths: | ||||||
|  | 	#   (use "git add <file>..." to mark resolution) | ||||||
|  | 	# | ||||||
|  | 	#	both modified:      main.txt | ||||||
|  | 	# | ||||||
|  | 	no changes added to commit (use "git add" and/or "git commit -a") | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_expect_success 'status when cherry-picking after resolving conflicts' ' | ||||||
|  | 	git reset --hard cherry_branch && | ||||||
|  | 	test_when_finished "git cherry-pick --abort" && | ||||||
|  | 	test_must_fail git cherry-pick cherry_branch_second && | ||||||
|  | 	echo end >main.txt && | ||||||
|  | 	git add main.txt && | ||||||
|  | 	cat >expected <<-\EOF && | ||||||
|  | 	# On branch cherry_branch | ||||||
|  | 	# You are currently cherry-picking. | ||||||
|  | 	#   (all conflicts fixed: run "git commit") | ||||||
|  | 	# | ||||||
|  | 	# Changes to be committed: | ||||||
|  | 	# | ||||||
|  | 	#	modified:   main.txt | ||||||
|  | 	# | ||||||
|  | 	# Untracked files not listed (use -u option to show untracked files) | ||||||
|  | 	EOF | ||||||
|  | 	git status --untracked-files=no >actual && | ||||||
|  | 	test_i18ncmp expected actual | ||||||
|  | ' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | test_done | ||||||
							
								
								
									
										245
									
								
								wt-status.c
								
								
								
								
							
							
						
						
									
										245
									
								
								wt-status.c
								
								
								
								
							|  | @ -12,6 +12,7 @@ | ||||||
| #include "refs.h" | #include "refs.h" | ||||||
| #include "submodule.h" | #include "submodule.h" | ||||||
| #include "column.h" | #include "column.h" | ||||||
|  | #include "strbuf.h" | ||||||
|  |  | ||||||
| static char default_wt_status_colors[][COLOR_MAXLEN] = { | static char default_wt_status_colors[][COLOR_MAXLEN] = { | ||||||
| 	GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */ | 	GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */ | ||||||
|  | @ -23,6 +24,7 @@ static char default_wt_status_colors[][COLOR_MAXLEN] = { | ||||||
| 	GIT_COLOR_GREEN,  /* WT_STATUS_LOCAL_BRANCH */ | 	GIT_COLOR_GREEN,  /* WT_STATUS_LOCAL_BRANCH */ | ||||||
| 	GIT_COLOR_RED,    /* WT_STATUS_REMOTE_BRANCH */ | 	GIT_COLOR_RED,    /* WT_STATUS_REMOTE_BRANCH */ | ||||||
| 	GIT_COLOR_NIL,    /* WT_STATUS_ONBRANCH */ | 	GIT_COLOR_NIL,    /* WT_STATUS_ONBRANCH */ | ||||||
|  | 	GIT_COLOR_NORMAL, /* WT_STATUS_IN_PROGRESS */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static const char *color(int slot, struct wt_status *s) | static const char *color(int slot, struct wt_status *s) | ||||||
|  | @ -130,9 +132,34 @@ void wt_status_prepare(struct wt_status *s) | ||||||
|  |  | ||||||
| static void wt_status_print_unmerged_header(struct wt_status *s) | static void wt_status_print_unmerged_header(struct wt_status *s) | ||||||
| { | { | ||||||
|  | 	int i; | ||||||
|  | 	int del_mod_conflict = 0; | ||||||
|  | 	int both_deleted = 0; | ||||||
|  | 	int not_deleted = 0; | ||||||
| 	const char *c = color(WT_STATUS_HEADER, s); | 	const char *c = color(WT_STATUS_HEADER, s); | ||||||
|  |  | ||||||
| 	status_printf_ln(s, c, _("Unmerged paths:")); | 	status_printf_ln(s, c, _("Unmerged paths:")); | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < s->change.nr; i++) { | ||||||
|  | 		struct string_list_item *it = &(s->change.items[i]); | ||||||
|  | 		struct wt_status_change_data *d = it->util; | ||||||
|  |  | ||||||
|  | 		switch (d->stagemask) { | ||||||
|  | 		case 0: | ||||||
|  | 			break; | ||||||
|  | 		case 1: | ||||||
|  | 			both_deleted = 1; | ||||||
|  | 			break; | ||||||
|  | 		case 3: | ||||||
|  | 		case 5: | ||||||
|  | 			del_mod_conflict = 1; | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			not_deleted = 1; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if (!advice_status_hints) | 	if (!advice_status_hints) | ||||||
| 		return; | 		return; | ||||||
| 	if (s->whence != FROM_COMMIT) | 	if (s->whence != FROM_COMMIT) | ||||||
|  | @ -141,7 +168,17 @@ static void wt_status_print_unmerged_header(struct wt_status *s) | ||||||
| 		status_printf_ln(s, c, _("  (use \"git reset %s <file>...\" to unstage)"), s->reference); | 		status_printf_ln(s, c, _("  (use \"git reset %s <file>...\" to unstage)"), s->reference); | ||||||
| 	else | 	else | ||||||
| 		status_printf_ln(s, c, _("  (use \"git rm --cached <file>...\" to unstage)")); | 		status_printf_ln(s, c, _("  (use \"git rm --cached <file>...\" to unstage)")); | ||||||
| 	status_printf_ln(s, c, _("  (use \"git add/rm <file>...\" as appropriate to mark resolution)")); |  | ||||||
|  | 	if (!both_deleted) { | ||||||
|  | 		if (!del_mod_conflict) | ||||||
|  | 			status_printf_ln(s, c, _("  (use \"git add <file>...\" to mark resolution)")); | ||||||
|  | 		else | ||||||
|  | 			status_printf_ln(s, c, _("  (use \"git add/rm <file>...\" as appropriate to mark resolution)")); | ||||||
|  | 	} else if (!del_mod_conflict && !not_deleted) { | ||||||
|  | 		status_printf_ln(s, c, _("  (use \"git rm <file>...\" to mark resolution)")); | ||||||
|  | 	} else { | ||||||
|  | 		status_printf_ln(s, c, _("  (use \"git add/rm <file>...\" as appropriate to mark resolution)")); | ||||||
|  | 	} | ||||||
| 	status_printf_ln(s, c, ""); | 	status_printf_ln(s, c, ""); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -728,6 +765,211 @@ static void wt_status_print_tracking(struct wt_status *s) | ||||||
| 	color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); | 	color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int has_unmerged(struct wt_status *s) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < s->change.nr; i++) { | ||||||
|  | 		struct wt_status_change_data *d; | ||||||
|  | 		d = s->change.items[i].util; | ||||||
|  | 		if (d->stagemask) | ||||||
|  | 			return 1; | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void show_merge_in_progress(struct wt_status *s, | ||||||
|  | 				struct wt_status_state *state, | ||||||
|  | 				const char *color) | ||||||
|  | { | ||||||
|  | 	if (has_unmerged(s)) { | ||||||
|  | 		status_printf_ln(s, color, _("You have unmerged paths.")); | ||||||
|  | 		if (advice_status_hints) | ||||||
|  | 			status_printf_ln(s, color, | ||||||
|  | 				_("  (fix conflicts and run \"git commit\")")); | ||||||
|  | 	} else { | ||||||
|  | 		status_printf_ln(s, color, | ||||||
|  | 			_("All conflicts fixed but you are still merging.")); | ||||||
|  | 		if (advice_status_hints) | ||||||
|  | 			status_printf_ln(s, color, | ||||||
|  | 				_("  (use \"git commit\" to conclude merge)")); | ||||||
|  | 	} | ||||||
|  | 	wt_status_print_trailer(s); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void show_am_in_progress(struct wt_status *s, | ||||||
|  | 				struct wt_status_state *state, | ||||||
|  | 				const char *color) | ||||||
|  | { | ||||||
|  | 	status_printf_ln(s, color, | ||||||
|  | 		_("You are in the middle of an am session.")); | ||||||
|  | 	if (state->am_empty_patch) | ||||||
|  | 		status_printf_ln(s, color, | ||||||
|  | 			_("The current patch is empty.")); | ||||||
|  | 	if (advice_status_hints) { | ||||||
|  | 		if (!state->am_empty_patch) | ||||||
|  | 			status_printf_ln(s, color, | ||||||
|  | 				_("  (fix conflicts and then run \"git am --resolved\")")); | ||||||
|  | 		status_printf_ln(s, color, | ||||||
|  | 			_("  (use \"git am --skip\" to skip this patch)")); | ||||||
|  | 		status_printf_ln(s, color, | ||||||
|  | 			_("  (use \"git am --abort\" to restore the original branch)")); | ||||||
|  | 	} | ||||||
|  | 	wt_status_print_trailer(s); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static char *read_line_from_git_path(const char *filename) | ||||||
|  | { | ||||||
|  | 	struct strbuf buf = STRBUF_INIT; | ||||||
|  | 	FILE *fp = fopen(git_path("%s", filename), "r"); | ||||||
|  | 	if (!fp) { | ||||||
|  | 		strbuf_release(&buf); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	strbuf_getline(&buf, fp, '\n'); | ||||||
|  | 	if (!fclose(fp)) { | ||||||
|  | 		return strbuf_detach(&buf, NULL); | ||||||
|  | 	} else { | ||||||
|  | 		strbuf_release(&buf); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int split_commit_in_progress(struct wt_status *s) | ||||||
|  | { | ||||||
|  | 	int split_in_progress = 0; | ||||||
|  | 	char *head = read_line_from_git_path("HEAD"); | ||||||
|  | 	char *orig_head = read_line_from_git_path("ORIG_HEAD"); | ||||||
|  | 	char *rebase_amend = read_line_from_git_path("rebase-merge/amend"); | ||||||
|  | 	char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head"); | ||||||
|  |  | ||||||
|  | 	if (!head || !orig_head || !rebase_amend || !rebase_orig_head || | ||||||
|  | 	    !s->branch || strcmp(s->branch, "HEAD")) | ||||||
|  | 		return split_in_progress; | ||||||
|  |  | ||||||
|  | 	if (!strcmp(rebase_amend, rebase_orig_head)) { | ||||||
|  | 		if (strcmp(head, rebase_amend)) | ||||||
|  | 			split_in_progress = 1; | ||||||
|  | 	} else if (strcmp(orig_head, rebase_orig_head)) { | ||||||
|  | 		split_in_progress = 1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (!s->amend && !s->nowarn && !s->workdir_dirty) | ||||||
|  | 		split_in_progress = 0; | ||||||
|  |  | ||||||
|  | 	free(head); | ||||||
|  | 	free(orig_head); | ||||||
|  | 	free(rebase_amend); | ||||||
|  | 	free(rebase_orig_head); | ||||||
|  | 	return split_in_progress; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void show_rebase_in_progress(struct wt_status *s, | ||||||
|  | 				struct wt_status_state *state, | ||||||
|  | 				const char *color) | ||||||
|  | { | ||||||
|  | 	struct stat st; | ||||||
|  |  | ||||||
|  | 	if (has_unmerged(s)) { | ||||||
|  | 		status_printf_ln(s, color, _("You are currently rebasing.")); | ||||||
|  | 		if (advice_status_hints) { | ||||||
|  | 			status_printf_ln(s, color, | ||||||
|  | 				_("  (fix conflicts and then run \"git rebase --continue\")")); | ||||||
|  | 			status_printf_ln(s, color, | ||||||
|  | 				_("  (use \"git rebase --skip\" to skip this patch)")); | ||||||
|  | 			status_printf_ln(s, color, | ||||||
|  | 				_("  (use \"git rebase --abort\" to check out the original branch)")); | ||||||
|  | 		} | ||||||
|  | 	} else if (state->rebase_in_progress || !stat(git_path("MERGE_MSG"), &st)) { | ||||||
|  | 		status_printf_ln(s, color, _("You are currently rebasing.")); | ||||||
|  | 		if (advice_status_hints) | ||||||
|  | 			status_printf_ln(s, color, | ||||||
|  | 				_("  (all conflicts fixed: run \"git rebase --continue\")")); | ||||||
|  | 	} else if (split_commit_in_progress(s)) { | ||||||
|  | 		status_printf_ln(s, color, _("You are currently splitting a commit during a rebase.")); | ||||||
|  | 		if (advice_status_hints) | ||||||
|  | 			status_printf_ln(s, color, | ||||||
|  | 				_("  (Once your working directory is clean, run \"git rebase --continue\")")); | ||||||
|  | 	} else { | ||||||
|  | 		status_printf_ln(s, color, _("You are currently editing a commit during a rebase.")); | ||||||
|  | 		if (advice_status_hints && !s->amend) { | ||||||
|  | 			status_printf_ln(s, color, | ||||||
|  | 				_("  (use \"git commit --amend\" to amend the current commit)")); | ||||||
|  | 			status_printf_ln(s, color, | ||||||
|  | 				_("  (use \"git rebase --continue\" once you are satisfied with your changes)")); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	wt_status_print_trailer(s); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void show_cherry_pick_in_progress(struct wt_status *s, | ||||||
|  | 					struct wt_status_state *state, | ||||||
|  | 					const char *color) | ||||||
|  | { | ||||||
|  | 	status_printf_ln(s, color, _("You are currently cherry-picking.")); | ||||||
|  | 	if (advice_status_hints) { | ||||||
|  | 		if (has_unmerged(s)) | ||||||
|  | 			status_printf_ln(s, color, | ||||||
|  | 				_("  (fix conflicts and run \"git commit\")")); | ||||||
|  | 		else | ||||||
|  | 			status_printf_ln(s, color, | ||||||
|  | 				_("  (all conflicts fixed: run \"git commit\")")); | ||||||
|  | 	} | ||||||
|  | 	wt_status_print_trailer(s); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void show_bisect_in_progress(struct wt_status *s, | ||||||
|  | 				struct wt_status_state *state, | ||||||
|  | 				const char *color) | ||||||
|  | { | ||||||
|  | 	status_printf_ln(s, color, _("You are currently bisecting.")); | ||||||
|  | 	if (advice_status_hints) | ||||||
|  | 		status_printf_ln(s, color, | ||||||
|  | 			_("  (use \"git bisect reset\" to get back to the original branch)")); | ||||||
|  | 	wt_status_print_trailer(s); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void wt_status_print_state(struct wt_status *s) | ||||||
|  | { | ||||||
|  | 	const char *state_color = color(WT_STATUS_IN_PROGRESS, s); | ||||||
|  | 	struct wt_status_state state; | ||||||
|  | 	struct stat st; | ||||||
|  |  | ||||||
|  | 	memset(&state, 0, sizeof(state)); | ||||||
|  |  | ||||||
|  | 	if (!stat(git_path("MERGE_HEAD"), &st)) { | ||||||
|  | 		state.merge_in_progress = 1; | ||||||
|  | 	} else if (!stat(git_path("rebase-apply"), &st)) { | ||||||
|  | 		if (!stat(git_path("rebase-apply/applying"), &st)) { | ||||||
|  | 			state.am_in_progress = 1; | ||||||
|  | 			if (!stat(git_path("rebase-apply/patch"), &st) && !st.st_size) | ||||||
|  | 				state.am_empty_patch = 1; | ||||||
|  | 		} else { | ||||||
|  | 			state.rebase_in_progress = 1; | ||||||
|  | 		} | ||||||
|  | 	} else if (!stat(git_path("rebase-merge"), &st)) { | ||||||
|  | 		if (!stat(git_path("rebase-merge/interactive"), &st)) | ||||||
|  | 			state.rebase_interactive_in_progress = 1; | ||||||
|  | 		else | ||||||
|  | 			state.rebase_in_progress = 1; | ||||||
|  | 	} else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) { | ||||||
|  | 		state.cherry_pick_in_progress = 1; | ||||||
|  | 	} | ||||||
|  | 	if (!stat(git_path("BISECT_LOG"), &st)) | ||||||
|  | 		state.bisect_in_progress = 1; | ||||||
|  |  | ||||||
|  | 	if (state.merge_in_progress) | ||||||
|  | 		show_merge_in_progress(s, &state, state_color); | ||||||
|  | 	else if (state.am_in_progress) | ||||||
|  | 		show_am_in_progress(s, &state, state_color); | ||||||
|  | 	else if (state.rebase_in_progress || state.rebase_interactive_in_progress) | ||||||
|  | 		show_rebase_in_progress(s, &state, state_color); | ||||||
|  | 	else if (state.cherry_pick_in_progress) | ||||||
|  | 		show_cherry_pick_in_progress(s, &state, state_color); | ||||||
|  | 	if (state.bisect_in_progress) | ||||||
|  | 		show_bisect_in_progress(s, &state, state_color); | ||||||
|  | } | ||||||
|  |  | ||||||
| void wt_status_print(struct wt_status *s) | void wt_status_print(struct wt_status *s) | ||||||
| { | { | ||||||
| 	const char *branch_color = color(WT_STATUS_ONBRANCH, s); | 	const char *branch_color = color(WT_STATUS_ONBRANCH, s); | ||||||
|  | @ -750,6 +992,7 @@ void wt_status_print(struct wt_status *s) | ||||||
| 			wt_status_print_tracking(s); | 			wt_status_print_tracking(s); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	wt_status_print_state(s); | ||||||
| 	if (s->is_initial) { | 	if (s->is_initial) { | ||||||
| 		status_printf_ln(s, color(WT_STATUS_HEADER, s), ""); | 		status_printf_ln(s, color(WT_STATUS_HEADER, s), ""); | ||||||
| 		status_printf_ln(s, color(WT_STATUS_HEADER, s), _("Initial commit")); | 		status_printf_ln(s, color(WT_STATUS_HEADER, s), _("Initial commit")); | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								wt-status.h
								
								
								
								
							
							
						
						
									
										11
									
								
								wt-status.h
								
								
								
								
							|  | @ -15,6 +15,7 @@ enum color_wt_status { | ||||||
| 	WT_STATUS_LOCAL_BRANCH, | 	WT_STATUS_LOCAL_BRANCH, | ||||||
| 	WT_STATUS_REMOTE_BRANCH, | 	WT_STATUS_REMOTE_BRANCH, | ||||||
| 	WT_STATUS_ONBRANCH, | 	WT_STATUS_ONBRANCH, | ||||||
|  | 	WT_STATUS_IN_PROGRESS, | ||||||
| 	WT_STATUS_MAXSLOT | 	WT_STATUS_MAXSLOT | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -71,6 +72,16 @@ struct wt_status { | ||||||
| 	struct string_list ignored; | 	struct string_list ignored; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct wt_status_state { | ||||||
|  | 	int merge_in_progress; | ||||||
|  | 	int am_in_progress; | ||||||
|  | 	int am_empty_patch; | ||||||
|  | 	int rebase_in_progress; | ||||||
|  | 	int rebase_interactive_in_progress; | ||||||
|  | 	int cherry_pick_in_progress; | ||||||
|  | 	int bisect_in_progress; | ||||||
|  | }; | ||||||
|  |  | ||||||
| void wt_status_prepare(struct wt_status *s); | void wt_status_prepare(struct wt_status *s); | ||||||
| void wt_status_print(struct wt_status *s); | void wt_status_print(struct wt_status *s); | ||||||
| void wt_status_collect(struct wt_status *s); | void wt_status_collect(struct wt_status *s); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano